Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2022 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | |
13 | | #include <stdio.h> |
14 | | #include <stddef.h> |
15 | | #include <stdint.h> |
16 | | #include <string.h> |
17 | | #include <assert.h> |
18 | | #include <stdlib.h> |
19 | | #include <inttypes.h> |
20 | | #include "zlib.h" |
21 | | |
22 | | static const uint8_t *data; |
23 | | static size_t dataLen; |
24 | | |
25 | | static void check_compress_level(uint8_t *compr, size_t comprLen, |
26 | | uint8_t *uncompr, size_t uncomprLen, |
27 | 0 | int level) { |
28 | 0 | compress2(compr, &comprLen, data, dataLen, level); |
29 | 0 | uncompress(uncompr, &uncomprLen, compr, comprLen); |
30 | | |
31 | | /* Make sure compress + uncompress gives back the input data. */ |
32 | 0 | assert(dataLen == uncomprLen); |
33 | 0 | assert(0 == memcmp(data, uncompr, dataLen)); |
34 | 0 | } |
35 | | |
36 | 0 | #define put_byte(s, i, c) {s[i] = (unsigned char)(c);} |
37 | | |
38 | 0 | static void write_zlib_header(uint8_t *s, unsigned compression_method, unsigned flags) { |
39 | 0 | unsigned int header = (Z_DEFLATED + ((flags)<<4)) << 8; |
40 | 0 | header |= (compression_method << 6); |
41 | |
|
42 | 0 | header += 31 - (header % 31); |
43 | | |
44 | | /* s is guaranteed to be longer than 2 bytes. */ |
45 | 0 | put_byte(s, 0, (unsigned char)(header >> 8)); |
46 | 0 | put_byte(s, 1, (unsigned char)(header & 0xff)); |
47 | 0 | } |
48 | | |
49 | 0 | static void check_decompress(uint8_t *compr, size_t comprLen, unsigned compression_method, unsigned flags) { |
50 | | /* We need to write a valid zlib header of size two bytes. Copy the input data |
51 | | in a larger buffer. Do not modify the input data to avoid libFuzzer error: |
52 | | fuzz target overwrites its const input. */ |
53 | 0 | size_t copyLen = dataLen + 2; |
54 | 0 | uint8_t *copy = (uint8_t *)malloc(copyLen); |
55 | 0 | memcpy(copy + 2, data, dataLen); |
56 | 0 | write_zlib_header(copy, compression_method, flags); |
57 | |
|
58 | 0 | uncompress(compr, &comprLen, copy, copyLen); |
59 | 0 | free(copy); |
60 | 0 | } |
61 | | |
62 | 0 | int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { |
63 | 0 | if (size < 10 || size > 1024 * 1024) |
64 | 0 | return 0; |
65 | | |
66 | 0 | const int level = d[0] % 10; |
67 | 0 | d++,size--; |
68 | | |
69 | | //https://web.archive.org/web/20200220015003/http://www.onicos.com/staff/iz/formats/gzip.html |
70 | 0 | unsigned compression_method = d[0] % 5; |
71 | 0 | if (compression_method == 4) //[4...7] are reserved |
72 | 0 | compression_method = 8; |
73 | 0 | d++,size--; |
74 | 0 | unsigned flags = d[0] & (2 << 4); |
75 | 0 | d++,size--; |
76 | |
|
77 | 0 | size_t comprLen = compressBound(size); |
78 | 0 | size_t uncomprLen = size; |
79 | 0 | uint8_t *compr = NULL, *uncompr = NULL; |
80 | |
|
81 | 0 | data = d; |
82 | 0 | dataLen = size; |
83 | 0 | compr = (uint8_t *)calloc(1, comprLen); |
84 | 0 | if (!compr) |
85 | 0 | goto err; |
86 | 0 | uncompr = (uint8_t *)calloc(1, uncomprLen); |
87 | 0 | if (!uncompr) |
88 | 0 | goto err; |
89 | | |
90 | 0 | check_compress_level(compr, comprLen, uncompr, uncomprLen, level); |
91 | 0 | check_decompress(compr, comprLen, compression_method, flags); |
92 | |
|
93 | 0 | err: |
94 | 0 | free(compr); |
95 | 0 | free(uncompr); |
96 | | |
97 | | /* This function must return 0. */ |
98 | 0 | return 0; |
99 | 0 | } |