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 : #ifdef REGISTER_GTiff
90 : GDALRegister_GTiff();
91 : #endif
92 :
93 0 : return 0;
94 : }
95 :
96 0 : static void ExploreAttributes(const GDALIHasAttribute *attributeHolder)
97 : {
98 0 : const auto attributes = attributeHolder->GetAttributes();
99 0 : for (const auto &attribute : attributes)
100 : {
101 0 : attribute->ReadAsRaw();
102 : }
103 :
104 0 : attributeHolder->GetAttribute("i_do_not_exist");
105 0 : }
106 :
107 0 : static void ExploreArray(const std::shared_ptr<GDALMDArray> &poArray,
108 : const char *pszDriverName)
109 : {
110 0 : ExploreAttributes(poArray.get());
111 :
112 0 : poArray->GetFilename();
113 0 : poArray->GetStructuralInfo();
114 0 : poArray->GetUnit();
115 0 : poArray->GetSpatialRef();
116 0 : poArray->GetRawNoDataValue();
117 0 : poArray->GetOffset();
118 0 : poArray->GetScale();
119 0 : poArray->GetCoordinateVariables();
120 :
121 0 : const auto nDimCount = poArray->GetDimensionCount();
122 0 : bool bRead = true;
123 0 : constexpr size_t MAX_ALLOC = 1000 * 1000 * 1000U;
124 0 : if (pszDriverName && EQUAL(pszDriverName, "GRIB"))
125 : {
126 0 : const auto &poDims = poArray->GetDimensions();
127 0 : if (nDimCount >= 2 &&
128 0 : poDims[nDimCount - 2]->GetSize() >
129 0 : MAX_ALLOC / sizeof(double) / poDims[nDimCount - 1]->GetSize())
130 : {
131 0 : bRead = false;
132 0 : }
133 : }
134 : else
135 : {
136 0 : const auto anBlockSize = poArray->GetBlockSize();
137 0 : size_t nBlockSize = poArray->GetDataType().GetSize();
138 0 : for (const auto nDimBlockSize : anBlockSize)
139 : {
140 0 : if (nDimBlockSize == 0)
141 : {
142 0 : break;
143 : }
144 0 : if (nBlockSize > MAX_ALLOC / nDimBlockSize)
145 : {
146 0 : bRead = false;
147 0 : break;
148 : }
149 0 : nBlockSize *= static_cast<size_t>(nDimBlockSize);
150 : }
151 : }
152 :
153 0 : if (bRead && poArray->GetDataType().GetClass() == GEDTC_NUMERIC)
154 : {
155 0 : std::vector<GUInt64> anArrayStartIdx(nDimCount);
156 0 : std::vector<size_t> anCount(nDimCount, 1);
157 0 : std::vector<GInt64> anArrayStep(nDimCount);
158 0 : std::vector<GPtrDiff_t> anBufferStride(nDimCount);
159 0 : std::vector<GByte> abyData(poArray->GetDataType().GetSize());
160 0 : poArray->Read(anArrayStartIdx.data(), anCount.data(),
161 0 : anArrayStep.data(), anBufferStride.data(),
162 0 : poArray->GetDataType(), &abyData[0]);
163 : }
164 0 : }
165 :
166 0 : static void ExploreGroup(const std::shared_ptr<GDALGroup> &poGroup,
167 : const char *pszDriverName)
168 : {
169 0 : ExploreAttributes(poGroup.get());
170 :
171 0 : const auto groupNames = poGroup->GetGroupNames();
172 0 : poGroup->OpenGroup("i_do_not_exist");
173 0 : for (const auto &name : groupNames)
174 : {
175 0 : auto poSubGroup = poGroup->OpenGroup(name);
176 0 : if (poSubGroup)
177 0 : ExploreGroup(poSubGroup, pszDriverName);
178 : }
179 :
180 0 : const auto arrayNames = poGroup->GetMDArrayNames();
181 0 : poGroup->OpenMDArray("i_do_not_exist");
182 0 : for (const auto &name : arrayNames)
183 : {
184 0 : auto poArray = poGroup->OpenMDArray(name);
185 0 : if (poArray)
186 : {
187 0 : ExploreArray(poArray, pszDriverName);
188 : }
189 : }
190 0 : }
191 :
192 1 : int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
193 : {
194 : #ifdef USE_FILESYSTEM
195 : char szTempFilename[64];
196 : snprintf(szTempFilename, sizeof(szTempFilename), "/tmp/gdal_fuzzer_%d.%s",
197 : (int)getpid(), EXTENSION);
198 : VSILFILE *fp = VSIFOpenL(szTempFilename, "wb");
199 : if (!fp)
200 : {
201 : fprintf(stderr, "Cannot create %s\n", szTempFilename);
202 : return 1;
203 : }
204 : VSIFWriteL(buf, 1, len, fp);
205 : #else
206 1 : VSILFILE *fp = VSIFileFromMemBuffer(
207 : MEM_FILENAME, reinterpret_cast<GByte *>(const_cast<uint8_t *>(buf)),
208 : len, FALSE);
209 : #endif
210 1 : VSIFCloseL(fp);
211 :
212 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
213 : #ifdef USE_FILESYSTEM
214 : const char *pszGDALFilename = szTempFilename;
215 : #else
216 1 : const char *pszGDALFilename = GDAL_FILENAME;
217 : #endif
218 :
219 : #ifdef DRIVER_NAME
220 : const char *const apszAllowedDrivers[] = {DRIVER_NAME, nullptr};
221 : #else
222 1 : const char *const *apszAllowedDrivers = nullptr;
223 : #endif
224 :
225 1 : GDALDatasetH hDS = GDALOpenEx(pszGDALFilename, GDAL_OF_RASTER,
226 : apszAllowedDrivers, nullptr, nullptr);
227 1 : if (hDS)
228 : {
229 0 : const int nTotalBands = GDALGetRasterCount(hDS);
230 0 : const int nBands = std::min(10, nTotalBands);
231 0 : bool bDoCheckSum = true;
232 0 : int nXSizeToRead = std::min(1024, GDALGetRasterXSize(hDS));
233 0 : int nYSizeToRead = std::min(1024, GDALGetRasterYSize(hDS));
234 0 : if (nBands > 0)
235 : {
236 : const char *pszInterleave =
237 0 : GDALGetMetadataItem(hDS, "INTERLEAVE", "IMAGE_STRUCTURE");
238 0 : int nSimultaneousBands =
239 0 : (pszInterleave && EQUAL(pszInterleave, "PIXEL")) ? nTotalBands
240 : : 1;
241 :
242 : // When using the RGBA interface in pixel-interleaved mode, take
243 : // into account the raw number of bands to compute memory
244 : // requirements
245 0 : if (nBands == 4 && nSimultaneousBands != 1 &&
246 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
247 : {
248 0 : GDALDatasetH hRawDS = GDALOpen(
249 0 : (CPLString("GTIFF_RAW:") + pszGDALFilename).c_str(),
250 : GA_ReadOnly);
251 0 : if (hRawDS)
252 : {
253 0 : nSimultaneousBands = GDALGetRasterCount(hRawDS);
254 : // shouldn't happen, but will make Coverity Scan happy
255 0 : if (nSimultaneousBands == 0)
256 0 : nSimultaneousBands = 1;
257 0 : GDALClose(hRawDS);
258 : }
259 : }
260 :
261 : // If we know that we will need to allocate a lot of memory
262 : // given the block size and interleaving mode, do not read
263 : // pixels to avoid out of memory conditions by ASAN
264 0 : GIntBig nPixels = 0;
265 0 : for (int i = 0; i < nBands; i++)
266 : {
267 0 : int nBXSize = 0, nBYSize = 0;
268 0 : GDALGetBlockSize(GDALGetRasterBand(hDS, i + 1), &nBXSize,
269 : &nBYSize);
270 0 : if (nBXSize == 0 || nBYSize == 0 || nBXSize > INT_MAX / nBYSize)
271 : {
272 0 : bDoCheckSum = false;
273 0 : break;
274 : }
275 :
276 : // Limit to 1000 blocks read for each band.
277 0 : while ((nXSizeToRead > 1 || nYSizeToRead > 1) &&
278 0 : (DIV_ROUND_UP(nXSizeToRead, nBXSize) *
279 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize) >
280 : 1000))
281 : {
282 0 : if (nXSizeToRead > 1 &&
283 0 : DIV_ROUND_UP(nXSizeToRead, nBXSize) >
284 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize))
285 0 : nXSizeToRead /= 2;
286 0 : else if (nYSizeToRead > 1)
287 0 : nYSizeToRead /= 2;
288 : else
289 0 : nXSizeToRead /= 2;
290 : }
291 :
292 : // Currently decoding of PIXARLOG compressed TIFF requires
293 : // a temporary buffer for the whole strip (if stripped) or
294 : // image (if tiled), so be careful for a
295 : // GTiffSplitBand
296 : // Could probably be fixed for the CHUNKY_STRIP_READ_SUPPORT
297 : // mode.
298 : // Workaround
299 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2606
300 : const char *pszCompress =
301 0 : GDALGetMetadataItem(hDS, "COMPRESSION", "IMAGE_STRUCTURE");
302 0 : if (pszCompress != nullptr &&
303 0 : ((nBYSize == 1 && GDALGetRasterYSize(hDS) > 1 &&
304 0 : GDALGetMetadataItem(GDALGetRasterBand(hDS, 1),
305 : "BLOCK_OFFSET_0_1",
306 0 : "TIFF") == nullptr) ||
307 0 : nBXSize != GDALGetRasterXSize(hDS)) &&
308 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
309 : {
310 0 : if (EQUAL(pszCompress, "PIXARLOG") &&
311 0 : GDALGetRasterYSize(hDS) >
312 0 : (INT_MAX / 2) / static_cast<int>(sizeof(GUInt16)) /
313 0 : nSimultaneousBands / GDALGetRasterXSize(hDS))
314 : {
315 0 : bDoCheckSum = false;
316 : }
317 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2874
318 0 : else if (EQUAL(pszCompress, "SGILOG24") &&
319 0 : GDALGetRasterYSize(hDS) >
320 : (INT_MAX / 2) /
321 0 : static_cast<int>(sizeof(GUInt32)) /
322 0 : nSimultaneousBands /
323 0 : GDALGetRasterXSize(hDS))
324 : {
325 0 : bDoCheckSum = false;
326 : }
327 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=38051
328 0 : else if (STARTS_WITH_CI(pszCompress, "LERC") &&
329 0 : (GDALGetRasterYSize(hDS) >
330 0 : (INT_MAX / 2) / nSimultaneousBands /
331 0 : GDALGetRasterXSize(hDS) ||
332 0 : static_cast<int64_t>(GDALGetRasterYSize(hDS)) *
333 0 : nSimultaneousBands *
334 0 : GDALGetRasterXSize(hDS) * 4 / 3 +
335 : 100 >
336 : (INT_MAX / 2)))
337 : {
338 0 : bDoCheckSum = false;
339 : }
340 : }
341 :
342 0 : GIntBig nNewPixels = static_cast<GIntBig>(nBXSize) * nBYSize;
343 0 : nNewPixels *= DIV_ROUND_UP(nXSizeToRead, nBXSize);
344 0 : nNewPixels *= DIV_ROUND_UP(nYSizeToRead, nBYSize);
345 0 : if (nNewPixels > nPixels)
346 0 : nPixels = nNewPixels;
347 : }
348 0 : if (bDoCheckSum)
349 : {
350 : const GDALDataType eDT =
351 0 : GDALGetRasterDataType(GDALGetRasterBand(hDS, 1));
352 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
353 0 : if (nPixels > 10 * 1024 * 1024 / nDTSize / nSimultaneousBands)
354 : {
355 0 : bDoCheckSum = false;
356 : }
357 : }
358 : }
359 0 : if (bDoCheckSum)
360 : {
361 0 : for (int i = 0; i < nBands; i++)
362 : {
363 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, i + 1);
364 0 : CPLDebug("FUZZER", "Checksum band %d: %d,%d,%d,%d", i + 1, 0, 0,
365 : nXSizeToRead, nYSizeToRead);
366 0 : GDALChecksumImage(hBand, 0, 0, nXSizeToRead, nYSizeToRead);
367 : }
368 : }
369 :
370 : // Test other API
371 0 : GDALGetProjectionRef(hDS);
372 : double adfGeoTransform[6];
373 0 : GDALGetGeoTransform(hDS, adfGeoTransform);
374 0 : CSLDestroy(GDALGetFileList(hDS));
375 0 : GDALGetGCPCount(hDS);
376 0 : GDALGetGCPs(hDS);
377 0 : GDALGetGCPProjection(hDS);
378 0 : GDALGetMetadata(hDS, nullptr);
379 0 : GDALGetMetadataItem(hDS, "foo", nullptr);
380 0 : CSLDestroy(GDALGetFileList(hDS));
381 0 : if (nBands > 0)
382 : {
383 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, 1);
384 :
385 0 : int bFound = FALSE;
386 0 : GDALGetRasterNoDataValue(hBand, &bFound);
387 0 : GDALGetRasterOffset(hBand, &bFound);
388 0 : GDALGetRasterScale(hBand, &bFound);
389 0 : GDALGetRasterUnitType(hBand);
390 0 : GDALGetMetadata(hBand, nullptr);
391 0 : GDALGetMetadataItem(hBand, "foo", nullptr);
392 :
393 0 : int nFlags = GDALGetMaskFlags(hBand);
394 0 : GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand);
395 0 : GDALGetRasterBandXSize(hMaskBand);
396 0 : if (bDoCheckSum && nFlags == GMF_PER_DATASET)
397 : {
398 0 : int nBXSize = 0, nBYSize = 0;
399 0 : GDALGetBlockSize(hMaskBand, &nBXSize, &nBYSize);
400 0 : if (nBXSize == 0 || nBYSize == 0 ||
401 0 : nBXSize > INT_MAX / 2 / nBYSize)
402 : {
403 : // do nothing
404 : }
405 : else
406 : {
407 0 : GDALChecksumImage(hMaskBand, 0, 0, nXSizeToRead,
408 : nYSizeToRead);
409 : }
410 : }
411 :
412 0 : int nOverviewCount = GDALGetOverviewCount(hBand);
413 0 : for (int i = 0; i < nOverviewCount; i++)
414 : {
415 0 : GDALGetOverview(hBand, i);
416 : }
417 : }
418 :
419 0 : GDALClose(hDS);
420 : }
421 :
422 : auto poDS = std::unique_ptr<GDALDataset>(
423 1 : GDALDataset::Open(pszGDALFilename, GDAL_OF_MULTIDIM_RASTER));
424 1 : if (poDS)
425 : {
426 0 : auto poDriver = poDS->GetDriver();
427 0 : const char *pszDriverName = nullptr;
428 0 : if (poDriver)
429 0 : pszDriverName = poDriver->GetDescription();
430 0 : auto poRootGroup = poDS->GetRootGroup();
431 0 : poDS.reset();
432 0 : if (poRootGroup)
433 0 : ExploreGroup(poRootGroup, pszDriverName);
434 : }
435 :
436 1 : CPLPopErrorHandler();
437 : #ifdef USE_FILESYSTEM
438 : VSIUnlink(szTempFilename);
439 : #else
440 1 : VSIUnlink(MEM_FILENAME);
441 : #endif
442 2 : return 0;
443 : }
|