From e59ef9939d3f0ccc8f9bab51442989a81be0c914 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 23 Nov 2024 12:28:13 +1100 Subject: [PATCH 3/4] receiver: use secure_relative_open() for basis file this prevents attacks where the basis file is manipulated by a malicious sender to gain information about files outside the destination tree --- receiver.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) Index: rsync-3.1.3/receiver.c =================================================================== --- rsync-3.1.3.orig/receiver.c +++ rsync-3.1.3/receiver.c @@ -537,6 +537,8 @@ int recv_files(int f_in, int f_out, char delayed_bits = bitbag_create(cur_flist->used + 1); while (1) { + const char *basedir = NULL; + cleanup_disable(); /* This call also sets cur_flist. */ @@ -706,27 +708,29 @@ int recv_files(int f_in, int f_out, char exit_cleanup(RERR_PROTOCOL); } if (file->dirname) { - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname); - fnamecmp = fnamecmpbuf; - } else - fnamecmp = xname; + basedir = file->dirname; + } + fnamecmp = xname; break; default: if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) { fnamecmp_type -= FNAMECMP_FUZZY + 1; if (file->dirname) { - stringjoin(fnamecmpbuf, sizeof fnamecmpbuf, - basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL); - } else - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname); + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], file->dirname); + basedir = fnamecmpbuf; + } else { + basedir = basis_dir[fnamecmp_type]; + } + fnamecmp = xname; } else if (fnamecmp_type >= basis_dir_cnt) { rprintf(FERROR, "invalid basis_dir index: %d.\n", fnamecmp_type); exit_cleanup(RERR_PROTOCOL); - } else - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname); - fnamecmp = fnamecmpbuf; + } else { + basedir = basis_dir[fnamecmp_type]; + fnamecmp = fname; + } break; } if (!fnamecmp || (daemon_filter_list.head @@ -749,7 +753,7 @@ int recv_files(int f_in, int f_out, char } /* open the file */ - fd1 = do_open(fnamecmp, O_RDONLY, 0); + fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0); if (fd1 == -1 && protocol_version < 29) { if (fnamecmp != fname) { @@ -759,13 +763,19 @@ int recv_files(int f_in, int f_out, char if (fd1 == -1 && basis_dir[0]) { /* pre-29 allowed only one alternate basis */ - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, - basis_dir[0], fname); - fnamecmp = fnamecmpbuf; - fd1 = do_open(fnamecmp, O_RDONLY, 0); + basedir = basis_dir[0]; + fnamecmp = fname; + fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0); } } + if (basedir) { + // for the following code we need the full + // path name as a single string + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basedir, fnamecmp); + fnamecmp = fnamecmpbuf; + } + updating_basis_or_equiv = inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);