summaryrefslogtreecommitdiffstats
path: root/debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12747/0001-fixed-symlink-race-condition-in-sender.patch
blob: 0c2e92bccfeb045e28e35bc1734fa2b4232a565b (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
From f45f48055e548851bc7230f454dfeba139be6c04 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Wed, 18 Dec 2024 08:59:42 +1100
Subject: [PATCH] fixed symlink race condition in sender

when we open a file that we don't expect to be a symlink use
O_NOFOLLOW to prevent a race condition where an attacker could change
a file between being a normal file and a symlink

Backported-By: Samuel Henrique <samueloph@debian.org>
* Refresh patch to remove offset.

---
 checksum.c  |  2 +-
 flist.c     |  2 +-
 generator.c |  4 ++--
 receiver.c  |  2 +-
 sender.c    |  2 +-
 syscall.c   | 20 ++++++++++++++++++++
 t_unsafe.c  |  3 +++
 tls.c       |  3 +++
 trimslash.c |  2 ++
 util1.c     |  2 +-
 10 files changed, 35 insertions(+), 7 deletions(-)

Index: rsync/checksum.c
===================================================================
--- rsync.orig/checksum.c
+++ rsync/checksum.c
@@ -406,7 +406,7 @@ void file_checksum(const char *fname, co
 	int32 remainder;
 	int fd;
 
-	fd = do_open(fname, O_RDONLY, 0);
+	fd = do_open_checklinks(fname);
 	if (fd == -1) {
 		memset(sum, 0, file_sum_len);
 		return;
Index: rsync/flist.c
===================================================================
--- rsync.orig/flist.c
+++ rsync/flist.c
@@ -1390,7 +1390,7 @@ struct file_struct *make_file(const char
 
 	if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
 		if (st.st_size == 0) {
-			int fd = do_open(fname, O_RDONLY, 0);
+			int fd = do_open_checklinks(fname);
 			if (fd >= 0) {
 				st.st_size = get_device_size(fd, fname);
 				close(fd);
Index: rsync/generator.c
===================================================================
--- rsync.orig/generator.c
+++ rsync/generator.c
@@ -1798,7 +1798,7 @@ static void recv_generator(char *fname,
 
 	if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
 		/* This early open into fd skips the regular open below. */
-		if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0)
+		if ((fd = do_open_nofollow(fnamecmp, O_RDONLY)) >= 0)
 			real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp);
 	}
 
@@ -1867,7 +1867,7 @@ static void recv_generator(char *fname,
 	}
 
 	/* open the file */
-	if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+	if (fd < 0 && (fd = do_open_checklinks(fnamecmp)) < 0) {
 		rsyserr(FERROR, errno, "failed to open %s, continuing",
 			full_fname(fnamecmp));
 	  pretend_missing:
Index: rsync/receiver.c
===================================================================
--- rsync.orig/receiver.c
+++ rsync/receiver.c
@@ -775,7 +775,7 @@ int recv_files(int f_in, int f_out, char
 			if (fnamecmp != fname) {
 				fnamecmp = fname;
 				fnamecmp_type = FNAMECMP_FNAME;
-				fd1 = do_open(fnamecmp, O_RDONLY, 0);
+				fd1 = do_open_nofollow(fnamecmp, O_RDONLY);
 			}
 
 			if (fd1 == -1 && basis_dir[0]) {
Index: rsync/sender.c
===================================================================
--- rsync.orig/sender.c
+++ rsync/sender.c
@@ -350,7 +350,7 @@ void send_files(int f_in, int f_out)
 			exit_cleanup(RERR_PROTOCOL);
 		}
 
-		fd = do_open(fname, O_RDONLY, 0);
+		fd = do_open_checklinks(fname);
 		if (fd == -1) {
 			if (errno == ENOENT) {
 				enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING;
Index: rsync/syscall.c
===================================================================
--- rsync.orig/syscall.c
+++ rsync/syscall.c
@@ -45,6 +45,8 @@ extern int preallocate_files;
 extern int preserve_perms;
 extern int preserve_executability;
 extern int open_noatime;
+extern int copy_links;
+extern int copy_unsafe_links;
 
 #ifndef S_BLKSIZE
 # if defined hpux || defined __hpux__ || defined __hpux
@@ -793,3 +795,21 @@ cleanup:
 	return retfd;
 #endif // O_NOFOLLOW, O_DIRECTORY
 }
+
+/*
+  varient of do_open/do_open_nofollow which does do_open() if the
+  copy_links or copy_unsafe_links options are set and does
+  do_open_nofollow() otherwise
+
+  This is used to prevent a race condition where an attacker could be
+  switching a file between being a symlink and being a normal file
+
+  The open is always done with O_RDONLY flags
+ */
+int do_open_checklinks(const char *pathname)
+{
+	if (copy_links || copy_unsafe_links) {
+		return do_open(pathname, O_RDONLY, 0);
+	}
+	return do_open_nofollow(pathname, O_RDONLY);
+}
Index: rsync/t_unsafe.c
===================================================================
--- rsync.orig/t_unsafe.c
+++ rsync/t_unsafe.c
@@ -28,6 +28,9 @@ int am_root = 0;
 int am_sender = 1;
 int read_only = 0;
 int list_only = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
+
 short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
 
 int
Index: rsync/tls.c
===================================================================
--- rsync.orig/tls.c
+++ rsync/tls.c
@@ -49,6 +49,9 @@ int list_only = 0;
 int link_times = 0;
 int link_owner = 0;
 int nsec_times = 0;
+int safe_symlinks = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
 
 #ifdef SUPPORT_XATTRS
 
Index: rsync/trimslash.c
===================================================================
--- rsync.orig/trimslash.c
+++ rsync/trimslash.c
@@ -26,6 +26,8 @@ int am_root = 0;
 int am_sender = 1;
 int read_only = 1;
 int list_only = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
 
 int
 main(int argc, char **argv)
Index: rsync/util1.c
===================================================================
--- rsync.orig/util1.c
+++ rsync/util1.c
@@ -365,7 +365,7 @@ int copy_file(const char *source, const
 	int len;   /* Number of bytes read into `buf'. */
 	OFF_T prealloc_len = 0, offset = 0;
 
-	if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
+	if ((ifd = do_open_nofollow(source, O_RDONLY)) < 0) {
 		int save_errno = errno;
 		rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
 		errno = save_errno;