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