summaryrefslogtreecommitdiff
path: root/backport-CVE-2024-12084-part1.patch
blob: e5ba8ddc6f79a52b5f179959a1e6399c5db67cfe (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
From 0902b52f6687b1f7952422080d50b93108742e53 Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Tue, 29 Oct 2024 22:55:29 -0700
Subject: [PATCH 1/2] Some checksum buffer fixes.

- Put sum2_array into sum_struct to hold an array of sum2 checksums
  that are each xfer_sum_len bytes.
- Remove sum2 buf from sum_buf.
- Add macro sum2_at() to access each sum2 array element.
- Throw an error if a sums header has an s2length larger than
  xfer_sum_len.
---
 io.c     | 3 ++-
 match.c  | 8 ++++----
 rsync.c  | 5 ++++-
 rsync.h  | 4 +++-
 sender.c | 4 +++-
 5 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/io.c b/io.c
index a99ac0ec..bb60eeca 100644
--- a/io.c
+++ b/io.c
@@ -55,6 +55,7 @@ extern int read_batch;
 extern int compat_flags;
 extern int protect_args;
 extern int checksum_seed;
+extern int xfer_sum_len;
 extern int daemon_connection;
 extern int protocol_version;
 extern int remove_source_files;
@@ -1977,7 +1978,7 @@ void read_sum_head(int f, struct sum_struct *sum)
 		exit_cleanup(RERR_PROTOCOL);
 	}
 	sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f);
-	if (sum->s2length < 0 || sum->s2length > MAX_DIGEST_LEN) {
+	if (sum->s2length < 0 || sum->s2length > xfer_sum_len) {
 		rprintf(FERROR, "Invalid checksum length %d [%s]\n",
 			sum->s2length, who_am_i());
 		exit_cleanup(RERR_PROTOCOL);
diff --git a/match.c b/match.c
index cdb30a15..36e78ed2 100644
--- a/match.c
+++ b/match.c
@@ -232,7 +232,7 @@ static void hash_search(int f,struct sum_struct *s,
 				done_csum2 = 1;
 			}
 
-			if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
+			if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0) {
 				false_alarms++;
 				continue;
 			}
@@ -252,7 +252,7 @@ static void hash_search(int f,struct sum_struct *s,
 					if (i != aligned_i) {
 						if (sum != s->sums[aligned_i].sum1
 						 || l != s->sums[aligned_i].len
-						 || memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
+						 || memcmp(sum2, sum2_at(s, aligned_i), s->s2length) != 0)
 							goto check_want_i;
 						i = aligned_i;
 					}
@@ -271,7 +271,7 @@ static void hash_search(int f,struct sum_struct *s,
 						if (sum != s->sums[i].sum1)
 							goto check_want_i;
 						get_checksum2((char *)map, l, sum2);
-						if (memcmp(sum2, s->sums[i].sum2, s->s2length) != 0)
+						if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0)
 							goto check_want_i;
 						/* OK, we have a re-alignment match.  Bump the offset
 						 * forward to the new match point. */
@@ -290,7 +290,7 @@ static void hash_search(int f,struct sum_struct *s,
 			 && (!updating_basis_file || s->sums[want_i].offset >= offset
 			  || s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
 			 && sum == s->sums[want_i].sum1
-			 && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
+			 && memcmp(sum2, sum2_at(s, want_i), s->s2length) == 0) {
 				/* we've found an adjacent match - the RLL coder
 				 * will be happy */
 				i = want_i;
diff --git a/rsync.c b/rsync.c
index cd288f57..b130aba5 100644
--- a/rsync.c
+++ b/rsync.c
@@ -437,7 +437,10 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, cha
   */
 void free_sums(struct sum_struct *s)
 {
-	if (s->sums) free(s->sums);
+	if (s->sums) {
+		free(s->sums);
+		free(s->sum2_array);
+	}
 	free(s);
 }
 
diff --git a/rsync.h b/rsync.h
index d3709fe0..8ddbe702 100644
--- a/rsync.h
+++ b/rsync.h
@@ -958,12 +958,12 @@ struct sum_buf {
 	uint32 sum1;	        /**< simple checksum */
 	int32 chain;		/**< next hash-table collision */
 	short flags;		/**< flag bits */
-	char sum2[SUM_LENGTH];	/**< checksum  */
 };
 
 struct sum_struct {
 	OFF_T flength;		/**< total file length */
 	struct sum_buf *sums;	/**< points to info for each chunk */
+	char *sum2_array;	/**< checksums of length xfer_sum_len */
 	int32 count;		/**< how many chunks */
 	int32 blength;		/**< block_length */
 	int32 remainder;	/**< flength % block_length */
@@ -982,6 +982,8 @@ struct map_struct {
 	int status;		/* first errno from read errors		*/
 };
 
+#define sum2_at(s, i)	((s)->sum2_array + ((OFF_T)(i) * xfer_sum_len))
+
 #define NAME_IS_FILE		(0)    /* filter name as a file */
 #define NAME_IS_DIR		(1<<0) /* filter name as a dir */
 #define NAME_IS_XATTR		(1<<2) /* filter name as an xattr */
diff --git a/sender.c b/sender.c
index 3d4f052e..ab205341 100644
--- a/sender.c
+++ b/sender.c
@@ -31,6 +31,7 @@ extern int log_before_transfer;
 extern int stdout_format_has_i;
 extern int logfile_format_has_i;
 extern int want_xattr_optim;
+extern int xfer_sum_len;
 extern int csum_length;
 extern int append_mode;
 extern int copy_links;
@@ -94,10 +95,11 @@ static struct sum_struct *receive_sums(int f)
 		return(s);
 
 	s->sums = new_array(struct sum_buf, s->count);
+	s->sum2_array = new_array(char, s->count * xfer_sum_len);
 
 	for (i = 0; i < s->count; i++) {
 		s->sums[i].sum1 = read_int(f);
-		read_buf(f, s->sums[i].sum2, s->s2length);
+		read_buf(f, sum2_at(s, i), s->s2length);
 
 		s->sums[i].offset = offset;
 		s->sums[i].flags = 0;
-- 
2.34.1