summaryrefslogtreecommitdiffstats
path: root/debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0003-receiver-use-secure_relative_open-for-basis-file.patch
blob: 4be6391648dfd2769c05adbe94168b847bbc53bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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