fix(receiver): confine --temp-dir scratch dir and gate setuid bits
Three receiver security fixes from the audit: 1. --temp-dir symlink escape (High): file_open_temp_dir() opened the client-controlled scratch dir with a bare open(), so a symlink planted under the receive root let a peer redirect receiver scratch files outside the authorized root. The opened dir is now judged by the REAL path of its fd (via /proc/self/fd), and any target outside the authorized receive root is refused with a logged error (EACCES). An in-root symlink (the EXDEV cross-filesystem fallback case) still works, and the no-root local batch path is unchanged. 2. setuid/setgid/sticky under SUPER_MODE_OFF (High): the special bits were applied under --perms (and via --chmod) even when the connection forbade super-user activities. FileAttrPolicy gains super_permitted, set by file_attr_policy_from_config() from privilege_super_mode_permitted(); metadata_mode_for_policy(), the symlink path, the special-node creation path, and the deferred directory-mode apply now strip the special bits when it is false. Exact rsync semantics are preserved when permitted. 3. daemon umask (Low): daemonize() forced umask(0), so implied parent directories created without -p were world-writable 0777. Set the conventional daemon umask 022 instead (rsync never forces 0); -p/-a mode preservation is unaffected because it restores modes via fchmod. Tests: new unit tests for file_open_temp_dir confinement and the masked/unmasked special-bit policy (incl. the --chmod path), a daemon world-writable-dir regression test, an integration escape test, and a root-only integration test asserting special bits are masked without --allow-super. The old cross-filesystem test encoded the vulnerable behavior (symlink target outside the root) and is replaced by the escape test; the EXDEV fallback code is retained for in-root links.
This commit is contained in:
+10
-4
@@ -1178,13 +1178,19 @@ static bool daemonize(void) {
|
||||
close(devnull);
|
||||
}
|
||||
/* Do not pin the launch CWD (module-relative 'path' entries would resolve
|
||||
* against an unstable working directory) and drop the restrictive host umask
|
||||
* so modules can create files/dirs with the modes the config requests. */
|
||||
* against an unstable working directory). Set a conservative daemon umask
|
||||
* of 022 (the conventional service default): rsync never forces umask 0 --
|
||||
* it reads and restores the inherited umask and creates new entries as
|
||||
* 0777 & ~umask / source & ~umask without -p. Forcing 0 here made every
|
||||
* implied parent directory world-writable (0777) whenever -p metadata was not
|
||||
* applied. 022 gives 0755 directories and source&~022 files, matching rsync
|
||||
* under a normal daemon umask; -p/-a still restore the exact source mode via
|
||||
* fchmod, which is unaffected by the umask. */
|
||||
if (chdir("/") != 0)
|
||||
log_message(LOG_LEVEL_WARNING, "daemon: chdir to / failed: %s", strerror(errno));
|
||||
umask(0);
|
||||
umask(022);
|
||||
/* Refresh the cached umask: main() captured the launch umask before this
|
||||
* (single-threaded) umask(0), and file_mode_base() must see the daemon's
|
||||
* (single-threaded) umask(022), and file_mode_base() must see the daemon's
|
||||
* actual umask. */
|
||||
file_umask_capture();
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user