1 /* infcover.c -- test zlib's inflate routines with full code coverage
2 * Copyright (C) 2011, 2016 Mark Adler
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6 /* to use, do: ./configure --cover && make cover */
7 // clang-format off
8 #include "infcover.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "zlib.h"
14
15 /* get definition of internal structure so we can mess with it (see pull()),
16 and so we can call inflate_trees() (see cover5()) */
17 #define ZLIB_INTERNAL
18 #include "inftrees.h"
19 #include "inflate.h"
20
21 /* XXX: use C++ streams instead of printf/fputs/etc due to portability
22 * as type sizes can vary between platforms.
23 */
24 #include <iostream>
25 #define local static
26
27 /* XXX: hacking C assert and plugging into GTest. */
28 #include "gtest.h"
29 #if defined(assert)
30 #undef assert
31 #define assert EXPECT_TRUE
32 #endif
33
34 /* XXX: handle what is a reserved word in C++. */
35 #define try try_f
36
37 /* -- memory tracking routines -- */
38
39 /*
40 These memory tracking routines are provided to zlib and track all of zlib's
41 allocations and deallocations, check for LIFO operations, keep a current
42 and high water mark of total bytes requested, optionally set a limit on the
43 total memory that can be allocated, and when done check for memory leaks.
44
45 They are used as follows:
46
47 z_stream strm;
48 mem_setup(&strm) initializes the memory tracking and sets the
49 zalloc, zfree, and opaque members of strm to use
50 memory tracking for all zlib operations on strm
51 mem_limit(&strm, limit) sets a limit on the total bytes requested -- a
52 request that exceeds this limit will result in an
53 allocation failure (returns NULL) -- setting the
54 limit to zero means no limit, which is the default
55 after mem_setup()
56 mem_used(&strm, "msg") prints to stderr "msg" and the total bytes used
57 mem_high(&strm, "msg") prints to stderr "msg" and the high water mark
58 mem_done(&strm, "msg") ends memory tracking, releases all allocations
59 for the tracking as well as leaked zlib blocks, if
60 any. If there was anything unusual, such as leaked
61 blocks, non-FIFO frees, or frees of addresses not
62 allocated, then "msg" and information about the
63 problem is printed to stderr. If everything is
64 normal, nothing is printed. mem_done resets the
65 strm members to Z_NULL to use the default memory
66 allocation routines on the next zlib initialization
67 using strm.
68 */
69
70 /* these items are strung together in a linked list, one for each allocation */
71 struct mem_item {
72 void *ptr; /* pointer to allocated memory */
73 size_t size; /* requested size of allocation */
74 struct mem_item *next; /* pointer to next item in list, or NULL */
75 };
76
77 /* this structure is at the root of the linked list, and tracks statistics */
78 struct mem_zone {
79 struct mem_item *first; /* pointer to first item in list, or NULL */
80 size_t total, highwater; /* total allocations, and largest total */
81 size_t limit; /* memory allocation limit, or 0 if no limit */
82 int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */
83 };
84
85 /* memory allocation routine to pass to zlib */
mem_alloc(void * mem,unsigned count,unsigned size)86 local void *mem_alloc(void *mem, unsigned count, unsigned size)
87 {
88 void *ptr;
89 struct mem_item *item;
90 struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
91 size_t len = count * (size_t)size;
92
93 /* induced allocation failure */
94 if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
95 return NULL;
96
97 /* perform allocation using the standard library, fill memory with a
98 non-zero value to make sure that the code isn't depending on zeros */
99 ptr = malloc(len);
100 if (ptr == NULL)
101 return NULL;
102 memset(ptr, 0xa5, len);
103
104 /* create a new item for the list */
105 item = static_cast<struct mem_item *>(malloc(sizeof(struct mem_item)));
106 if (item == NULL) {
107 free(ptr);
108 return NULL;
109 }
110 item->ptr = ptr;
111 item->size = len;
112
113 /* insert item at the beginning of the list */
114 item->next = zone->first;
115 zone->first = item;
116
117 /* update the statistics */
118 zone->total += item->size;
119 if (zone->total > zone->highwater)
120 zone->highwater = zone->total;
121
122 /* return the allocated memory */
123 return ptr;
124 }
125
126 /* memory free routine to pass to zlib */
mem_free(void * mem,void * ptr)127 local void mem_free(void *mem, void *ptr)
128 {
129 struct mem_item *item, *next;
130 struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
131
132 /* if no zone, just do a free */
133 if (zone == NULL) {
134 free(ptr);
135 return;
136 }
137
138 /* point next to the item that matches ptr, or NULL if not found -- remove
139 the item from the linked list if found */
140 next = zone->first;
141 if (next) {
142 if (next->ptr == ptr)
143 zone->first = next->next; /* first one is it, remove from list */
144 else {
145 do { /* search the linked list */
146 item = next;
147 next = item->next;
148 } while (next != NULL && next->ptr != ptr);
149 if (next) { /* if found, remove from linked list */
150 item->next = next->next;
151 zone->notlifo++; /* not a LIFO free */
152 }
153
154 }
155 }
156
157 /* if found, update the statistics and free the item */
158 if (next) {
159 zone->total -= next->size;
160 free(next);
161 }
162
163 /* if not found, update the rogue count */
164 else
165 zone->rogue++;
166
167 /* in any case, do the requested free with the standard library function */
168 free(ptr);
169 }
170
171 /* set up a controlled memory allocation space for monitoring, set the stream
172 parameters to the controlled routines, with opaque pointing to the space */
mem_setup(z_stream * strm)173 local void mem_setup(z_stream *strm)
174 {
175 struct mem_zone *zone;
176
177 zone = static_cast<struct mem_zone *>(malloc(sizeof(struct mem_zone)));
178 assert(zone != NULL);
179 zone->first = NULL;
180 zone->total = 0;
181 zone->highwater = 0;
182 zone->limit = 0;
183 zone->notlifo = 0;
184 zone->rogue = 0;
185 strm->opaque = zone;
186 strm->zalloc = mem_alloc;
187 strm->zfree = mem_free;
188 }
189
190 /* set a limit on the total memory allocation, or 0 to remove the limit */
mem_limit(z_stream * strm,size_t limit)191 local void mem_limit(z_stream *strm, size_t limit)
192 {
193 struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
194
195 zone->limit = limit;
196 }
197
198 /* show the current total requested allocations in bytes */
mem_used(z_stream * strm,const char * prefix)199 local void mem_used(z_stream *strm, const char *prefix)
200 {
201 struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
202
203 std::cout << prefix << ": " << zone->total << " allocated" << std::endl;
204 }
205
206 /* show the high water allocation in bytes */
mem_high(z_stream * strm,const char * prefix)207 local void mem_high(z_stream *strm, const char *prefix)
208 {
209 struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
210
211 std::cout << prefix << ": " << zone->highwater << " high water mark" << std::endl;
212 }
213
214 /* release the memory allocation zone -- if there are any surprises, notify */
mem_done(z_stream * strm,const char * prefix)215 local void mem_done(z_stream *strm, const char *prefix)
216 {
217 int count = 0;
218 struct mem_item *item, *next;
219 struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
220
221 /* show high water mark */
222 mem_high(strm, prefix);
223
224 /* free leftover allocations and item structures, if any */
225 item = zone->first;
226 while (item != NULL) {
227 free(item->ptr);
228 next = item->next;
229 free(item);
230 item = next;
231 count++;
232 }
233
234 /* issue alerts about anything unexpected */
235 if (count || zone->total)
236 std::cout << "** " << prefix << ": "
237 << zone->total << " bytes in "
238 << count << " blocks not freed"
239 << std::endl;
240
241 if (zone->notlifo)
242 std::cout << "** " << prefix << ": "
243 << zone->notlifo << " frees not LIFO"
244 << std::endl;
245
246 if (zone->rogue)
247 std::cout << "** " << prefix << ": "
248 << zone->rogue << " frees not recognized"
249 << std::endl;
250
251 /* free the zone and delete from the stream */
252 free(zone);
253 strm->opaque = Z_NULL;
254 strm->zalloc = Z_NULL;
255 strm->zfree = Z_NULL;
256 }
257
258 /* -- inflate test routines -- */
259
260 /* Decode a hexadecimal string, set *len to length, in[] to the bytes. This
261 decodes liberally, in that hex digits can be adjacent, in which case two in
262 a row writes a byte. Or they can be delimited by any non-hex character,
263 where the delimiters are ignored except when a single hex digit is followed
264 by a delimiter, where that single digit writes a byte. The returned data is
265 allocated and must eventually be freed. NULL is returned if out of memory.
266 If the length is not needed, then len can be NULL. */
h2b(const char * hex,unsigned * len)267 local unsigned char *h2b(const char *hex, unsigned *len)
268 {
269 unsigned char *in, *re;
270 unsigned next, val;
271
272 in = static_cast<unsigned char *>(malloc((strlen(hex) + 1) >> 1));
273 if (in == NULL)
274 return NULL;
275 next = 0;
276 val = 1;
277 do {
278 if (*hex >= '0' && *hex <= '9')
279 val = (val << 4) + *hex - '0';
280 else if (*hex >= 'A' && *hex <= 'F')
281 val = (val << 4) + *hex - 'A' + 10;
282 else if (*hex >= 'a' && *hex <= 'f')
283 val = (val << 4) + *hex - 'a' + 10;
284 else if (val != 1 && val < 32) /* one digit followed by delimiter */
285 val += 240; /* make it look like two digits */
286 if (val > 255) { /* have two digits */
287 in[next++] = val & 0xff; /* save the decoded byte */
288 val = 1; /* start over */
289 }
290 } while (*hex++); /* go through the loop with the terminating null */
291 if (len != NULL)
292 *len = next;
293 re = static_cast<unsigned char *>(realloc(in, next));
294 return re == NULL ? in : re;
295 }
296
297 /* generic inflate() run, where hex is the hexadecimal input data, what is the
298 text to include in an error message, step is how much input data to feed
299 inflate() on each call, or zero to feed it all, win is the window bits
300 parameter to inflateInit2(), len is the size of the output buffer, and err
301 is the error code expected from the first inflate() call (the second
302 inflate() call is expected to return Z_STREAM_END). If win is 47, then
303 header information is collected with inflateGetHeader(). If a zlib stream
304 is looking for a dictionary, then an empty dictionary is provided.
305 inflate() is run until all of the input data is consumed. */
inf(const char * hex,const char * what,unsigned step,int win,unsigned len,int err)306 local void inf(const char *hex, const char *what, unsigned step, int win, unsigned len,
307 int err)
308 {
309 int ret;
310 unsigned have;
311 unsigned char *in, *out;
312 z_stream strm, copy;
313 gz_header head;
314
315 mem_setup(&strm);
316 strm.avail_in = 0;
317 strm.next_in = Z_NULL;
318 ret = inflateInit2(&strm, win);
319 if (ret != Z_OK) {
320 mem_done(&strm, what);
321 return;
322 }
323 out = static_cast<unsigned char *>(malloc(len)); assert(out != NULL);
324 if (win == 47) {
325 head.extra = out;
326 head.extra_max = len;
327 head.name = out;
328 head.name_max = len;
329 head.comment = out;
330 head.comm_max = len;
331 ret = inflateGetHeader(&strm, &head); assert(ret == Z_OK);
332 }
333 in = h2b(hex, &have); assert(in != NULL);
334 if (step == 0 || step > have)
335 step = have;
336 strm.avail_in = step;
337 have -= step;
338 strm.next_in = in;
339 do {
340 strm.avail_out = len;
341 strm.next_out = out;
342 ret = inflate(&strm, Z_NO_FLUSH); assert(err == 9 || ret == err);
343 if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
344 break;
345 if (ret == Z_NEED_DICT) {
346 ret = inflateSetDictionary(&strm, in, 1);
347 assert(ret == Z_DATA_ERROR);
348 mem_limit(&strm, 1);
349 ret = inflateSetDictionary(&strm, out, 0);
350 assert(ret == Z_MEM_ERROR);
351 mem_limit(&strm, 0);
352 ((struct inflate_state *)strm.state)->mode = DICT;
353 ret = inflateSetDictionary(&strm, out, 0);
354 assert(ret == Z_OK);
355 ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_BUF_ERROR);
356 }
357 ret = inflateCopy(©, &strm); assert(ret == Z_OK);
358 ret = inflateEnd(©); assert(ret == Z_OK);
359 err = 9; /* don't care next time around */
360 have += strm.avail_in;
361 strm.avail_in = step > have ? have : step;
362 have -= strm.avail_in;
363 } while (strm.avail_in);
364 free(in);
365 free(out);
366 ret = inflateReset2(&strm, -8); assert(ret == Z_OK);
367 ret = inflateEnd(&strm); assert(ret == Z_OK);
368 mem_done(&strm, what);
369 }
370
371 /* cover all of the lines in inflate.c up to inflate() */
cover_support(void)372 void cover_support(void)
373 {
374 int ret;
375 z_stream strm;
376
377 mem_setup(&strm);
378 strm.avail_in = 0;
379 strm.next_in = Z_NULL;
380 ret = inflateInit(&strm); assert(ret == Z_OK);
381 mem_used(&strm, "inflate init");
382 ret = inflatePrime(&strm, 5, 31); assert(ret == Z_OK);
383 ret = inflatePrime(&strm, -1, 0); assert(ret == Z_OK);
384 ret = inflateSetDictionary(&strm, Z_NULL, 0);
385 assert(ret == Z_STREAM_ERROR);
386 ret = inflateEnd(&strm); assert(ret == Z_OK);
387 mem_done(&strm, "prime");
388
389 inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
390 inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
391 inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
392 inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
393 inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
394
395 mem_setup(&strm);
396 strm.avail_in = 0;
397 strm.next_in = Z_NULL;
398 ret = inflateInit_(&strm, "!", (int)sizeof(z_stream));
399 assert(ret == Z_VERSION_ERROR);
400 mem_done(&strm, "wrong version");
401
402 strm.avail_in = 0;
403 strm.next_in = Z_NULL;
404 ret = inflateInit(&strm); assert(ret == Z_OK);
405 ret = inflateEnd(&strm); assert(ret == Z_OK);
406 std::cout << "inflate built-in memory routines" << std::endl;;
407 }
408
409 /* cover all inflate() header and trailer cases and code after inflate() */
cover_wrap(void)410 void cover_wrap(void)
411 {
412 int ret;
413 z_stream strm, copy;
414 unsigned char dict[257];
415
416 ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR);
417 ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
418 ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR);
419 std::cout << "inflate bad parameters" << std::endl;
420
421 inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
422 inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
423 inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
424 inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
425 inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
426 inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
427 inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
428 Z_DATA_ERROR);
429 inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length",
430 0, 47, 0, Z_STREAM_END);
431 inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
432 inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
433 inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
434
435 mem_setup(&strm);
436 strm.avail_in = 0;
437 strm.next_in = Z_NULL;
438 ret = inflateInit2(&strm, -8);
439 strm.avail_in = 2;
440 strm.next_in = (Bytef *)"\x63";
441 strm.avail_out = 1;
442 strm.next_out = (Bytef *)&ret;
443 mem_limit(&strm, 1);
444 ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
445 ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
446 mem_limit(&strm, 0);
447 memset(dict, 0, 257);
448 ret = inflateSetDictionary(&strm, dict, 257);
449 assert(ret == Z_OK);
450 mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
451 ret = inflatePrime(&strm, 16, 0); assert(ret == Z_OK);
452 strm.avail_in = 2;
453 strm.next_in = (Bytef *)"\x80";
454 ret = inflateSync(&strm); assert(ret == Z_DATA_ERROR);
455 ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR);
456 strm.avail_in = 4;
457 strm.next_in = (Bytef *)"\0\0\xff\xff";
458 ret = inflateSync(&strm); assert(ret == Z_OK);
459 (void)inflateSyncPoint(&strm);
460 ret = inflateCopy(©, &strm); assert(ret == Z_MEM_ERROR);
461 mem_limit(&strm, 0);
462 ret = inflateUndermine(&strm, 1); assert(ret == Z_DATA_ERROR);
463 (void)inflateMark(&strm);
464 ret = inflateEnd(&strm); assert(ret == Z_OK);
465 mem_done(&strm, "miscellaneous, force memory errors");
466 }
467
468 /* input and output functions for inflateBack() */
pull(void * desc,unsigned char ** buf)469 local unsigned pull(void *desc, unsigned char **buf)
470 {
471 static unsigned int next = 0;
472 static unsigned char dat[] = {0x63, 0, 2, 0};
473 struct inflate_state *state;
474
475 if (desc == Z_NULL) {
476 next = 0;
477 return 0; /* no input (already provided at next_in) */
478 }
479 state = reinterpret_cast<struct inflate_state *>(((z_stream *)desc)->state);
480 if (state != Z_NULL)
481 state->mode = SYNC; /* force an otherwise impossible situation */
482 return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
483 }
484
push(void * desc,unsigned char * buf,unsigned len)485 local int push(void *desc, unsigned char *buf, unsigned len)
486 {
487 (void)buf;
488 (void)len;
489 return desc != Z_NULL; /* force error if desc not null */
490 }
491
492 /* cover inflateBack() up to common deflate data cases and after those */
cover_back(void)493 void cover_back(void)
494 {
495 int ret;
496 z_stream strm;
497 unsigned char win[32768];
498
499 ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
500 assert(ret == Z_VERSION_ERROR);
501 ret = inflateBackInit(Z_NULL, 0, win); assert(ret == Z_STREAM_ERROR);
502 ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
503 assert(ret == Z_STREAM_ERROR);
504 ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
505 std::cout << "inflateBack bad parameters" << std::endl;;
506
507 mem_setup(&strm);
508 ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
509 strm.avail_in = 2;
510 strm.next_in = (Bytef *)"\x03";
511 ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
512 assert(ret == Z_STREAM_END);
513 /* force output error */
514 strm.avail_in = 3;
515 strm.next_in = (Bytef *)"\x63\x00";
516 ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
517 assert(ret == Z_BUF_ERROR);
518 /* force mode error by mucking with state */
519 ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
520 assert(ret == Z_STREAM_ERROR);
521 ret = inflateBackEnd(&strm); assert(ret == Z_OK);
522 mem_done(&strm, "inflateBack bad state");
523
524 ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
525 ret = inflateBackEnd(&strm); assert(ret == Z_OK);
526 std::cout << "inflateBack built-in memory routines" << std::endl;;
527 }
528
529 /* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
530 local int try(const char *hex, const char *id, int err)
531 {
532 int ret;
533 unsigned len, size;
534 unsigned char *in, *out, *win;
535 char *prefix;
536 z_stream strm;
537
538 /* convert to hex */
539 in = h2b(hex, &len);
540 assert(in != NULL);
541
542 /* allocate work areas */
543 size = len << 3;
544 out = static_cast<unsigned char *>(malloc(size));
545 assert(out != NULL);
546 win = static_cast<unsigned char *>(malloc(32768));
547 assert(win != NULL);
548 prefix = static_cast<char *>(malloc(strlen(id) + 6));
549 assert(prefix != NULL);
550
551 /* first with inflate */
552 strcpy(prefix, id);
553 strcat(prefix, "-late");
554 mem_setup(&strm);
555 strm.avail_in = 0;
556 strm.next_in = Z_NULL;
557 ret = inflateInit2(&strm, err < 0 ? 47 : -15);
558 assert(ret == Z_OK);
559 strm.avail_in = len;
560 strm.next_in = in;
561 do {
562 strm.avail_out = size;
563 strm.next_out = out;
564 ret = inflate(&strm, Z_TREES);
565 assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
566 if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
567 break;
568 } while (strm.avail_in || strm.avail_out == 0);
569 if (err) {
570 assert(ret == Z_DATA_ERROR);
571 assert(strcmp(id, strm.msg) == 0);
572 }
573 inflateEnd(&strm);
574 mem_done(&strm, prefix);
575
576 /* then with inflateBack */
577 if (err >= 0) {
578 strcpy(prefix, id);
579 strcat(prefix, "-back");
580 mem_setup(&strm);
581 ret = inflateBackInit(&strm, 15, win);
582 assert(ret == Z_OK);
583 strm.avail_in = len;
584 strm.next_in = in;
585 ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
586 assert(ret != Z_STREAM_ERROR);
587 if (err) {
588 assert(ret == Z_DATA_ERROR);
589 assert(strcmp(id, strm.msg) == 0);
590 }
591 inflateBackEnd(&strm);
592 mem_done(&strm, prefix);
593 }
594
595 /* clean up */
596 free(prefix);
597 free(win);
598 free(out);
599 free(in);
600 return ret;
601 }
602
603 /* cover deflate data cases in both inflate() and inflateBack() */
cover_inflate(void)604 void cover_inflate(void)
605 {
606 try("0 0 0 0 0", "invalid stored block lengths", 1);
607 try("3 0", "fixed", 0);
608 try("6", "invalid block type", 1);
609 try("1 1 0 fe ff 0", "stored", 0);
610 try("fc 0 0", "too many length or distance symbols", 1);
611 try("4 0 fe ff", "invalid code lengths set", 1);
612 try("4 0 24 49 0", "invalid bit length repeat", 1);
613 try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
614 try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
615 try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
616 "invalid literal/lengths set", 1);
617 try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
618 try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
619 try("2 7e ff ff", "invalid distance code", 1);
620 try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
621
622 /* also trailer mismatch just in inflate() */
623 try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
624 try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
625 "incorrect length check", -1);
626 try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
627 try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
628 "long code", 0);
629 try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
630 try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c",
631 "long distance and extra", 0);
632 try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
633 "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
634 inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
635 Z_STREAM_END);
636 inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
637 }
638
639 /* XXX(cavalcantii): fix linking error due inflate_table. */
640 /* cover remaining lines in inftrees.c */
641 /* void cover_trees(void) */
642 /* { */
643 /* int ret; */
644 /* unsigned bits; */
645 /* unsigned short lens[16], work[16]; */
646 /* code *next, table[ENOUGH_DISTS]; */
647
648 /* /\* we need to call inflate_table() directly in order to manifest not- */
649 /* enough errors, since zlib insures that enough is always enough *\/ */
650 /* for (bits = 0; bits < 15; bits++) */
651 /* lens[bits] = (unsigned short)(bits + 1); */
652 /* lens[15] = 15; */
653 /* next = table; */
654 /* bits = 15; */
655 /* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
656 /* assert(ret == 1); */
657 /* next = table; */
658 /* bits = 1; */
659 /* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
660 /* assert(ret == 1); */
661 /* fputs("inflate_table not enough errors\n", stderr); */
662 /* } */
663
664 /* cover remaining inffast.c decoding and window copying */
cover_fast(void)665 void cover_fast(void)
666 {
667 inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
668 " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
669 inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
670 " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
671 Z_DATA_ERROR);
672 inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
673 Z_DATA_ERROR);
674 inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
675 Z_DATA_ERROR);
676 inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0",
677 "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
678 inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
679 inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
680 "contiguous and wrap around window", 6, -8, 259, Z_OK);
681 inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
682 Z_STREAM_END);
683 }
684
685 /* Adapted from Evgeny Legerov PoC (https://github.com/ivd38/zlib_overflow)
686 * this test case crashes in ASAN builds with the correct payload.
687 */
inf_cve_2022_37434(char * hex,char * what,unsigned step,int win,unsigned len,int err)688 local void inf_cve_2022_37434(char *hex, char *what, unsigned step, int win, unsigned len,
689 int err)
690 {
691 int ret;
692 unsigned have;
693 unsigned char *in, *out;
694 z_stream strm, copy;
695 gz_header head;
696
697 mem_setup(&strm);
698 strm.avail_in = 0;
699 strm.next_in = Z_NULL;
700 ret = inflateInit2(&strm, win);
701 if (ret != Z_OK) {
702 mem_done(&strm, what);
703 return;
704 }
705 out = static_cast<unsigned char *>(malloc(len)); assert(out != NULL);
706 if (win == 47) {
707 head.extra = out;
708 head.extra_max = len;
709 head.name = out;
710 head.name_max = len;
711 head.comment = out;
712 head.comm_max = len;
713 ret = inflateGetHeader(&strm, &head); assert(ret == Z_OK);
714 }
715 in = h2b(hex, &have); assert(in != NULL);
716 if (step == 0 || step > have)
717 step = have;
718 strm.avail_in = step;
719 have -= step;
720 strm.next_in = in;
721 do {
722 strm.avail_out = len;
723 strm.next_out = out;
724 ret = inflate(&strm, Z_NO_FLUSH);
725 if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
726 break;
727 have += strm.avail_in;
728 strm.avail_in = step > have ? have : step;
729 have -= strm.avail_in;
730 } while (strm.avail_in);
731 free(in);
732 free(out);
733 ret = inflateReset2(&strm, -8);
734 ret = inflateEnd(&strm);
735 mem_done(&strm, what);
736 }
737
cover_CVE_2022_37434(void)738 void cover_CVE_2022_37434(void)
739 {
740 char payload[] = "1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51";
741 char cve[] = "wtf";
742 inf_cve_2022_37434(payload, cve, 13, 47, 12, Z_OK);
743 }
744
745 // clang-format on
746