mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-24 23:05:52 -04:00
sender: fix read-path TOCTOU by opening from module root (CVE-2026-29518)
The sender's file open was vulnerable to the same TOCTOU symlink race as the receiver-side basis-file open. change_pathname() calls chdir() into subdirectories, which follows symlinks; an attacker could race to swap a directory for a symlink between the chdir and the file open, allowing reads of privileged files through the daemon. Reconstruct the full relative path (F_PATHNAME + fname) and open via secure_relative_open() from the trusted module_dir, which walks each path component without following symlinks. This is independent of CWD, so the chdir race is neutralised. CVE-2026-29518. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
22
sender.c
22
sender.c
@@ -48,6 +48,8 @@ extern int make_backups;
|
||||
extern int inplace;
|
||||
extern int inplace_partial;
|
||||
extern int batch_fd;
|
||||
extern int use_secure_symlinks;
|
||||
extern char *module_dir;
|
||||
extern int write_batch;
|
||||
extern int file_old_total;
|
||||
extern BOOL want_progress_now;
|
||||
@@ -352,7 +354,25 @@ void send_files(int f_in, int f_out)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
fd = do_open_checklinks(fname);
|
||||
if (use_secure_symlinks) {
|
||||
/* Open from module root to prevent TOCTOU race where
|
||||
* change_pathname's chdir follows a directory symlink.
|
||||
* Reconstruct the full path relative to module_dir
|
||||
* from F_PATHNAME (path) and f_name (fname). */
|
||||
char secure_path[MAXPATHLEN];
|
||||
int slen = snprintf(secure_path, sizeof secure_path, "%s%s%s", path, slash, fname);
|
||||
if (slen >= (int)sizeof secure_path) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR_XFER, "path too long: %s%s%s\n", path, slash, fname);
|
||||
free_sums(s);
|
||||
if (protocol_version >= 30)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
fd = secure_relative_open(module_dir, secure_path, O_RDONLY, 0);
|
||||
} else {
|
||||
fd = do_open_checklinks(fname);
|
||||
}
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING;
|
||||
|
||||
Reference in New Issue
Block a user