/src/libtiff/contrib/oss-fuzz/tiff_read_rgba_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 1988-1997 Sam Leffler |
2 | | * Copyright (c) 1991-1997 Silicon Graphics, Inc. |
3 | | * |
4 | | * Permission to use, copy, modify, distribute, and sell this software and |
5 | | * its documentation for any purpose is hereby granted without fee, provided |
6 | | * that (i) the above copyright notices and this permission notice appear in |
7 | | * all copies of the software and related documentation, and (ii) the names of |
8 | | * Sam Leffler and Silicon Graphics may not be used in any advertising or |
9 | | * publicity relating to the software without the specific, prior written |
10 | | * permission of Sam Leffler and Silicon Graphics. |
11 | | * |
12 | | * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
13 | | * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
14 | | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
15 | | * |
16 | | * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR |
17 | | * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
18 | | * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
19 | | * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
20 | | * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
21 | | * OF THIS SOFTWARE. |
22 | | */ |
23 | | |
24 | | #include <cstdint> |
25 | | #include <cstdlib> |
26 | | #include <cstring> |
27 | | #include <sstream> |
28 | | #include <tiffio.h> |
29 | | #include <tiffio.hxx> |
30 | | |
31 | | /* stolen from tiffiop.h, which is a private header so we can't just include it |
32 | | */ |
33 | | /* safe multiply returns either the multiplied value or 0 if it overflowed */ |
34 | | #define __TIFFSafeMultiply(t, v, m) \ |
35 | 15.2k | ((((t)(m) != (t)0) && (((t)(((v) * (m)) / (m))) == (t)(v))) \ |
36 | 15.2k | ? (t)((v) * (m)) \ |
37 | 15.2k | : (t)0) |
38 | | |
39 | | const uint64_t MAX_SIZE = 500000000; |
40 | | |
41 | | extern "C" void handle_error(const char *unused, const char *unused2, |
42 | | va_list unused3) |
43 | 2.76M | { |
44 | 2.76M | return; |
45 | 2.76M | } |
46 | | |
47 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) |
48 | 8.02k | { |
49 | 8.02k | #ifndef STANDALONE |
50 | 8.02k | TIFFSetErrorHandler(handle_error); |
51 | 8.02k | TIFFSetWarningHandler(handle_error); |
52 | 8.02k | #endif |
53 | 8.02k | #if defined(__has_feature) |
54 | | #if __has_feature(memory_sanitizer) |
55 | | // libjpeg-turbo has issues with MSAN and SIMD code |
56 | | // See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=7547 |
57 | | // and https://github.com/libjpeg-turbo/libjpeg-turbo/pull/365 |
58 | | setenv("JSIMD_FORCENONE", "1", 1); |
59 | | #endif |
60 | 8.02k | #endif |
61 | 8.02k | std::istringstream s(std::string(Data, Data + Size)); |
62 | 8.02k | TIFF *tif = TIFFStreamOpen("MemTIFF", &s); |
63 | 8.02k | if (!tif) |
64 | 2.63k | { |
65 | 2.63k | return 0; |
66 | 2.63k | } |
67 | 5.38k | uint32_t w, h; |
68 | 5.38k | uint32_t *raster; |
69 | | |
70 | 5.38k | TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); |
71 | 5.38k | TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); |
72 | | /* don't continue if file size is ludicrous */ |
73 | 5.38k | if (TIFFTileSize64(tif) > MAX_SIZE) |
74 | 203 | { |
75 | 203 | TIFFClose(tif); |
76 | 203 | return 0; |
77 | 203 | } |
78 | 5.18k | uint64_t bufsize = TIFFTileSize64(tif); |
79 | | /* don't continue if the buffer size greater than the max allowed by the |
80 | | * fuzzer */ |
81 | 5.18k | if (bufsize > MAX_SIZE || bufsize == 0) |
82 | 114 | { |
83 | 114 | TIFFClose(tif); |
84 | 114 | return 0; |
85 | 114 | } |
86 | | |
87 | 5.07k | if (TIFFIsTiled(tif)) |
88 | 3.45k | { |
89 | | /* another hack to work around an OOM in tif_fax3.c */ |
90 | 3.45k | uint32_t tilewidth = 0; |
91 | 3.45k | uint32_t imagewidth = 0; |
92 | 3.45k | TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tilewidth); |
93 | 3.45k | TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imagewidth); |
94 | 3.45k | tilewidth = __TIFFSafeMultiply(uint32_t, tilewidth, 2); |
95 | 3.45k | imagewidth = __TIFFSafeMultiply(uint32_t, imagewidth, 2); |
96 | 3.45k | if (tilewidth * 2 > MAX_SIZE || imagewidth * 2 > MAX_SIZE || |
97 | 3.45k | tilewidth == 0 || imagewidth == 0) |
98 | 2 | { |
99 | 2 | TIFFClose(tif); |
100 | 2 | return 0; |
101 | 2 | } |
102 | 3.45k | } |
103 | 1.62k | else |
104 | 1.62k | { |
105 | | // check the size of the non-tiled image |
106 | 1.62k | uint32_t rowsize = 0; |
107 | 1.62k | TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsize); |
108 | 1.62k | uint32_t stripsize = TIFFStripSize(tif); |
109 | 1.62k | rowsize = __TIFFSafeMultiply(uint32_t, rowsize, 2); |
110 | 1.62k | stripsize = __TIFFSafeMultiply(uint32_t, stripsize, 2); |
111 | 1.62k | if (rowsize * 2 > MAX_SIZE || stripsize * 2 > MAX_SIZE || |
112 | 1.62k | rowsize == 0 || stripsize == 0) |
113 | 5 | { |
114 | 5 | TIFFClose(tif); |
115 | 5 | return 0; |
116 | 5 | } |
117 | 1.62k | } |
118 | | |
119 | 5.06k | uint32_t size = __TIFFSafeMultiply(uint32_t, w, h); |
120 | | |
121 | 5.06k | if (size > MAX_SIZE || size == 0) |
122 | 5 | { |
123 | 5 | TIFFClose(tif); |
124 | 5 | return 0; |
125 | 5 | } |
126 | | |
127 | 5.06k | raster = (uint32_t *)_TIFFmalloc(size * sizeof(uint32_t)); |
128 | 5.06k | int ret = 0; |
129 | 5.06k | if (raster != NULL) |
130 | 5.06k | { |
131 | 5.06k | TIFFReadRGBAImage(tif, w, h, raster, 0); |
132 | | |
133 | 5.06k | if (!TIFFIsTiled(tif)) |
134 | 1.61k | { |
135 | | // Allocate a buffer to hold one scanline |
136 | 1.61k | tsize_t scanlineSize = TIFFScanlineSize(tif); |
137 | 1.61k | void *buffer = _TIFFmalloc(scanlineSize); |
138 | 1.61k | if (!buffer) |
139 | 0 | { |
140 | 0 | fprintf(stderr, "Memory allocation failed\n"); |
141 | 0 | ret = 1; |
142 | 0 | goto cleanup; |
143 | 0 | } |
144 | | |
145 | | // Read each scanline |
146 | 245k | for (uint32_t row = 0; row < h; row++) |
147 | 245k | { |
148 | 245k | if (TIFFReadScanline(tif, buffer, row, 0) < 0) |
149 | 1.23k | { |
150 | 1.23k | _TIFFfree(buffer); |
151 | 1.23k | ret = 1; |
152 | 1.23k | goto cleanup; |
153 | 1.23k | } |
154 | 245k | } |
155 | 374 | _TIFFfree(buffer); |
156 | 374 | } |
157 | 5.06k | cleanup: |
158 | 5.06k | _TIFFfree(raster); |
159 | 5.06k | } |
160 | 5.06k | TIFFClose(tif); |
161 | | |
162 | 5.06k | return ret; |
163 | 5.06k | } |
164 | | |
165 | | #ifdef STANDALONE |
166 | | |
167 | | template <class T> static void CPL_IGNORE_RET_VAL(T) {} |
168 | | |
169 | | static void Usage(int, char *argv[]) |
170 | | { |
171 | | fprintf(stderr, "%s [--help] [-repeat N] filename.\n", argv[0]); |
172 | | exit(1); |
173 | | } |
174 | | |
175 | | int main(int argc, char *argv[]) |
176 | | { |
177 | | int nRet = 0; |
178 | | void *buf = NULL; |
179 | | int nLen = 0; |
180 | | int nLoops = 1; |
181 | | const char *pszFilename = NULL; |
182 | | |
183 | | for (int i = 1; i < argc; i++) |
184 | | { |
185 | | if (i + 1 < argc && strcmp(argv[i], "-repeat") == 0) |
186 | | { |
187 | | nLoops = atoi(argv[i + 1]); |
188 | | i++; |
189 | | } |
190 | | else if (strcmp(argv[i], "-dummy") == 0) |
191 | | { |
192 | | uint8_t dummy = ' '; |
193 | | return LLVMFuzzerTestOneInput(&dummy, 1); |
194 | | } |
195 | | else if (strcmp(argv[i], "--help") == 0) |
196 | | { |
197 | | Usage(argc, argv); |
198 | | } |
199 | | else if (argv[i][0] == '-') |
200 | | { |
201 | | fprintf(stderr, "Unrecognized option: %s", argv[i]); |
202 | | Usage(argc, argv); |
203 | | } |
204 | | else |
205 | | { |
206 | | pszFilename = argv[i]; |
207 | | } |
208 | | } |
209 | | if (pszFilename == nullptr) |
210 | | { |
211 | | fprintf(stderr, "No filename specified\n"); |
212 | | Usage(argc, argv); |
213 | | } |
214 | | FILE *f = fopen(pszFilename, "rb"); |
215 | | if (!f) |
216 | | { |
217 | | fprintf(stderr, "%s does not exist.\n", pszFilename); |
218 | | exit(1); |
219 | | } |
220 | | fseek(f, 0, SEEK_END); |
221 | | nLen = (int)ftell(f); |
222 | | fseek(f, 0, SEEK_SET); |
223 | | buf = malloc(nLen); |
224 | | if (!buf) |
225 | | { |
226 | | fprintf(stderr, "malloc failed.\n"); |
227 | | fclose(f); |
228 | | exit(1); |
229 | | } |
230 | | CPL_IGNORE_RET_VAL(fread(buf, nLen, 1, f)); |
231 | | fclose(f); |
232 | | for (int i = 0; i < nLoops; i++) |
233 | | { |
234 | | nRet = LLVMFuzzerTestOneInput(static_cast<const uint8_t *>(buf), nLen); |
235 | | if (nRet != 0) |
236 | | break; |
237 | | } |
238 | | free(buf); |
239 | | return nRet; |
240 | | } |
241 | | |
242 | | #endif |