From 0e0803f859682e71dc2756ef503efd6f522baa4c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 12 Jun 2026 18:46:44 +1000 Subject: [PATCH] rrsync: deny copy-unsafe-links in restricted dirs; flock fallback Deny --copy-unsafe-links inside a restricted (non-"/") rrsync directory (it dereferences a symlink pointing outside the tree and copies the referent out -- exfiltration), and don't abort the run when flock() is unavailable. Test: rrsync-copy-unsafe-links-denied. (cherry picked from commit beaae13ff25d5a8f4435010e0531116fb1d00742) --- support/rrsync | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/support/rrsync b/support/rrsync index 94c85f59..f6c4edf1 100755 --- a/support/rrsync +++ b/support/rrsync @@ -182,6 +182,7 @@ def main(): if args.dir != '/': global short_disabled short_disabled += short_disabled_subdir + long_opts['copy-unsafe-links'] = -1 short_no_arg_re = short_no_arg short_with_num_re = short_with_num @@ -333,13 +334,20 @@ def validated_arg(opt, arg, typ=3, wild=False): def lock_or_die(dirname): - import fcntl + import fcntl, errno global lock_handle lock_handle = os.open(dirname, os.O_RDONLY) try: fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB) - except: - die('Another instance of rrsync is already accessing this directory.') + except OSError as e: + if e.errno in (errno.EWOULDBLOCK, errno.EAGAIN, errno.EACCES): + die('Another instance of rrsync is already accessing this directory.') + # flock() is unavailable on this fd/platform -- e.g. Solaris returns + # EBADF for flock() on a directory fd. The single-run lock is a + # best-effort convenience (cf. -no-lock), not a security control, so + # proceed without it rather than abort every transfer. + os.close(lock_handle) + lock_handle = None def die(*msg):