Skip to content

TOCTOU race condition in grabbag__file_copy_metadata() #893

Description

@luongtrieudai2005

poc_toctou_flac.sh

TOCTOU race condition in grabbag__file_copy_metadata()

Environment

  • flac version: 1.3.3
  • OS: Ubuntu 22.04 (WSL)
  • Tool: strace 5.16

Summary

grabbag__file_copy_metadata() in src/share/grabbag/file.c:116 calls
flac_stat(filename) and flac_chmod(filename) on the same path string.
Between the two calls, a local attacker with write access to the output
directory can atomically replace the file with a symlink pointing to an
arbitrary target. The subsequent chmod() follows the symlink and changes
permissions on that target.

Vulnerable pattern

// src/share/grabbag/file.c
flac_stat(filename, &stats);           // CHECK: read mode by path
flac_chmod(filename, stats.st_mode);   // USE:   apply mode by path

Verification

strace confirms chmod() is called by path, not fchmod() by descriptor:

chmod("/tmp/.../dst.flac", 0100644) = 0   // by path — vulnerable
// fchmod() not observed

Race confirmed with a PoC script (written with AI assistance):

  • symlink swap succeeded on attempt 4 out of 50,000
  • victim file permissions changed from 000 to 644
  • tested on flac 1.3.3, Ubuntu/WSL

Attack scenario

Most relevant when flac is invoked by a service or automated pipeline
with elevated privileges, where the output directory is also writable by
a lower-privileged user (e.g. media processing server, NAS, CI/CD pipeline).

Suggested fix

Replace path-based calls with file-descriptor-based equivalents:

// BEFORE
flac_stat(filename, &stats);
flac_chmod(filename, stats.st_mode);

// AFTER
int fd = open(filename, O_RDONLY);
if (fd >= 0) {
    fstat(fd, &stats);
    fchmod(fd, stats.st_mode);
    close(fd);
}

Note

PoC script available on request.

Reported by: Luong Trieu Dai

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions