mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-11-06 03:53:33 -05:00
On a kernel without the Linux 6.13 *xattrat syscalls, xacl_*_at() returned ENOSYS so acls.c fell back to the unconfined path-based sys_acl_set_file() -- the long-standing parent-symlink race for --acls on every pre-6.13 Linux (the receiver applies a received ACL to a leaf an attacker raced to a symlink -> arbitrary-ACL LPE; acl-symlink-race only documented it as a residual there). Add a /proc/self/fd compat to the dirfd dispatchers: when the *xattrat syscall is absent (runtime ENOSYS or unbuilt), address the leaf as /proc/self/fd/<dirfd>/<leaf> and use the l*xattr (no-follow-leaf) calls. The /proc/self/fd/<dirfd> magic symlink resolves to the pinned parent inode (a raced parent symlink can't redirect it) and l*xattr does not follow a raced leaf symlink, so the dirfd+leaf ACL ops are race-safe on every Linux kernel with procfs -- no libacl dependency and no 6.13 requirement. xacl_at_available() now returns true when the syscalls OR the /proc compat are usable, so acls.c takes the race-safe dirfd path instead of the path-based fallback (now only the BSDs / a /proc-less namespace). The held-fd path (fsetxattr) is unchanged. Verified on ubuntu-2004 (kernel 5.4, HAVE_XATTRAT_SYSCALLS=0): "ACL_at": true and acl-symlink-race PASSES while asserting (a vacuous pass before); no regression on a 6.13+ host (native syscalls unchanged) or t_acl.