]> git.ipfire.org Git - thirdparty/rsync.git/commit
util1+syscall: secure copy_file source/dest opens; bare-path defence-in-depth
authorAndrew Tridgell <andrew@tridgell.net>
Tue, 5 May 2026 23:45:30 +0000 (09:45 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Wed, 20 May 2026 00:01:22 +0000 (10:01 +1000)
commit3cc6a9e8cdcffb637ecdd41dae47833096dca317
treeccbeb4545c45fc592750080b4224e292ed438551
parent30656c5e358b1c6033f4caf24f3e11b29d25c9f4
util1+syscall: secure copy_file source/dest opens; bare-path defence-in-depth

Three related codex audit findings:

  Finding 3a: copy_file()'s source open in util1.c used
  do_open_nofollow(), which only rejects a final-component
  symlink. A parent-component symlink (e.g. --copy-dest=cd where
  cd -> /outside) follows freely and reads outside the module.
  Route through secure_relative_open() with O_NOFOLLOW.

  Finding 3b: generator.c's in-place backup-file create still
  used a bare do_open with O_CREAT, leaving a tiny but reachable
  parent-symlink window between the secure unlink (already
  through do_unlink_at) and the create. Add do_open_at() that
  goes through a secure parent dirfd, and route the call site
  through it.

  Finding 3c: copy_file()'s destination open in
  unlink_and_reopen() had the same bare-do_open pattern; route
  through do_open_at as well.

Adds testsuite/copy-dest-source-symlink.test and
testsuite/bare-do-open-symlink-race.test as regression coverage
for both attack shapes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
generator.c
syscall.c
testsuite/bare-do-open-symlink-race.test [new file with mode: 0755]
testsuite/copy-dest-source-symlink.test [new file with mode: 0755]
util1.c