File: | compress.c |
Warning: | line 873, column 8 Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) Ian F. Darwin 1986-1995. |
3 | * Software written by Ian F. Darwin and others; |
4 | * maintained 1995-present by Christos Zoulas and others. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice immediately at the beginning of the file, without modification, |
11 | * this list of conditions, and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /* |
29 | * compress routines: |
30 | * zmagic() - returns 0 if not recognized, uncompresses and prints |
31 | * information if recognized |
32 | * uncompress(method, old, n, newch) - uncompress old into new, |
33 | * using method, return sizeof new |
34 | */ |
35 | #include "file.h" |
36 | |
37 | #ifndef lint |
38 | FILE_RCSID("@(#)$File: compress.c,v 1.131 2021/10/28 16:01:58 christos Exp $")static const char rcsid[] __attribute__((__used__)) = "@(#)$File: compress.c,v 1.131 2021/10/28 16:01:58 christos Exp $" ; |
39 | #endif |
40 | |
41 | #include "magic.h" |
42 | #include <stdlib.h> |
43 | #ifdef HAVE_UNISTD_H1 |
44 | #include <unistd.h> |
45 | #endif |
46 | #include <string.h> |
47 | #include <errno(*__errno_location ()).h> |
48 | #include <ctype.h> |
49 | #include <stdarg.h> |
50 | #include <signal.h> |
51 | #ifndef HAVE_SIG_T1 |
52 | typedef void (*sig_t)(int); |
53 | #endif /* HAVE_SIG_T */ |
54 | #if !defined(__MINGW32__) && !defined(WIN32) && !defined(__MINGW64__) |
55 | #include <sys/ioctl.h> |
56 | #endif |
57 | #ifdef HAVE_SYS_WAIT_H1 |
58 | #include <sys/wait.h> |
59 | #endif |
60 | #if defined(HAVE_SYS_TIME_H1) |
61 | #include <sys/time.h> |
62 | #endif |
63 | |
64 | #if defined(HAVE_ZLIB_H1) && defined(ZLIBSUPPORT1) |
65 | #define BUILTIN_DECOMPRESS |
66 | #include <zlib.h> |
67 | #endif |
68 | |
69 | #if defined(HAVE_BZLIB_H1) && defined(BZLIBSUPPORT1) |
70 | #define BUILTIN_BZLIB |
71 | #include <bzlib.h> |
72 | #endif |
73 | |
74 | #if defined(HAVE_LZMA_H1) && defined(XZLIBSUPPORT1) |
75 | #define BUILTIN_XZLIB |
76 | #include <lzma.h> |
77 | #endif |
78 | |
79 | #ifdef DEBUG |
80 | int tty = -1; |
81 | #define DPRINTF(...) do { \ |
82 | if (tty == -1) \ |
83 | tty = open("/dev/tty", O_RDWR02); \ |
84 | if (tty == -1) \ |
85 | abort(); \ |
86 | dprintf(tty, __VA_ARGS__); \ |
87 | } while (/*CONSTCOND*/0) |
88 | #else |
89 | #define DPRINTF(...) |
90 | #endif |
91 | |
92 | #ifdef ZLIBSUPPORT1 |
93 | /* |
94 | * The following python code is not really used because ZLIBSUPPORT is only |
95 | * defined if we have a built-in zlib, and the built-in zlib handles that. |
96 | * That is not true for android where we have zlib.h and not -lz. |
97 | */ |
98 | static const char zlibcode[] = |
99 | "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; |
100 | |
101 | static const char *zlib_args[] = { "python", "-c", zlibcode, NULL((void*)0) }; |
102 | |
103 | static int |
104 | zlibcmp(const unsigned char *buf) |
105 | { |
106 | unsigned short x = 1; |
107 | unsigned char *s = CAST(unsigned char *, CAST(void *, &x))((unsigned char *)(((void *)(&x)))); |
108 | |
109 | if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) |
110 | return 0; |
111 | if (s[0] != 1) /* endianness test */ |
112 | x = buf[0] | (buf[1] << 8); |
113 | else |
114 | x = buf[1] | (buf[0] << 8); |
115 | if (x % 31) |
116 | return 0; |
117 | return 1; |
118 | } |
119 | #endif |
120 | |
121 | static int |
122 | lzmacmp(const unsigned char *buf) |
123 | { |
124 | if (buf[0] != 0x5d || buf[1] || buf[2]) |
125 | return 0; |
126 | if (buf[12] && buf[12] != 0xff) |
127 | return 0; |
128 | return 1; |
129 | } |
130 | |
131 | #define gzip_flags"-cd" "-cd" |
132 | #define lrzip_flags"-do" "-do" |
133 | #define lzip_flags"-cd" gzip_flags"-cd" |
134 | |
135 | static const char *gzip_args[] = { |
136 | "gzip", gzip_flags"-cd", NULL((void*)0) |
137 | }; |
138 | static const char *uncompress_args[] = { |
139 | "uncompress", "-c", NULL((void*)0) |
140 | }; |
141 | static const char *bzip2_args[] = { |
142 | "bzip2", "-cd", NULL((void*)0) |
143 | }; |
144 | static const char *lzip_args[] = { |
145 | "lzip", lzip_flags"-cd", NULL((void*)0) |
146 | }; |
147 | static const char *xz_args[] = { |
148 | "xz", "-cd", NULL((void*)0) |
149 | }; |
150 | static const char *lrzip_args[] = { |
151 | "lrzip", lrzip_flags"-do", NULL((void*)0) |
152 | }; |
153 | static const char *lz4_args[] = { |
154 | "lz4", "-cd", NULL((void*)0) |
155 | }; |
156 | static const char *zstd_args[] = { |
157 | "zstd", "-cd", NULL((void*)0) |
158 | }; |
159 | |
160 | #define do_zlib((void*)0) NULL((void*)0) |
161 | #define do_bzlib((void*)0) NULL((void*)0) |
162 | |
163 | privatestatic const struct { |
164 | union { |
165 | const char *magic; |
166 | int (*func)(const unsigned char *); |
167 | } u; |
168 | int maglen; |
169 | const char **argv; |
170 | void *unused; |
171 | } compr[] = { |
172 | #define METH_FROZEN2 2 |
173 | #define METH_BZIP7 7 |
174 | #define METH_XZ9 9 |
175 | #define METH_LZMA13 13 |
176 | #define METH_ZLIB14 14 |
177 | { { .magic = "\037\235" }, 2, gzip_args, NULL((void*)0) }, /* 0, compressed */ |
178 | /* Uncompress can get stuck; so use gzip first if we have it |
179 | * Idea from Damien Clark, thanks! */ |
180 | { { .magic = "\037\235" }, 2, uncompress_args, NULL((void*)0) },/* 1, compressed */ |
181 | { { .magic = "\037\213" }, 2, gzip_args, do_zlib((void*)0) },/* 2, gzipped */ |
182 | { { .magic = "\037\236" }, 2, gzip_args, NULL((void*)0) }, /* 3, frozen */ |
183 | { { .magic = "\037\240" }, 2, gzip_args, NULL((void*)0) }, /* 4, SCO LZH */ |
184 | /* the standard pack utilities do not accept standard input */ |
185 | { { .magic = "\037\036" }, 2, gzip_args, NULL((void*)0) }, /* 5, packed */ |
186 | { { .magic = "PK\3\4" }, 4, gzip_args, NULL((void*)0) }, /* 6, pkziped */ |
187 | /* ...only first file examined */ |
188 | { { .magic = "BZh" }, 3, bzip2_args, do_bzlib((void*)0) },/* 7, bzip2-ed */ |
189 | { { .magic = "LZIP" }, 4, lzip_args, NULL((void*)0) }, /* 8, lzip-ed */ |
190 | { { .magic = "\3757zXZ\0" },6, xz_args, NULL((void*)0) }, /* 9, XZ Util */ |
191 | { { .magic = "LRZI" }, 4, lrzip_args, NULL((void*)0) }, /* 10, LRZIP */ |
192 | { { .magic = "\004\"M\030" },4, lz4_args, NULL((void*)0) }, /* 11, LZ4 */ |
193 | { { .magic = "\x28\xB5\x2F\xFD" }, 4, zstd_args, NULL((void*)0) },/* 12, zstd */ |
194 | { { .func = lzmacmp }, -13, xz_args, NULL((void*)0) }, /* 13, lzma */ |
195 | #ifdef ZLIBSUPPORT1 |
196 | { { .func = zlibcmp }, -2, zlib_args, NULL((void*)0) }, /* 14, zlib */ |
197 | #endif |
198 | }; |
199 | |
200 | #define OKDATA0 0 |
201 | #define NODATA1 1 |
202 | #define ERRDATA2 2 |
203 | |
204 | privatestatic ssize_t swrite(int, const void *, size_t); |
205 | #if HAVE_FORK1 |
206 | privatestatic size_t ncompr = __arraycount(compr)(sizeof(compr) / sizeof(compr[0])); |
207 | privatestatic int uncompressbuf(int, size_t, size_t, const unsigned char *, |
208 | unsigned char **, size_t *); |
209 | #ifdef BUILTIN_DECOMPRESS |
210 | privatestatic int uncompresszlib(const unsigned char *, unsigned char **, size_t, |
211 | size_t *, int); |
212 | privatestatic int uncompressgzipped(const unsigned char *, unsigned char **, size_t, |
213 | size_t *); |
214 | #endif |
215 | #ifdef BUILTIN_BZLIB |
216 | privatestatic int uncompressbzlib(const unsigned char *, unsigned char **, size_t, |
217 | size_t *); |
218 | #endif |
219 | #ifdef BUILTIN_XZLIB |
220 | privatestatic int uncompressxzlib(const unsigned char *, unsigned char **, size_t, |
221 | size_t *); |
222 | #endif |
223 | |
224 | static int makeerror(unsigned char **, size_t *, const char *, ...) |
225 | __attribute__((__format__(__printf__, 3, 4))); |
226 | privatestatic const char *methodname(size_t); |
227 | |
228 | privatestatic int |
229 | format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf) |
230 | { |
231 | unsigned char *p; |
232 | int mime = ms->flags & MAGIC_MIME(0x0000010|0x0000400); |
233 | |
234 | if (!mime) |
235 | return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf); |
236 | |
237 | for (p = buf; *p; p++) |
238 | if (!isalnum(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int) _ISalnum)) |
239 | *p = '-'; |
240 | |
241 | return file_printf(ms, "application/x-decompression-error-%s-%s", |
242 | methodname(i), buf); |
243 | } |
244 | |
245 | protected__attribute__ ((__visibility__("hidden"))) int |
246 | file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) |
247 | { |
248 | unsigned char *newbuf = NULL((void*)0); |
249 | size_t i, nsz; |
250 | char *rbuf; |
251 | file_pushbuf_t *pb; |
252 | int urv, prv, rv = 0; |
253 | int mime = ms->flags & MAGIC_MIME(0x0000010|0x0000400); |
254 | int fd = b->fd; |
255 | const unsigned char *buf = CAST(const unsigned char *, b->fbuf)((const unsigned char *)(b->fbuf)); |
256 | size_t nbytes = b->flen; |
257 | int sa_saved = 0; |
258 | struct sigaction sig_act; |
259 | |
260 | if ((ms->flags & MAGIC_COMPRESS0x0000004) == 0) |
261 | return 0; |
262 | |
263 | for (i = 0; i < ncompr; i++) { |
264 | int zm; |
265 | if (nbytes < CAST(size_t, abs(compr[i].maglen))((size_t)(abs(compr[i].maglen)))) |
266 | continue; |
267 | if (compr[i].maglen < 0) { |
268 | zm = (*compr[i].u.func)(buf); |
269 | } else { |
270 | zm = memcmp(buf, compr[i].u.magic, |
271 | CAST(size_t, compr[i].maglen)((size_t)(compr[i].maglen))) == 0; |
272 | } |
273 | |
274 | if (!zm) |
275 | continue; |
276 | |
277 | /* Prevent SIGPIPE death if child dies unexpectedly */ |
278 | if (!sa_saved) { |
279 | //We can use sig_act for both new and old, but |
280 | struct sigaction new_act; |
281 | memset(&new_act, 0, sizeof(new_act)); |
282 | new_act.sa_handler__sigaction_handler.sa_handler = SIG_IGN((__sighandler_t) 1); |
283 | sa_saved = sigaction(SIGPIPE13, &new_act, &sig_act) != -1; |
284 | } |
285 | |
286 | nsz = nbytes; |
287 | urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); |
288 | DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv, |
289 | (char *)newbuf, nsz); |
290 | switch (urv) { |
291 | case OKDATA0: |
292 | case ERRDATA2: |
293 | ms->flags &= ~MAGIC_COMPRESS0x0000004; |
294 | if (urv == ERRDATA2) |
295 | prv = format_decompression_error(ms, i, newbuf); |
296 | else |
297 | prv = file_buffer(ms, -1, NULL((void*)0), name, newbuf, nsz); |
298 | if (prv == -1) |
299 | goto error; |
300 | rv = 1; |
301 | if ((ms->flags & MAGIC_COMPRESS_TRANSP0x2000000) != 0) |
302 | goto out; |
303 | if (mime != MAGIC_MIME(0x0000010|0x0000400) && mime != 0) |
304 | goto out; |
305 | if ((file_printf(ms, |
306 | mime ? " compressed-encoding=" : " (")) == -1) |
307 | goto error; |
308 | if ((pb = file_push_buffer(ms)) == NULL((void*)0)) |
309 | goto error; |
310 | /* |
311 | * XXX: If file_buffer fails here, we overwrite |
312 | * the compressed text. FIXME. |
313 | */ |
314 | if (file_buffer(ms, -1, NULL((void*)0), NULL((void*)0), buf, nbytes) == -1) { |
315 | if (file_pop_buffer(ms, pb) != NULL((void*)0)) |
316 | abort(); |
317 | goto error; |
318 | } |
319 | if ((rbuf = file_pop_buffer(ms, pb)) != NULL((void*)0)) { |
320 | if (file_printf(ms, "%s", rbuf) == -1) { |
321 | free(rbuf); |
322 | goto error; |
323 | } |
324 | free(rbuf); |
325 | } |
326 | if (!mime && file_printf(ms, ")") == -1) |
327 | goto error; |
328 | /*FALLTHROUGH*/ |
329 | case NODATA1: |
330 | break; |
331 | default: |
332 | abort(); |
333 | /*NOTREACHED*/ |
334 | error: |
335 | rv = -1; |
336 | break; |
337 | } |
338 | } |
339 | out: |
340 | DPRINTF("rv = %d\n", rv); |
341 | |
342 | if (sa_saved && sig_act.sa_handler__sigaction_handler.sa_handler != SIG_IGN((__sighandler_t) 1)) |
343 | (void)sigaction(SIGPIPE13, &sig_act, NULL((void*)0)); |
344 | |
345 | free(newbuf); |
346 | ms->flags |= MAGIC_COMPRESS0x0000004; |
347 | DPRINTF("Zmagic returns %d\n", rv); |
348 | return rv; |
349 | } |
350 | #endif |
351 | /* |
352 | * `safe' write for sockets and pipes. |
353 | */ |
354 | privatestatic ssize_t |
355 | swrite(int fd, const void *buf, size_t n) |
356 | { |
357 | ssize_t rv; |
358 | size_t rn = n; |
359 | |
360 | do |
361 | switch (rv = write(fd, buf, n)) { |
362 | case -1: |
363 | if (errno(*__errno_location ()) == EINTR4) |
364 | continue; |
365 | return -1; |
366 | default: |
367 | n -= rv; |
368 | buf = CAST(const char *, buf)((const char *)(buf)) + rv; |
369 | break; |
370 | } |
371 | while (n > 0); |
372 | return rn; |
373 | } |
374 | |
375 | |
376 | /* |
377 | * `safe' read for sockets and pipes. |
378 | */ |
379 | protected__attribute__ ((__visibility__("hidden"))) ssize_t |
380 | sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) |
381 | { |
382 | ssize_t rv; |
383 | #ifdef FIONREAD0x541B |
384 | int t = 0; |
385 | #endif |
386 | size_t rn = n; |
387 | |
388 | if (fd == STDIN_FILENO0) |
389 | goto nocheck; |
390 | |
391 | #ifdef FIONREAD0x541B |
392 | if (canbepipe && (ioctl(fd, FIONREAD0x541B, &t) == -1 || t == 0)) { |
393 | #ifdef FD_ZERO |
394 | ssize_t cnt; |
395 | for (cnt = 0;; cnt++) { |
396 | fd_set check; |
397 | struct timeval tout = {0, 100 * 1000}; |
398 | int selrv; |
399 | |
400 | FD_ZERO(&check)do { unsigned int __i; fd_set *__arr = (&check); for (__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ( (__arr)->fds_bits)[__i] = 0; } while (0); |
401 | FD_SET(fd, &check)((void) (((&check)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((fd) % (8 * (int ) sizeof (__fd_mask))))))); |
402 | |
403 | /* |
404 | * Avoid soft deadlock: do not read if there |
405 | * is nothing to read from sockets and pipes. |
406 | */ |
407 | selrv = select(fd + 1, &check, NULL((void*)0), NULL((void*)0), &tout); |
408 | if (selrv == -1) { |
409 | if (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11) |
410 | continue; |
411 | } else if (selrv == 0 && cnt >= 5) { |
412 | return 0; |
413 | } else |
414 | break; |
415 | } |
416 | #endif |
417 | (void)ioctl(fd, FIONREAD0x541B, &t); |
418 | } |
419 | |
420 | if (t > 0 && CAST(size_t, t)((size_t)(t)) < n) { |
421 | n = t; |
422 | rn = n; |
423 | } |
424 | #endif |
425 | |
426 | nocheck: |
427 | do |
428 | switch ((rv = read(fd, buf, n))) { |
429 | case -1: |
430 | if (errno(*__errno_location ()) == EINTR4) |
431 | continue; |
432 | return -1; |
433 | case 0: |
434 | return rn - n; |
435 | default: |
436 | n -= rv; |
437 | buf = CAST(char *, CCAST(void *, buf))((char *)(((void *)(uintptr_t)(buf)))) + rv; |
438 | break; |
439 | } |
440 | while (n > 0); |
441 | return rn; |
442 | } |
443 | |
444 | protected__attribute__ ((__visibility__("hidden"))) int |
445 | file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, |
446 | size_t nbytes) |
447 | { |
448 | char buf[4096]; |
449 | ssize_t r; |
450 | int tfd; |
451 | |
452 | (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf); |
453 | #ifndef HAVE_MKSTEMP1 |
454 | { |
455 | char *ptr = mktemp(buf); |
456 | tfd = open(ptr, O_RDWR02|O_TRUNC01000|O_EXCL0200|O_CREAT0100, 0600); |
457 | r = errno(*__errno_location ()); |
458 | (void)unlink(ptr); |
459 | errno(*__errno_location ()) = r; |
460 | } |
461 | #else |
462 | { |
463 | int te; |
464 | mode_t ou = umask(0); |
465 | tfd = mkstemp(buf); |
466 | (void)umask(ou); |
467 | te = errno(*__errno_location ()); |
468 | (void)unlink(buf); |
469 | errno(*__errno_location ()) = te; |
470 | } |
471 | #endif |
472 | if (tfd == -1) { |
473 | file_error(ms, errno(*__errno_location ()), |
474 | "cannot create temporary file for pipe copy"); |
475 | return -1; |
476 | } |
477 | |
478 | if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes)((ssize_t)(nbytes))) |
479 | r = 1; |
480 | else { |
481 | while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) |
482 | if (swrite(tfd, buf, CAST(size_t, r)((size_t)(r))) != r) |
483 | break; |
484 | } |
485 | |
486 | switch (r) { |
487 | case -1: |
488 | file_error(ms, errno(*__errno_location ()), "error copying from pipe to temp file"); |
489 | return -1; |
490 | case 0: |
491 | break; |
492 | default: |
493 | file_error(ms, errno(*__errno_location ()), "error while writing to temp file"); |
494 | return -1; |
495 | } |
496 | |
497 | /* |
498 | * We duplicate the file descriptor, because fclose on a |
499 | * tmpfile will delete the file, but any open descriptors |
500 | * can still access the phantom inode. |
501 | */ |
502 | if ((fd = dup2(tfd, fd)) == -1) { |
503 | file_error(ms, errno(*__errno_location ()), "could not dup descriptor for temp file"); |
504 | return -1; |
505 | } |
506 | (void)close(tfd); |
507 | if (lseek(fd, CAST(off_t, 0)((off_t)(0)), SEEK_SET0) == CAST(off_t, -1)((off_t)(-1))) { |
508 | file_badseek(ms); |
509 | return -1; |
510 | } |
511 | return fd; |
512 | } |
513 | #if HAVE_FORK1 |
514 | #ifdef BUILTIN_DECOMPRESS |
515 | |
516 | #define FHCRC(1 << 1) (1 << 1) |
517 | #define FEXTRA(1 << 2) (1 << 2) |
518 | #define FNAME(1 << 3) (1 << 3) |
519 | #define FCOMMENT(1 << 4) (1 << 4) |
520 | |
521 | |
522 | privatestatic int |
523 | uncompressgzipped(const unsigned char *old, unsigned char **newch, |
524 | size_t bytes_max, size_t *n) |
525 | { |
526 | unsigned char flg = old[3]; |
527 | size_t data_start = 10; |
528 | |
529 | if (flg & FEXTRA(1 << 2)) { |
530 | if (data_start + 1 >= *n) |
531 | goto err; |
532 | data_start += 2 + old[data_start] + old[data_start + 1] * 256; |
533 | } |
534 | if (flg & FNAME(1 << 3)) { |
535 | while(data_start < *n && old[data_start]) |
536 | data_start++; |
537 | data_start++; |
538 | } |
539 | if (flg & FCOMMENT(1 << 4)) { |
540 | while(data_start < *n && old[data_start]) |
541 | data_start++; |
542 | data_start++; |
543 | } |
544 | if (flg & FHCRC(1 << 1)) |
545 | data_start += 2; |
546 | |
547 | if (data_start >= *n) |
548 | goto err; |
549 | |
550 | *n -= data_start; |
551 | old += data_start; |
552 | return uncompresszlib(old, newch, bytes_max, n, 0); |
553 | err: |
554 | return makeerror(newch, n, "File too short"); |
555 | } |
556 | |
557 | privatestatic int |
558 | uncompresszlib(const unsigned char *old, unsigned char **newch, |
559 | size_t bytes_max, size_t *n, int zlib) |
560 | { |
561 | int rc; |
562 | z_stream z; |
563 | |
564 | if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))((unsigned char *)(malloc(bytes_max + 1)))) == NULL((void*)0)) |
565 | return makeerror(newch, n, "No buffer, %s", strerror(errno(*__errno_location ()))); |
566 | |
567 | z.next_in = CCAST(Bytef *, old)((Bytef *)(uintptr_t)(old)); |
568 | z.avail_in = CAST(uint32_t, *n)((uint32_t)(*n)); |
569 | z.next_out = *newch; |
570 | z.avail_out = CAST(unsigned int, bytes_max)((unsigned int)(bytes_max)); |
571 | z.zalloc = Z_NULL0; |
572 | z.zfree = Z_NULL0; |
573 | z.opaque = Z_NULL0; |
574 | |
575 | /* LINTED bug in header macro */ |
576 | rc = zlib ? inflateInit(&z)inflateInit_((&z), "1.2.11", (int)sizeof(z_stream)) : inflateInit2(&z, -15)inflateInit2_((&z), (-15), "1.2.11", (int)sizeof(z_stream )); |
577 | if (rc != Z_OK0) |
578 | goto err; |
579 | |
580 | rc = inflate(&z, Z_SYNC_FLUSH2); |
581 | if (rc != Z_OK0 && rc != Z_STREAM_END1) |
582 | goto err; |
583 | |
584 | *n = CAST(size_t, z.total_out)((size_t)(z.total_out)); |
585 | rc = inflateEnd(&z); |
586 | if (rc != Z_OK0) |
587 | goto err; |
588 | |
589 | /* let's keep the nul-terminate tradition */ |
590 | (*newch)[*n] = '\0'; |
591 | |
592 | return OKDATA0; |
593 | err: |
594 | strlcpy(RCAST(char *, *newch)((char *)(uintptr_t)(*newch)), z.msg ? z.msg : zError(rc), bytes_max); |
595 | *n = strlen(RCAST(char *, *newch)((char *)(uintptr_t)(*newch))); |
596 | return ERRDATA2; |
597 | } |
598 | #endif |
599 | |
600 | #ifdef BUILTIN_BZLIB |
601 | privatestatic int |
602 | uncompressbzlib(const unsigned char *old, unsigned char **newch, |
603 | size_t bytes_max, size_t *n) |
604 | { |
605 | int rc; |
606 | bz_stream bz; |
607 | |
608 | memset(&bz, 0, sizeof(bz)); |
609 | rc = BZ2_bzDecompressInit(&bz, 0, 0); |
610 | if (rc != BZ_OK0) |
611 | goto err; |
612 | |
613 | if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))((unsigned char *)(malloc(bytes_max + 1)))) == NULL((void*)0)) |
614 | return makeerror(newch, n, "No buffer, %s", strerror(errno(*__errno_location ()))); |
615 | |
616 | bz.next_in = CCAST(char *, RCAST(const char *, old))((char *)(uintptr_t)(((const char *)(uintptr_t)(old)))); |
617 | bz.avail_in = CAST(uint32_t, *n)((uint32_t)(*n)); |
618 | bz.next_out = RCAST(char *, *newch)((char *)(uintptr_t)(*newch)); |
619 | bz.avail_out = CAST(unsigned int, bytes_max)((unsigned int)(bytes_max)); |
620 | |
621 | rc = BZ2_bzDecompress(&bz); |
622 | if (rc != BZ_OK0 && rc != BZ_STREAM_END4) |
623 | goto err; |
624 | |
625 | /* Assume byte_max is within 32bit */ |
626 | /* assert(bz.total_out_hi32 == 0); */ |
627 | *n = CAST(size_t, bz.total_out_lo32)((size_t)(bz.total_out_lo32)); |
628 | rc = BZ2_bzDecompressEnd(&bz); |
629 | if (rc != BZ_OK0) |
630 | goto err; |
631 | |
632 | /* let's keep the nul-terminate tradition */ |
633 | (*newch)[*n] = '\0'; |
634 | |
635 | return OKDATA0; |
636 | err: |
637 | snprintf(RCAST(char *, *newch)((char *)(uintptr_t)(*newch)), bytes_max, "bunzip error %d", rc); |
638 | *n = strlen(RCAST(char *, *newch)((char *)(uintptr_t)(*newch))); |
639 | return ERRDATA2; |
640 | } |
641 | #endif |
642 | |
643 | #ifdef BUILTIN_XZLIB |
644 | privatestatic int |
645 | uncompressxzlib(const unsigned char *old, unsigned char **newch, |
646 | size_t bytes_max, size_t *n) |
647 | { |
648 | int rc; |
649 | lzma_stream xz; |
650 | |
651 | memset(&xz, 0, sizeof(xz)); |
652 | rc = lzma_auto_decoder(&xz, UINT64_MAX(18446744073709551615UL), 0); |
653 | if (rc != LZMA_OK) |
654 | goto err; |
655 | |
656 | if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))((unsigned char *)(malloc(bytes_max + 1)))) == NULL((void*)0)) |
657 | return makeerror(newch, n, "No buffer, %s", strerror(errno(*__errno_location ()))); |
658 | |
659 | xz.next_in = CCAST(const uint8_t *, old)((const uint8_t *)(uintptr_t)(old)); |
660 | xz.avail_in = CAST(uint32_t, *n)((uint32_t)(*n)); |
661 | xz.next_out = RCAST(uint8_t *, *newch)((uint8_t *)(uintptr_t)(*newch)); |
662 | xz.avail_out = CAST(unsigned int, bytes_max)((unsigned int)(bytes_max)); |
663 | |
664 | rc = lzma_code(&xz, LZMA_RUN); |
665 | if (rc != LZMA_OK && rc != LZMA_STREAM_END) |
666 | goto err; |
667 | |
668 | *n = CAST(size_t, xz.total_out)((size_t)(xz.total_out)); |
669 | |
670 | lzma_end(&xz); |
671 | |
672 | /* let's keep the nul-terminate tradition */ |
673 | (*newch)[*n] = '\0'; |
674 | |
675 | return OKDATA0; |
676 | err: |
677 | snprintf(RCAST(char *, *newch)((char *)(uintptr_t)(*newch)), bytes_max, "unxz error %d", rc); |
678 | *n = strlen(RCAST(char *, *newch)((char *)(uintptr_t)(*newch))); |
679 | return ERRDATA2; |
680 | } |
681 | #endif |
682 | |
683 | |
684 | static int |
685 | makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) |
686 | { |
687 | char *msg; |
688 | va_list ap; |
689 | int rv; |
690 | |
691 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
692 | rv = vasprintf(&msg, fmt, ap); |
693 | va_end(ap)__builtin_va_end(ap); |
694 | if (rv < 0) { |
695 | *buf = NULL((void*)0); |
696 | *len = 0; |
697 | return NODATA1; |
698 | } |
699 | *buf = RCAST(unsigned char *, msg)((unsigned char *)(uintptr_t)(msg)); |
700 | *len = strlen(msg); |
701 | return ERRDATA2; |
702 | } |
703 | |
704 | static void |
705 | closefd(int *fd, size_t i) |
706 | { |
707 | if (fd[i] == -1) |
708 | return; |
709 | (void) close(fd[i]); |
710 | fd[i] = -1; |
711 | } |
712 | |
713 | static void |
714 | closep(int *fd) |
715 | { |
716 | size_t i; |
717 | for (i = 0; i < 2; i++) |
718 | closefd(fd, i); |
719 | } |
720 | |
721 | static int |
722 | copydesc(int i, int fd) |
723 | { |
724 | if (fd == i) |
725 | return 0; /* "no dup was necessary" */ |
726 | if (dup2(fd, i) == -1) { |
727 | DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno)); |
728 | exit(1); |
729 | } |
730 | return 1; |
731 | } |
732 | |
733 | static pid_t |
734 | writechild(int fd, const void *old, size_t n) |
735 | { |
736 | pid_t pid; |
737 | |
738 | /* |
739 | * fork again, to avoid blocking because both |
740 | * pipes filled |
741 | */ |
742 | pid = fork(); |
743 | if (pid == -1) { |
744 | DPRINTF("Fork failed (%s)\n", strerror(errno)); |
745 | exit(1); |
746 | } |
747 | if (pid == 0) { |
748 | /* child */ |
749 | if (swrite(fd, old, n) != CAST(ssize_t, n)((ssize_t)(n))) { |
750 | DPRINTF("Write failed (%s)\n", strerror(errno)); |
751 | exit(1); |
752 | } |
753 | exit(0); |
754 | } |
755 | /* parent */ |
756 | return pid; |
757 | } |
758 | |
759 | static ssize_t |
760 | filter_error(unsigned char *ubuf, ssize_t n) |
761 | { |
762 | char *p; |
763 | char *buf; |
764 | |
765 | ubuf[n] = '\0'; |
766 | buf = RCAST(char *, ubuf)((char *)(uintptr_t)(ubuf)); |
767 | while (isspace(CAST(unsigned char, *buf))((*__ctype_b_loc ())[(int) ((((unsigned char)(*buf))))] & (unsigned short int) _ISspace)) |
768 | buf++; |
769 | DPRINTF("Filter error[[[%s]]]\n", buf); |
770 | if ((p = strchr(CAST(char *, buf)((char *)(buf)), '\n')) != NULL((void*)0)) |
771 | *p = '\0'; |
772 | if ((p = strchr(CAST(char *, buf)((char *)(buf)), ';')) != NULL((void*)0)) |
773 | *p = '\0'; |
774 | if ((p = strrchr(CAST(char *, buf)((char *)(buf)), ':')) != NULL((void*)0)) { |
775 | ++p; |
776 | while (isspace(CAST(unsigned char, *p))((*__ctype_b_loc ())[(int) ((((unsigned char)(*p))))] & ( unsigned short int) _ISspace)) |
777 | p++; |
778 | n = strlen(p); |
779 | memmove(ubuf, p, CAST(size_t, n + 1)((size_t)(n + 1))); |
780 | } |
781 | DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); |
782 | if (islower(*ubuf)((*__ctype_b_loc ())[(int) ((*ubuf))] & (unsigned short int ) _ISlower)) |
783 | *ubuf = toupper(*ubuf); |
784 | return n; |
785 | } |
786 | |
787 | privatestatic const char * |
788 | methodname(size_t method) |
789 | { |
790 | switch (method) { |
791 | #ifdef BUILTIN_DECOMPRESS |
792 | case METH_FROZEN2: |
793 | case METH_ZLIB14: |
794 | return "zlib"; |
795 | #endif |
796 | #ifdef BUILTIN_BZLIB |
797 | case METH_BZIP7: |
798 | return "bzlib"; |
799 | #endif |
800 | #ifdef BUILTIN_XZLIB |
801 | case METH_XZ9: |
802 | case METH_LZMA13: |
803 | return "xzlib"; |
804 | #endif |
805 | default: |
806 | return compr[method].argv[0]; |
807 | } |
808 | } |
809 | |
810 | privatestatic int |
811 | uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, |
812 | unsigned char **newch, size_t* n) |
813 | { |
814 | int fdp[3][2]; |
815 | int status, rv, w; |
816 | pid_t pid; |
817 | pid_t writepid = -1; |
818 | size_t i; |
819 | ssize_t r; |
820 | |
821 | switch (method) { |
822 | #ifdef BUILTIN_DECOMPRESS |
823 | case METH_FROZEN2: |
824 | return uncompressgzipped(old, newch, bytes_max, n); |
825 | case METH_ZLIB14: |
826 | return uncompresszlib(old, newch, bytes_max, n, 1); |
827 | #endif |
828 | #ifdef BUILTIN_BZLIB |
829 | case METH_BZIP7: |
830 | return uncompressbzlib(old, newch, bytes_max, n); |
831 | #endif |
832 | #ifdef BUILTIN_XZLIB |
833 | case METH_XZ9: |
834 | case METH_LZMA13: |
835 | return uncompressxzlib(old, newch, bytes_max, n); |
836 | #endif |
837 | default: |
838 | break; |
839 | } |
840 | |
841 | (void)fflush(stdoutstdout); |
842 | (void)fflush(stderrstderr); |
843 | |
844 | for (i = 0; i < __arraycount(fdp)(sizeof(fdp) / sizeof(fdp[0])); i++) |
845 | fdp[i][0] = fdp[i][1] = -1; |
846 | |
847 | /* |
848 | * There are multithreaded users who run magic_file() |
849 | * from dozens of threads. If two parallel magic_file() calls |
850 | * analyze two large compressed files, both will spawn |
851 | * an uncompressing child here, which writes out uncompressed data. |
852 | * We read some portion, then close the pipe, then waitpid() the child. |
853 | * If uncompressed data is larger, child shound get EPIPE and exit. |
854 | * However, with *parallel* calls OTHER child may unintentionally |
855 | * inherit pipe fds, thus keeping pipe open and making writes in |
856 | * our child block instead of failing with EPIPE! |
857 | * (For the bug to occur, two threads must mutually inherit their pipes, |
858 | * and both must have large outputs. Thus it happens not that often). |
859 | * To avoid this, be sure to create pipes with O_CLOEXEC. |
860 | */ |
861 | if ((fd == -1 && file_pipe_closexec(fdp[STDIN_FILENO0]) == -1) || |
862 | file_pipe_closexec(fdp[STDOUT_FILENO1]) == -1 || |
863 | file_pipe_closexec(fdp[STDERR_FILENO2]) == -1) { |
864 | closep(fdp[STDIN_FILENO0]); |
865 | closep(fdp[STDOUT_FILENO1]); |
866 | return makeerror(newch, n, "Cannot create pipe, %s", |
867 | strerror(errno(*__errno_location ()))); |
868 | } |
869 | |
870 | /* For processes with large mapped virtual sizes, vfork |
871 | * may be _much_ faster (10-100 times) than fork. |
872 | */ |
873 | pid = vfork(); |
Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process. Replace calls to vfork with calls to the safer 'posix_spawn' function | |
874 | if (pid == -1) { |
875 | return makeerror(newch, n, "Cannot vfork, %s", |
876 | strerror(errno(*__errno_location ()))); |
877 | } |
878 | if (pid == 0) { |
879 | /* child */ |
880 | /* Note: we are after vfork, do not modify memory |
881 | * in a way which confuses parent. In particular, |
882 | * do not modify fdp[i][j]. |
883 | */ |
884 | if (fd != -1) { |
885 | (void) lseek(fd, CAST(off_t, 0)((off_t)(0)), SEEK_SET0); |
886 | if (copydesc(STDIN_FILENO0, fd)) |
887 | (void) close(fd); |
888 | } else { |
889 | if (copydesc(STDIN_FILENO0, fdp[STDIN_FILENO0][0])) |
890 | (void) close(fdp[STDIN_FILENO0][0]); |
891 | if (fdp[STDIN_FILENO0][1] > 2) |
892 | (void) close(fdp[STDIN_FILENO0][1]); |
893 | } |
894 | file_clear_closexec(STDIN_FILENO0); |
895 | |
896 | ///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly |
897 | if (copydesc(STDOUT_FILENO1, fdp[STDOUT_FILENO1][1])) |
898 | (void) close(fdp[STDOUT_FILENO1][1]); |
899 | if (fdp[STDOUT_FILENO1][0] > 2) |
900 | (void) close(fdp[STDOUT_FILENO1][0]); |
901 | file_clear_closexec(STDOUT_FILENO1); |
902 | |
903 | if (copydesc(STDERR_FILENO2, fdp[STDERR_FILENO2][1])) |
904 | (void) close(fdp[STDERR_FILENO2][1]); |
905 | if (fdp[STDERR_FILENO2][0] > 2) |
906 | (void) close(fdp[STDERR_FILENO2][0]); |
907 | file_clear_closexec(STDERR_FILENO2); |
908 | |
909 | (void)execvp(compr[method].argv[0], |
910 | RCAST(char *const *, RCAST(intptr_t, compr[method].argv))((char *const *)(uintptr_t)(((intptr_t)(uintptr_t)(compr[method ].argv))))); |
911 | dprintf(STDERR_FILENO2, "exec `%s' failed, %s", |
912 | compr[method].argv[0], strerror(errno(*__errno_location ()))); |
913 | _exit(1); /* _exit(), not exit(), because of vfork */ |
914 | } |
915 | /* parent */ |
916 | /* Close write sides of child stdout/err pipes */ |
917 | for (i = 1; i < __arraycount(fdp)(sizeof(fdp) / sizeof(fdp[0])); i++) |
918 | closefd(fdp[i], 1); |
919 | /* Write the buffer data to child stdin, if we don't have fd */ |
920 | if (fd == -1) { |
921 | closefd(fdp[STDIN_FILENO0], 0); |
922 | writepid = writechild(fdp[STDIN_FILENO0][1], old, *n); |
923 | closefd(fdp[STDIN_FILENO0], 1); |
924 | } |
925 | |
926 | *newch = CAST(unsigned char *, malloc(bytes_max + 1))((unsigned char *)(malloc(bytes_max + 1))); |
927 | if (*newch == NULL((void*)0)) { |
928 | rv = makeerror(newch, n, "No buffer, %s", |
929 | strerror(errno(*__errno_location ()))); |
930 | goto err; |
931 | } |
932 | rv = OKDATA0; |
933 | r = sread(fdp[STDOUT_FILENO1][0], *newch, bytes_max, 0); |
934 | if (r <= 0) { |
935 | DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], |
936 | r != -1 ? strerror(errno) : "no data"); |
937 | |
938 | rv = ERRDATA2; |
939 | if (r == 0 && |
940 | (r = sread(fdp[STDERR_FILENO2][0], *newch, bytes_max, 0)) > 0) |
941 | { |
942 | r = filter_error(*newch, r); |
943 | goto ok; |
944 | } |
945 | free(*newch); |
946 | if (r == 0) |
947 | rv = makeerror(newch, n, "Read failed, %s", |
948 | strerror(errno(*__errno_location ()))); |
949 | else |
950 | rv = makeerror(newch, n, "No data"); |
951 | goto err; |
952 | } |
953 | ok: |
954 | *n = r; |
955 | /* NUL terminate, as every buffer is handled here. */ |
956 | (*newch)[*n] = '\0'; |
957 | err: |
958 | closefd(fdp[STDIN_FILENO0], 1); |
959 | closefd(fdp[STDOUT_FILENO1], 0); |
960 | closefd(fdp[STDERR_FILENO2], 0); |
961 | |
962 | w = waitpid(pid, &status, 0); |
963 | wait_err: |
964 | if (w == -1) { |
965 | free(*newch); |
966 | rv = makeerror(newch, n, "Wait failed, %s", strerror(errno(*__errno_location ()))); |
967 | DPRINTF("Child wait return %#x\n", status); |
968 | } else if (!WIFEXITED(status)(((status) & 0x7f) == 0)) { |
969 | DPRINTF("Child not exited (%#x)\n", status); |
970 | } else if (WEXITSTATUS(status)(((status) & 0xff00) >> 8) != 0) { |
971 | DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status)); |
972 | } |
973 | if (writepid > 0) { |
974 | /* _After_ we know decompressor has exited, our input writer |
975 | * definitely will exit now (at worst, writing fails in it, |
976 | * since output fd is closed now on the reading size). |
977 | */ |
978 | w = waitpid(writepid, &status, 0); |
979 | writepid = -1; |
980 | goto wait_err; |
981 | } |
982 | |
983 | closefd(fdp[STDIN_FILENO0], 0); //why? it is already closed here! |
984 | DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv); |
985 | |
986 | return rv; |
987 | } |
988 | #endif |