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
This commit is contained in:
Andrew Tridgell
2024-11-23 12:28:13 +11:00
parent b4a27ca25d
commit c35e28331f

View File

@@ -552,6 +552,8 @@ int recv_files(int f_in, int f_out, char *local_name)
progress_init(); progress_init();
while (1) { while (1) {
const char *basedir = NULL;
cleanup_disable(); cleanup_disable();
/* This call also sets cur_flist. */ /* This call also sets cur_flist. */
@@ -722,27 +724,29 @@ int recv_files(int f_in, int f_out, char *local_name)
exit_cleanup(RERR_PROTOCOL); exit_cleanup(RERR_PROTOCOL);
} }
if (file->dirname) { if (file->dirname) {
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname); basedir = file->dirname;
fnamecmp = fnamecmpbuf; }
} else fnamecmp = xname;
fnamecmp = xname;
break; break;
default: default:
if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) { if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) {
fnamecmp_type -= FNAMECMP_FUZZY + 1; fnamecmp_type -= FNAMECMP_FUZZY + 1;
if (file->dirname) { if (file->dirname) {
stringjoin(fnamecmpbuf, sizeof fnamecmpbuf, pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], file->dirname);
basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL); basedir = fnamecmpbuf;
} else } else {
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname); basedir = basis_dir[fnamecmp_type];
}
fnamecmp = xname;
} else if (fnamecmp_type >= basis_dir_cnt) { } else if (fnamecmp_type >= basis_dir_cnt) {
rprintf(FERROR, rprintf(FERROR,
"invalid basis_dir index: %d.\n", "invalid basis_dir index: %d.\n",
fnamecmp_type); fnamecmp_type);
exit_cleanup(RERR_PROTOCOL); exit_cleanup(RERR_PROTOCOL);
} else } else {
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname); basedir = basis_dir[fnamecmp_type];
fnamecmp = fnamecmpbuf; fnamecmp = fname;
}
break; break;
} }
if (!fnamecmp || (daemon_filter_list.head if (!fnamecmp || (daemon_filter_list.head
@@ -765,7 +769,7 @@ int recv_files(int f_in, int f_out, char *local_name)
} }
/* open the file */ /* 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 (fd1 == -1 && protocol_version < 29) {
if (fnamecmp != fname) { if (fnamecmp != fname) {
@@ -776,14 +780,20 @@ int recv_files(int f_in, int f_out, char *local_name)
if (fd1 == -1 && basis_dir[0]) { if (fd1 == -1 && basis_dir[0]) {
/* pre-29 allowed only one alternate basis */ /* pre-29 allowed only one alternate basis */
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basedir = basis_dir[0];
basis_dir[0], fname); fnamecmp = fname;
fnamecmp = fnamecmpbuf;
fnamecmp_type = FNAMECMP_BASIS_DIR_LOW; fnamecmp_type = FNAMECMP_BASIS_DIR_LOW;
fd1 = do_open(fnamecmp, O_RDONLY, 0); 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;
}
one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR; one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR;
updating_basis_or_equiv = one_inplace updating_basis_or_equiv = one_inplace
|| (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP)); || (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP));