summaryrefslogtreecommitdiff
path: root/backport-CVE-2024-12086-part3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'backport-CVE-2024-12086-part3.patch')
-rw-r--r--backport-CVE-2024-12086-part3.patch103
1 files changed, 103 insertions, 0 deletions
diff --git a/backport-CVE-2024-12086-part3.patch b/backport-CVE-2024-12086-part3.patch
new file mode 100644
index 0000000..4be6391
--- /dev/null
+++ b/backport-CVE-2024-12086-part3.patch
@@ -0,0 +1,103 @@
+From e59ef9939d3f0ccc8f9bab51442989a81be0c914 Mon Sep 17 00:00:00 2001
+From: Andrew Tridgell <andrew@tridgell.net>
+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(-)
+
+diff --git a/receiver.c b/receiver.c
+index 2d7f6033..8031b8f4 100644
+--- a/receiver.c
++++ b/receiver.c
+@@ -552,6 +552,8 @@ int recv_files(int f_in, int f_out, char *local_name)
+ progress_init();
+
+ while (1) {
++ const char *basedir = NULL;
++
+ cleanup_disable();
+
+ /* 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);
+ }
+ 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
+@@ -765,7 +769,7 @@ int recv_files(int f_in, int f_out, char *local_name)
+ }
+
+ /* 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) {
+@@ -776,14 +780,20 @@ int recv_files(int f_in, int f_out, char *local_name)
+
+ if (fd1 == -1 && basis_dir[0]) {
+ /* pre-29 allowed only one alternate basis */
+- pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
+- basis_dir[0], fname);
+- fnamecmp = fnamecmpbuf;
++ basedir = basis_dir[0];
++ fnamecmp = fname;
+ 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;
+ updating_basis_or_equiv = one_inplace
+ || (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP));
+--
+2.34.1
+