mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-06-09 14:45:55 -04:00
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:
42
receiver.c
42
receiver.c
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user