bsdiff: Add patches for CVEs
[openwrt/staging/pepe2k.git] / package / utils / bsdiff / patches / 033-CVE-2020-14315.patch
1 Description: patch for CVE-2020-14315
2 A memory corruption vulnerability is present in bspatch as shipped in
3 Colin Percival’s bsdiff tools version 4.3. Insufficient checks when
4 handling external inputs allows an attacker to bypass the sanity checks
5 in place and write out of a dynamically allocated buffer boundaries.
6 Source: https://svnweb.freebsd.org/base/head/usr.bin/bsdiff/bspatch/bspatch.c?revision=352742&view=co
7 Author: tony mancill <tmancill@debian.org>
8 Comment: The patch was created by comparing the Debian sources to the
9 "Confirmed Patched Version" [1] documented in the
10 X41 D-SEC GmbH Security Advisory: X41-2020-006 [2].
11 References to FreeBSD capsicum have been dropped. Definitions for
12 TYPE_MINIMUM and TYPE_MAXIMUM have been borrowed from the Debian
13 coreutils package sources but originate in gnulib [3] and are used to
14 define OFF_MIN and OFF_MAX (limits of off_t). Whitespace changes from
15 the confirmed patched version are also included and keep the difference
16 between the Debian sources and the confirmed patched version minimal.
17 .
18 [1] https://svnweb.freebsd.org/base/head/usr.bin/bsdiff/bspatch/bspatch.c?revision=352742&view=co
19 [2] https://www.openwall.com/lists/oss-security/2020/07/09/2
20 [3] https://www.gnu.org/software/gnulib/
21 Last-Update: 2021-04-03
22 Forwarded: not-needed
23 Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964796
24
25 --- a/bspatch.c
26 +++ b/bspatch.c
27 @@ -1,4 +1,6 @@
28 /*-
29 + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
30 + *
31 * Copyright 2003-2005 Colin Percival
32 * All rights reserved
33 *
34 @@ -25,55 +27,147 @@
35 */
36
37 #if 0
38 -__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");
39 +__FBSDID("$FreeBSD$");
40 #endif
41
42 #include <bzlib.h>
43 -#include <stdlib.h>
44 +#include <err.h>
45 +#include <fcntl.h>
46 +#include <libgen.h>
47 +#include <limits.h>
48 +#include <stdint.h>
49 #include <stdio.h>
50 +#include <stdlib.h>
51 #include <string.h>
52 -#include <err.h>
53 #include <unistd.h>
54 -#include <fcntl.h>
55 +
56 +#ifndef O_BINARY
57 +#define O_BINARY 0
58 +#endif
59 +#define HEADER_SIZE 32
60 +
61 +/* TYPE_MINIMUM and TYPE_MAXIMUM taken from coreutils */
62 +#ifndef TYPE_MINIMUM
63 +#define TYPE_MINIMUM(t) \
64 + ((t) ((t) 0 < (t) -1 ? (t) 0 : ~ TYPE_MAXIMUM (t)))
65 +#endif
66 +#ifndef TYPE_MAXIMUM
67 +#define TYPE_MAXIMUM(t) \
68 + ((t) ((t) 0 < (t) -1 \
69 + ? (t) -1 \
70 + : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
71 +#endif
72 +
73 +#ifndef OFF_MAX
74 +#define OFF_MAX TYPE_MAXIMUM(off_t)
75 +#endif
76 +
77 +#ifndef OFF_MIN
78 +#define OFF_MIN TYPE_MINIMUM(off_t)
79 +#endif
80 +
81 +static char *newfile;
82 +static int dirfd = -1;
83 +
84 +static void
85 +exit_cleanup(void)
86 +{
87 +
88 + if (dirfd != -1 && newfile != NULL)
89 + if (unlinkat(dirfd, newfile, 0))
90 + warn("unlinkat");
91 +}
92 +
93 +static inline off_t
94 +add_off_t(off_t a, off_t b)
95 +{
96 + off_t result;
97 +
98 +#if __GNUC__ >= 5 || \
99 + (defined(__has_builtin) && __has_builtin(__builtin_add_overflow))
100 + if (__builtin_add_overflow(a, b, &result))
101 + errx(1, "Corrupt patch");
102 +#else
103 + if ((b > 0 && a > OFF_MAX - b) || (b < 0 && a < OFF_MIN - b))
104 + errx(1, "Corrupt patch");
105 + result = a + b;
106 +#endif
107 + return result;
108 +}
109
110 static off_t offtin(unsigned char *buf)
111 {
112 off_t y;
113
114 - y=buf[7]&0x7F;
115 - y=y*256;y+=buf[6];
116 - y=y*256;y+=buf[5];
117 - y=y*256;y+=buf[4];
118 - y=y*256;y+=buf[3];
119 - y=y*256;y+=buf[2];
120 - y=y*256;y+=buf[1];
121 - y=y*256;y+=buf[0];
122 + y = buf[7] & 0x7F;
123 + y = y * 256; y += buf[6];
124 + y = y * 256; y += buf[5];
125 + y = y * 256; y += buf[4];
126 + y = y * 256; y += buf[3];
127 + y = y * 256; y += buf[2];
128 + y = y * 256; y += buf[1];
129 + y = y * 256; y += buf[0];
130
131 - if(buf[7]&0x80) y=-y;
132 + if (buf[7] & 0x80)
133 + y = -y;
134
135 - return y;
136 + return (y);
137 }
138
139 -int main(int argc,char * argv[])
140 +static void
141 +usage(void)
142 {
143 - FILE * f, * cpf, * dpf, * epf;
144 - BZFILE * cpfbz2, * dpfbz2, * epfbz2;
145 +
146 + fprintf(stderr, "usage: bspatch oldfile newfile patchfile\n");
147 + exit(1);
148 +}
149 +
150 +int main(int argc, char *argv[])
151 +{
152 + FILE *f, *cpf, *dpf, *epf;
153 + BZFILE *cpfbz2, *dpfbz2, *epfbz2;
154 + char *directory, *namebuf;
155 int cbz2err, dbz2err, ebz2err;
156 - int fd;
157 - ssize_t oldsize,newsize;
158 - ssize_t bzctrllen,bzdatalen;
159 - unsigned char header[32],buf[8];
160 + int newfd, oldfd;
161 + off_t oldsize, newsize;
162 + off_t bzctrllen, bzdatalen;
163 + unsigned char header[HEADER_SIZE], buf[8];
164 unsigned char *old, *new;
165 - off_t oldpos,newpos;
166 + off_t oldpos, newpos;
167 off_t ctrl[3];
168 - off_t lenread;
169 - off_t i;
170 + off_t i, lenread, offset;
171
172 - if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
173 + if (argc != 4)
174 + usage();
175
176 /* Open patch file */
177 - if ((f = fopen(argv[3], "r")) == NULL)
178 + if ((f = fopen(argv[3], "rb")) == NULL)
179 + err(1, "fopen(%s)", argv[3]);
180 + /* Open patch file for control block */
181 + if ((cpf = fopen(argv[3], "rb")) == NULL)
182 + err(1, "fopen(%s)", argv[3]);
183 + /* open patch file for diff block */
184 + if ((dpf = fopen(argv[3], "rb")) == NULL)
185 err(1, "fopen(%s)", argv[3]);
186 + /* open patch file for extra block */
187 + if ((epf = fopen(argv[3], "rb")) == NULL)
188 + err(1, "fopen(%s)", argv[3]);
189 + /* open oldfile */
190 + if ((oldfd = open(argv[1], O_RDONLY | O_BINARY, 0)) < 0)
191 + err(1, "open(%s)", argv[1]);
192 + /* open directory where we'll write newfile */
193 + if ((namebuf = strdup(argv[2])) == NULL ||
194 + (directory = dirname(namebuf)) == NULL ||
195 + (dirfd = open(directory, O_DIRECTORY)) < 0)
196 + err(1, "open %s", argv[2]);
197 + free(namebuf);
198 + if ((newfile = basename(argv[2])) == NULL)
199 + err(1, "basename");
200 + /* open newfile */
201 + if ((newfd = openat(dirfd, newfile,
202 + O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) < 0)
203 + err(1, "open(%s)", argv[2]);
204 + atexit(exit_cleanup);
205
206 /*
207 File format:
208 @@ -90,104 +184,104 @@ int main(int argc,char * argv[])
209 */
210
211 /* Read header */
212 - if (fread(header, 1, 32, f) < 32) {
213 + if (fread(header, 1, HEADER_SIZE, f) < HEADER_SIZE) {
214 if (feof(f))
215 - errx(1, "Corrupt patch\n");
216 + errx(1, "Corrupt patch");
217 err(1, "fread(%s)", argv[3]);
218 }
219
220 /* Check for appropriate magic */
221 if (memcmp(header, "BSDIFF40", 8) != 0)
222 - errx(1, "Corrupt patch\n");
223 + errx(1, "Corrupt patch");
224
225 /* Read lengths from header */
226 - bzctrllen=offtin(header+8);
227 - bzdatalen=offtin(header+16);
228 - newsize=offtin(header+24);
229 - if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
230 - errx(1,"Corrupt patch\n");
231 + bzctrllen = offtin(header + 8);
232 + bzdatalen = offtin(header + 16);
233 + newsize = offtin(header + 24);
234 + if (bzctrllen < 0 || bzctrllen > OFF_MAX - HEADER_SIZE ||
235 + bzdatalen < 0 || bzctrllen + HEADER_SIZE > OFF_MAX - bzdatalen ||
236 + newsize < 0 || newsize > SSIZE_MAX)
237 + errx(1, "Corrupt patch");
238
239 /* Close patch file and re-open it via libbzip2 at the right places */
240 if (fclose(f))
241 err(1, "fclose(%s)", argv[3]);
242 - if ((cpf = fopen(argv[3], "r")) == NULL)
243 - err(1, "fopen(%s)", argv[3]);
244 - if (fseeko(cpf, 32, SEEK_SET))
245 - err(1, "fseeko(%s, %lld)", argv[3],
246 - (long long)32);
247 + offset = HEADER_SIZE;
248 + if (fseeko(cpf, offset, SEEK_SET))
249 + err(1, "fseeko(%s, %jd)", argv[3], (intmax_t)offset);
250 if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
251 errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
252 - if ((dpf = fopen(argv[3], "r")) == NULL)
253 - err(1, "fopen(%s)", argv[3]);
254 - if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
255 - err(1, "fseeko(%s, %lld)", argv[3],
256 - (long long)(32 + bzctrllen));
257 + offset = add_off_t(offset, bzctrllen);
258 + if (fseeko(dpf, offset, SEEK_SET))
259 + err(1, "fseeko(%s, %jd)", argv[3], (intmax_t)offset);
260 if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
261 errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
262 - if ((epf = fopen(argv[3], "r")) == NULL)
263 - err(1, "fopen(%s)", argv[3]);
264 - if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
265 - err(1, "fseeko(%s, %lld)", argv[3],
266 - (long long)(32 + bzctrllen + bzdatalen));
267 + offset = add_off_t(offset, bzdatalen);
268 + if (fseeko(epf, offset, SEEK_SET))
269 + err(1, "fseeko(%s, %jd)", argv[3], (intmax_t)offset);
270 if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
271 errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
272
273 - if(((fd=open(argv[1],O_RDONLY,0))<0) ||
274 - ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
275 - ((old=malloc(oldsize+1))==NULL) ||
276 - (lseek(fd,0,SEEK_SET)!=0) ||
277 - (read(fd,old,oldsize)!=oldsize) ||
278 - (close(fd)==-1)) err(1,"%s",argv[1]);
279 - if((new=malloc(newsize+1))==NULL) err(1,NULL);
280 -
281 - oldpos=0;newpos=0;
282 - while(newpos<newsize) {
283 + if ((oldsize = lseek(oldfd, 0, SEEK_END)) == -1 ||
284 + oldsize > SSIZE_MAX ||
285 + (old = malloc(oldsize)) == NULL ||
286 + lseek(oldfd, 0, SEEK_SET) != 0 ||
287 + read(oldfd, old, oldsize) != oldsize ||
288 + close(oldfd) == -1)
289 + err(1, "%s", argv[1]);
290 + if ((new = malloc(newsize)) == NULL)
291 + err(1, NULL);
292 +
293 + oldpos = 0;
294 + newpos = 0;
295 + while (newpos < newsize) {
296 /* Read control data */
297 - for(i=0;i<=2;i++) {
298 + for (i = 0; i <= 2; i++) {
299 lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
300 if ((lenread < 8) || ((cbz2err != BZ_OK) &&
301 (cbz2err != BZ_STREAM_END)))
302 - errx(1, "Corrupt patch\n");
303 - ctrl[i]=offtin(buf);
304 - };
305 + errx(1, "Corrupt patch");
306 + ctrl[i] = offtin(buf);
307 + }
308
309 /* Sanity-check */
310 - if ((ctrl[0] < 0) || (ctrl[1] < 0))
311 - errx(1,"Corrupt patch\n");
312 + if (ctrl[0] < 0 || ctrl[0] > INT_MAX ||
313 + ctrl[1] < 0 || ctrl[1] > INT_MAX)
314 + errx(1, "Corrupt patch");
315
316 /* Sanity-check */
317 - if(newpos+ctrl[0]>newsize)
318 - errx(1,"Corrupt patch\n");
319 + if (add_off_t(newpos, ctrl[0]) > newsize)
320 + errx(1, "Corrupt patch");
321
322 /* Read diff string */
323 lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
324 if ((lenread < ctrl[0]) ||
325 ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
326 - errx(1, "Corrupt patch\n");
327 + errx(1, "Corrupt patch");
328
329 /* Add old data to diff string */
330 - for(i=0;i<ctrl[0];i++)
331 - if((oldpos+i>=0) && (oldpos+i<oldsize))
332 - new[newpos+i]+=old[oldpos+i];
333 + for (i = 0; i < ctrl[0]; i++)
334 + if (add_off_t(oldpos, i) < oldsize)
335 + new[newpos + i] += old[oldpos + i];
336
337 /* Adjust pointers */
338 - newpos+=ctrl[0];
339 - oldpos+=ctrl[0];
340 + newpos = add_off_t(newpos, ctrl[0]);
341 + oldpos = add_off_t(oldpos, ctrl[0]);
342
343 /* Sanity-check */
344 - if(newpos+ctrl[1]>newsize)
345 - errx(1,"Corrupt patch\n");
346 + if (add_off_t(newpos, ctrl[1]) > newsize)
347 + errx(1, "Corrupt patch");
348
349 /* Read extra string */
350 lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
351 if ((lenread < ctrl[1]) ||
352 ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
353 - errx(1, "Corrupt patch\n");
354 + errx(1, "Corrupt patch");
355
356 /* Adjust pointers */
357 - newpos+=ctrl[1];
358 - oldpos+=ctrl[2];
359 - };
360 + newpos = add_off_t(newpos, ctrl[1]);
361 + oldpos = add_off_t(oldpos, ctrl[2]);
362 + }
363
364 /* Clean up the bzip2 reads */
365 BZ2_bzReadClose(&cbz2err, cpfbz2);
366 @@ -197,12 +291,13 @@ int main(int argc,char * argv[])
367 err(1, "fclose(%s)", argv[3]);
368
369 /* Write the new file */
370 - if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
371 - (write(fd,new,newsize)!=newsize) || (close(fd)==-1))
372 - err(1,"%s",argv[2]);
373 + if (write(newfd, new, newsize) != newsize || close(newfd) == -1)
374 + err(1, "%s", argv[2]);
375 + /* Disable atexit cleanup */
376 + newfile = NULL;
377
378 free(new);
379 free(old);
380
381 - return 0;
382 + return (0);
383 }