Skip to content

chmod -R: raw fchmodat2 syscall bypasses libc, breaking LD_PRELOAD tools #14028

Description

@nadzyah

chmod -R changes entries below its command-line argument with a raw syscall(SYS_fchmodat2, ...) instead of a libc call, so LD_PRELOAD tools (fakeroot, fakechroot, pseudo) never see it. The mode changes on disk, but their bookkeeping does not, so later stat() calls report the old mode. Exit status is 0 and stderr is empty, so the loss is silent

This can be reproduced by running the following commands using uutils 0.10.0, fakeroot 1.37.1.2, Linux 6.16:

mkdir -p d/sub
fakeroot sh -c 'chown -R daemon:daemon d && chmod -R u+s d && find d -printf "%M %p\n" | sort'

GNU coreutils:

drwsrwxr-x d
drwsrwxr-x d/sub

uutils:

drwsrwxr-x d
drwxrwxr-x d/sub     # setuid bit lost

The cause, as I have found, is that DirFd::chmod_at in src/uucore/src/lib/features/safe_traversal.rs calls libc::syscall(452, ...) directly. The command-line argument itself is unaffected because it goes through fs::set_permissions -> chmod()

The raw syscall is #[cfg]-gated to asm-generic arches (x86_64, x86, arm, aarch64, riscv), so it does not reproduce on e.g. ppc64el or s390x, which take the fchmodat fallback. Introduced by #11918

Same class as #13399, different call site (that one is rustix in id, this one is a hand-written libc::syscall in uucore)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions