Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Fuzzer
5 : * Author: Even Rouault, even.rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include <stddef.h>
30 : #include <stdint.h>
31 :
32 : #include <algorithm>
33 : #include <vector>
34 :
35 : #include "gdal.h"
36 : #include "cpl_conv.h"
37 : #include "cpl_string.h"
38 : #include "cpl_vsi.h"
39 : #include "gdal_alg.h"
40 : #include "gdal_priv.h"
41 : #include "gdal_frmts.h"
42 :
43 : #ifndef REGISTER_FUNC
44 : #define REGISTER_FUNC GDALAllRegister
45 : #endif
46 :
47 : #ifndef GDAL_SKIP
48 : #define GDAL_SKIP "CAD"
49 : #endif
50 :
51 : #ifndef EXTENSION
52 : #define EXTENSION "bin"
53 : #endif
54 :
55 : #ifndef MEM_FILENAME
56 : #define MEM_FILENAME "/vsimem/test"
57 : #endif
58 :
59 : #ifndef GDAL_FILENAME
60 : #define GDAL_FILENAME MEM_FILENAME
61 : #endif
62 :
63 : extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv);
64 : extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len);
65 :
66 0 : int LLVMFuzzerInitialize(int * /*argc*/, char ***argv)
67 : {
68 0 : const char *exe_path = (*argv)[0];
69 0 : if (CPLGetConfigOption("GDAL_DATA", nullptr) == nullptr)
70 : {
71 0 : CPLSetConfigOption("GDAL_DATA", CPLGetPathSafe(exe_path).c_str());
72 : }
73 0 : CPLSetConfigOption("CPL_TMPDIR", "/tmp");
74 0 : CPLSetConfigOption("DISABLE_OPEN_REAL_NETCDF_FILES", "YES");
75 : // Disable PDF text rendering as fontconfig cannot access its config files
76 0 : CPLSetConfigOption("GDAL_PDF_RENDERING_OPTIONS", "RASTER,VECTOR");
77 : // to avoid timeout in WMS driver
78 0 : CPLSetConfigOption("GDAL_HTTP_TIMEOUT", "1");
79 0 : CPLSetConfigOption("GDAL_HTTP_CONNECTTIMEOUT", "1");
80 0 : CPLSetConfigOption("GDAL_CACHEMAX", "1000"); // Limit to 1 GB
81 : #ifdef GTIFF_USE_MMAP
82 : CPLSetConfigOption("GTIFF_USE_MMAP", "YES");
83 : #endif
84 :
85 : #ifdef GDAL_SKIP
86 0 : CPLSetConfigOption("GDAL_SKIP", GDAL_SKIP);
87 : #endif
88 0 : REGISTER_FUNC();
89 :
90 0 : return 0;
91 : }
92 :
93 0 : static void ExploreAttributes(const GDALIHasAttribute *attributeHolder)
94 : {
95 0 : const auto attributes = attributeHolder->GetAttributes();
96 0 : for (const auto &attribute : attributes)
97 : {
98 0 : attribute->ReadAsRaw();
99 : }
100 :
101 0 : attributeHolder->GetAttribute("i_do_not_exist");
102 0 : }
103 :
104 0 : static void ExploreArray(const std::shared_ptr<GDALMDArray> &poArray,
105 : const char *pszDriverName)
106 : {
107 0 : ExploreAttributes(poArray.get());
108 :
109 0 : poArray->GetFilename();
110 0 : poArray->GetStructuralInfo();
111 0 : poArray->GetUnit();
112 0 : poArray->GetSpatialRef();
113 0 : poArray->GetRawNoDataValue();
114 0 : poArray->GetOffset();
115 0 : poArray->GetScale();
116 0 : poArray->GetCoordinateVariables();
117 :
118 0 : const auto nDimCount = poArray->GetDimensionCount();
119 0 : bool bRead = true;
120 0 : constexpr size_t MAX_ALLOC = 1000 * 1000 * 1000U;
121 0 : if (pszDriverName && EQUAL(pszDriverName, "GRIB"))
122 : {
123 0 : const auto &poDims = poArray->GetDimensions();
124 0 : if (nDimCount >= 2 &&
125 0 : poDims[nDimCount - 2]->GetSize() >
126 0 : MAX_ALLOC / sizeof(double) / poDims[nDimCount - 1]->GetSize())
127 : {
128 0 : bRead = false;
129 0 : }
130 : }
131 : else
132 : {
133 0 : const auto anBlockSize = poArray->GetBlockSize();
134 0 : size_t nBlockSize = poArray->GetDataType().GetSize();
135 0 : for (const auto nDimBlockSize : anBlockSize)
136 : {
137 0 : if (nDimBlockSize == 0)
138 : {
139 0 : break;
140 : }
141 0 : if (nBlockSize > MAX_ALLOC / nDimBlockSize)
142 : {
143 0 : bRead = false;
144 0 : break;
145 : }
146 0 : nBlockSize *= static_cast<size_t>(nDimBlockSize);
147 : }
148 : }
149 :
150 0 : if (bRead && poArray->GetDataType().GetClass() == GEDTC_NUMERIC)
151 : {
152 0 : std::vector<GUInt64> anArrayStartIdx(nDimCount);
153 0 : std::vector<size_t> anCount(nDimCount, 1);
154 0 : std::vector<GInt64> anArrayStep(nDimCount);
155 0 : std::vector<GPtrDiff_t> anBufferStride(nDimCount);
156 0 : std::vector<GByte> abyData(poArray->GetDataType().GetSize());
157 0 : poArray->Read(anArrayStartIdx.data(), anCount.data(),
158 0 : anArrayStep.data(), anBufferStride.data(),
159 0 : poArray->GetDataType(), &abyData[0]);
160 : }
161 0 : }
162 :
163 0 : static void ExploreGroup(const std::shared_ptr<GDALGroup> &poGroup,
164 : const char *pszDriverName)
165 : {
166 0 : ExploreAttributes(poGroup.get());
167 :
168 0 : const auto groupNames = poGroup->GetGroupNames();
169 0 : poGroup->OpenGroup("i_do_not_exist");
170 0 : for (const auto &name : groupNames)
171 : {
172 0 : auto poSubGroup = poGroup->OpenGroup(name);
173 0 : if (poSubGroup)
174 0 : ExploreGroup(poSubGroup, pszDriverName);
175 : }
176 :
177 0 : const auto arrayNames = poGroup->GetMDArrayNames();
178 0 : poGroup->OpenMDArray("i_do_not_exist");
179 0 : for (const auto &name : arrayNames)
180 : {
181 0 : auto poArray = poGroup->OpenMDArray(name);
182 0 : if (poArray)
183 : {
184 0 : ExploreArray(poArray, pszDriverName);
185 : }
186 : }
187 0 : }
188 :
189 1 : int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
190 : {
191 : #ifdef USE_FILESYSTEM
192 : char szTempFilename[64];
193 : snprintf(szTempFilename, sizeof(szTempFilename), "/tmp/gdal_fuzzer_%d.%s",
194 : (int)getpid(), EXTENSION);
195 : VSILFILE *fp = VSIFOpenL(szTempFilename, "wb");
196 : if (!fp)
197 : {
198 : fprintf(stderr, "Cannot create %s\n", szTempFilename);
199 : return 1;
200 : }
201 : VSIFWriteL(buf, 1, len, fp);
202 : #else
203 1 : VSILFILE *fp = VSIFileFromMemBuffer(
204 : MEM_FILENAME, reinterpret_cast<GByte *>(const_cast<uint8_t *>(buf)),
205 : len, FALSE);
206 : #endif
207 1 : VSIFCloseL(fp);
208 :
209 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
210 : #ifdef USE_FILESYSTEM
211 : const char *pszGDALFilename = szTempFilename;
212 : #else
213 1 : const char *pszGDALFilename = GDAL_FILENAME;
214 : #endif
215 :
216 : #ifdef DRIVER_NAME
217 : const char *const apszAllowedDrivers[] = {DRIVER_NAME, nullptr};
218 : #else
219 1 : const char *const *apszAllowedDrivers = nullptr;
220 : #endif
221 :
222 1 : GDALDatasetH hDS = GDALOpenEx(pszGDALFilename, GDAL_OF_RASTER,
223 : apszAllowedDrivers, nullptr, nullptr);
224 1 : if (hDS)
225 : {
226 0 : const int nTotalBands = GDALGetRasterCount(hDS);
227 0 : const int nBands = std::min(10, nTotalBands);
228 0 : bool bDoCheckSum = true;
229 0 : int nXSizeToRead = std::min(1024, GDALGetRasterXSize(hDS));
230 0 : int nYSizeToRead = std::min(1024, GDALGetRasterYSize(hDS));
231 0 : if (nBands > 0)
232 : {
233 : const char *pszInterleave =
234 0 : GDALGetMetadataItem(hDS, "INTERLEAVE", "IMAGE_STRUCTURE");
235 0 : int nSimultaneousBands =
236 0 : (pszInterleave && EQUAL(pszInterleave, "PIXEL")) ? nTotalBands
237 : : 1;
238 :
239 : // When using the RGBA interface in pixel-interleaved mode, take
240 : // into account the raw number of bands to compute memory
241 : // requirements
242 0 : if (nBands == 4 && nSimultaneousBands != 1 &&
243 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
244 : {
245 0 : GDALDatasetH hRawDS = GDALOpen(
246 0 : (CPLString("GTIFF_RAW:") + pszGDALFilename).c_str(),
247 : GA_ReadOnly);
248 0 : if (hRawDS)
249 : {
250 0 : nSimultaneousBands = GDALGetRasterCount(hRawDS);
251 : // shouldn't happen, but will make Coverity Scan happy
252 0 : if (nSimultaneousBands == 0)
253 0 : nSimultaneousBands = 1;
254 0 : GDALClose(hRawDS);
255 : }
256 : }
257 :
258 : // If we know that we will need to allocate a lot of memory
259 : // given the block size and interleaving mode, do not read
260 : // pixels to avoid out of memory conditions by ASAN
261 0 : GIntBig nPixels = 0;
262 0 : for (int i = 0; i < nBands; i++)
263 : {
264 0 : int nBXSize = 0, nBYSize = 0;
265 0 : GDALGetBlockSize(GDALGetRasterBand(hDS, i + 1), &nBXSize,
266 : &nBYSize);
267 0 : if (nBXSize == 0 || nBYSize == 0 || nBXSize > INT_MAX / nBYSize)
268 : {
269 0 : bDoCheckSum = false;
270 0 : break;
271 : }
272 :
273 : // Limit to 1000 blocks read for each band.
274 0 : while ((nXSizeToRead > 1 || nYSizeToRead > 1) &&
275 0 : (DIV_ROUND_UP(nXSizeToRead, nBXSize) *
276 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize) >
277 : 1000))
278 : {
279 0 : if (nXSizeToRead > 1 &&
280 0 : DIV_ROUND_UP(nXSizeToRead, nBXSize) >
281 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize))
282 0 : nXSizeToRead /= 2;
283 0 : else if (nYSizeToRead > 1)
284 0 : nYSizeToRead /= 2;
285 : else
286 0 : nXSizeToRead /= 2;
287 : }
288 :
289 : // Currently decoding of PIXARLOG compressed TIFF requires
290 : // a temporary buffer for the whole strip (if stripped) or
291 : // image (if tiled), so be careful for a
292 : // GTiffSplitBand
293 : // Could probably be fixed for the CHUNKY_STRIP_READ_SUPPORT
294 : // mode.
295 : // Workaround
296 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2606
297 : const char *pszCompress =
298 0 : GDALGetMetadataItem(hDS, "COMPRESSION", "IMAGE_STRUCTURE");
299 0 : if (pszCompress != nullptr &&
300 0 : ((nBYSize == 1 && GDALGetRasterYSize(hDS) > 1 &&
301 0 : GDALGetMetadataItem(GDALGetRasterBand(hDS, 1),
302 : "BLOCK_OFFSET_0_1",
303 0 : "TIFF") == nullptr) ||
304 0 : nBXSize != GDALGetRasterXSize(hDS)) &&
305 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
306 : {
307 0 : if (EQUAL(pszCompress, "PIXARLOG") &&
308 0 : GDALGetRasterYSize(hDS) >
309 0 : (INT_MAX / 2) / static_cast<int>(sizeof(GUInt16)) /
310 0 : nSimultaneousBands / GDALGetRasterXSize(hDS))
311 : {
312 0 : bDoCheckSum = false;
313 : }
314 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2874
315 0 : else if (EQUAL(pszCompress, "SGILOG24") &&
316 0 : GDALGetRasterYSize(hDS) >
317 : (INT_MAX / 2) /
318 0 : static_cast<int>(sizeof(GUInt32)) /
319 0 : nSimultaneousBands /
320 0 : GDALGetRasterXSize(hDS))
321 : {
322 0 : bDoCheckSum = false;
323 : }
324 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=38051
325 0 : else if (STARTS_WITH_CI(pszCompress, "LERC") &&
326 0 : (GDALGetRasterYSize(hDS) >
327 0 : (INT_MAX / 2) / nSimultaneousBands /
328 0 : GDALGetRasterXSize(hDS) ||
329 0 : static_cast<int64_t>(GDALGetRasterYSize(hDS)) *
330 0 : nSimultaneousBands *
331 0 : GDALGetRasterXSize(hDS) * 4 / 3 +
332 : 100 >
333 : (INT_MAX / 2)))
334 : {
335 0 : bDoCheckSum = false;
336 : }
337 : }
338 :
339 0 : GIntBig nNewPixels = static_cast<GIntBig>(nBXSize) * nBYSize;
340 0 : nNewPixels *= DIV_ROUND_UP(nXSizeToRead, nBXSize);
341 0 : nNewPixels *= DIV_ROUND_UP(nYSizeToRead, nBYSize);
342 0 : if (nNewPixels > nPixels)
343 0 : nPixels = nNewPixels;
344 : }
345 0 : if (bDoCheckSum)
346 : {
347 : const GDALDataType eDT =
348 0 : GDALGetRasterDataType(GDALGetRasterBand(hDS, 1));
349 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
350 0 : if (nPixels > 10 * 1024 * 1024 / nDTSize / nSimultaneousBands)
351 : {
352 0 : bDoCheckSum = false;
353 : }
354 : }
355 : }
356 0 : if (bDoCheckSum)
357 : {
358 0 : for (int i = 0; i < nBands; i++)
359 : {
360 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, i + 1);
361 0 : CPLDebug("FUZZER", "Checksum band %d: %d,%d,%d,%d", i + 1, 0, 0,
362 : nXSizeToRead, nYSizeToRead);
363 0 : GDALChecksumImage(hBand, 0, 0, nXSizeToRead, nYSizeToRead);
364 : }
365 : }
366 :
367 : // Test other API
368 0 : GDALGetProjectionRef(hDS);
369 : double adfGeoTransform[6];
370 0 : GDALGetGeoTransform(hDS, adfGeoTransform);
371 0 : CSLDestroy(GDALGetFileList(hDS));
372 0 : GDALGetGCPCount(hDS);
373 0 : GDALGetGCPs(hDS);
374 0 : GDALGetGCPProjection(hDS);
375 0 : GDALGetMetadata(hDS, nullptr);
376 0 : GDALGetMetadataItem(hDS, "foo", nullptr);
377 0 : CSLDestroy(GDALGetFileList(hDS));
378 0 : if (nBands > 0)
379 : {
380 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, 1);
381 :
382 0 : int bFound = FALSE;
383 0 : GDALGetRasterNoDataValue(hBand, &bFound);
384 0 : GDALGetRasterOffset(hBand, &bFound);
385 0 : GDALGetRasterScale(hBand, &bFound);
386 0 : GDALGetRasterUnitType(hBand);
387 0 : GDALGetMetadata(hBand, nullptr);
388 0 : GDALGetMetadataItem(hBand, "foo", nullptr);
389 :
390 0 : int nFlags = GDALGetMaskFlags(hBand);
391 0 : GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand);
392 0 : GDALGetRasterBandXSize(hMaskBand);
393 0 : if (bDoCheckSum && nFlags == GMF_PER_DATASET)
394 : {
395 0 : int nBXSize = 0, nBYSize = 0;
396 0 : GDALGetBlockSize(hMaskBand, &nBXSize, &nBYSize);
397 0 : if (nBXSize == 0 || nBYSize == 0 ||
398 0 : nBXSize > INT_MAX / 2 / nBYSize)
399 : {
400 : // do nothing
401 : }
402 : else
403 : {
404 0 : GDALChecksumImage(hMaskBand, 0, 0, nXSizeToRead,
405 : nYSizeToRead);
406 : }
407 : }
408 :
409 0 : int nOverviewCount = GDALGetOverviewCount(hBand);
410 0 : for (int i = 0; i < nOverviewCount; i++)
411 : {
412 0 : GDALGetOverview(hBand, i);
413 : }
414 : }
415 :
416 0 : GDALClose(hDS);
417 : }
418 :
419 : auto poDS = std::unique_ptr<GDALDataset>(
420 1 : GDALDataset::Open(pszGDALFilename, GDAL_OF_MULTIDIM_RASTER));
421 1 : if (poDS)
422 : {
423 0 : auto poDriver = poDS->GetDriver();
424 0 : const char *pszDriverName = nullptr;
425 0 : if (poDriver)
426 0 : pszDriverName = poDriver->GetDescription();
427 0 : auto poRootGroup = poDS->GetRootGroup();
428 0 : poDS.reset();
429 0 : if (poRootGroup)
430 0 : ExploreGroup(poRootGroup, pszDriverName);
431 : }
432 :
433 1 : CPLPopErrorHandler();
434 : #ifdef USE_FILESYSTEM
435 : VSIUnlink(szTempFilename);
436 : #else
437 1 : VSIUnlink(MEM_FILENAME);
438 : #endif
439 2 : return 0;
440 : }
|