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", CPLGetPath(exe_path));
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 1 : GDALDatasetH hDS = GDALOpen(pszGDALFilename, GA_ReadOnly);
217 1 : if (hDS)
218 : {
219 0 : const int nTotalBands = GDALGetRasterCount(hDS);
220 0 : const int nBands = std::min(10, nTotalBands);
221 0 : bool bDoCheckSum = true;
222 0 : int nXSizeToRead = std::min(1024, GDALGetRasterXSize(hDS));
223 0 : int nYSizeToRead = std::min(1024, GDALGetRasterYSize(hDS));
224 0 : if (nBands > 0)
225 : {
226 : const char *pszInterleave =
227 0 : GDALGetMetadataItem(hDS, "INTERLEAVE", "IMAGE_STRUCTURE");
228 0 : int nSimultaneousBands =
229 0 : (pszInterleave && EQUAL(pszInterleave, "PIXEL")) ? nTotalBands
230 : : 1;
231 :
232 : // When using the RGBA interface in pixel-interleaved mode, take
233 : // into account the raw number of bands to compute memory
234 : // requirements
235 0 : if (nBands == 4 && nSimultaneousBands != 1 &&
236 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
237 : {
238 0 : GDALDatasetH hRawDS = GDALOpen(
239 0 : (CPLString("GTIFF_RAW:") + pszGDALFilename).c_str(),
240 : GA_ReadOnly);
241 0 : if (hRawDS)
242 : {
243 0 : nSimultaneousBands = GDALGetRasterCount(hRawDS);
244 : // shouldn't happen, but will make Coverity Scan happy
245 0 : if (nSimultaneousBands == 0)
246 0 : nSimultaneousBands = 1;
247 0 : GDALClose(hRawDS);
248 : }
249 : }
250 :
251 : // If we know that we will need to allocate a lot of memory
252 : // given the block size and interleaving mode, do not read
253 : // pixels to avoid out of memory conditions by ASAN
254 0 : GIntBig nPixels = 0;
255 0 : for (int i = 0; i < nBands; i++)
256 : {
257 0 : int nBXSize = 0, nBYSize = 0;
258 0 : GDALGetBlockSize(GDALGetRasterBand(hDS, i + 1), &nBXSize,
259 : &nBYSize);
260 0 : if (nBXSize == 0 || nBYSize == 0 || nBXSize > INT_MAX / nBYSize)
261 : {
262 0 : bDoCheckSum = false;
263 0 : break;
264 : }
265 :
266 : // Limit to 1000 blocks read for each band.
267 0 : while ((nXSizeToRead > 1 || nYSizeToRead > 1) &&
268 0 : (DIV_ROUND_UP(nXSizeToRead, nBXSize) *
269 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize) >
270 : 1000))
271 : {
272 0 : if (nXSizeToRead > 1 &&
273 0 : DIV_ROUND_UP(nXSizeToRead, nBXSize) >
274 0 : DIV_ROUND_UP(nYSizeToRead, nBYSize))
275 0 : nXSizeToRead /= 2;
276 0 : else if (nYSizeToRead > 1)
277 0 : nYSizeToRead /= 2;
278 : else
279 0 : nXSizeToRead /= 2;
280 : }
281 :
282 : // Currently decoding of PIXARLOG compressed TIFF requires
283 : // a temporary buffer for the whole strip (if stripped) or
284 : // image (if tiled), so be careful for a
285 : // GTiffSplitBand
286 : // Could probably be fixed for the CHUNKY_STRIP_READ_SUPPORT
287 : // mode.
288 : // Workaround
289 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2606
290 : const char *pszCompress =
291 0 : GDALGetMetadataItem(hDS, "COMPRESSION", "IMAGE_STRUCTURE");
292 0 : if (pszCompress != nullptr &&
293 0 : ((nBYSize == 1 && GDALGetRasterYSize(hDS) > 1 &&
294 0 : GDALGetMetadataItem(GDALGetRasterBand(hDS, 1),
295 : "BLOCK_OFFSET_0_1",
296 0 : "TIFF") == nullptr) ||
297 0 : nBXSize != GDALGetRasterXSize(hDS)) &&
298 0 : GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff"))
299 : {
300 0 : if (EQUAL(pszCompress, "PIXARLOG") &&
301 0 : GDALGetRasterYSize(hDS) >
302 0 : (INT_MAX / 2) / static_cast<int>(sizeof(GUInt16)) /
303 0 : nSimultaneousBands / GDALGetRasterXSize(hDS))
304 : {
305 0 : bDoCheckSum = false;
306 : }
307 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2874
308 0 : else if (EQUAL(pszCompress, "SGILOG24") &&
309 0 : GDALGetRasterYSize(hDS) >
310 : (INT_MAX / 2) /
311 0 : static_cast<int>(sizeof(GUInt32)) /
312 0 : nSimultaneousBands /
313 0 : GDALGetRasterXSize(hDS))
314 : {
315 0 : bDoCheckSum = false;
316 : }
317 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=38051
318 0 : else if (STARTS_WITH_CI(pszCompress, "LERC") &&
319 0 : (GDALGetRasterYSize(hDS) >
320 0 : (INT_MAX / 2) / nSimultaneousBands /
321 0 : GDALGetRasterXSize(hDS) ||
322 0 : static_cast<int64_t>(GDALGetRasterYSize(hDS)) *
323 0 : nSimultaneousBands *
324 0 : GDALGetRasterXSize(hDS) * 4 / 3 +
325 : 100 >
326 : (INT_MAX / 2)))
327 : {
328 0 : bDoCheckSum = false;
329 : }
330 : }
331 :
332 0 : GIntBig nNewPixels = static_cast<GIntBig>(nBXSize) * nBYSize;
333 0 : nNewPixels *= DIV_ROUND_UP(nXSizeToRead, nBXSize);
334 0 : nNewPixels *= DIV_ROUND_UP(nYSizeToRead, nBYSize);
335 0 : if (nNewPixels > nPixels)
336 0 : nPixels = nNewPixels;
337 : }
338 0 : if (bDoCheckSum)
339 : {
340 : const GDALDataType eDT =
341 0 : GDALGetRasterDataType(GDALGetRasterBand(hDS, 1));
342 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
343 0 : if (nPixels > 10 * 1024 * 1024 / nDTSize / nSimultaneousBands)
344 : {
345 0 : bDoCheckSum = false;
346 : }
347 : }
348 : }
349 0 : if (bDoCheckSum)
350 : {
351 0 : for (int i = 0; i < nBands; i++)
352 : {
353 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, i + 1);
354 0 : CPLDebug("FUZZER", "Checksum band %d: %d,%d,%d,%d", i + 1, 0, 0,
355 : nXSizeToRead, nYSizeToRead);
356 0 : GDALChecksumImage(hBand, 0, 0, nXSizeToRead, nYSizeToRead);
357 : }
358 : }
359 :
360 : // Test other API
361 0 : GDALGetProjectionRef(hDS);
362 : double adfGeoTransform[6];
363 0 : GDALGetGeoTransform(hDS, adfGeoTransform);
364 0 : CSLDestroy(GDALGetFileList(hDS));
365 0 : GDALGetGCPCount(hDS);
366 0 : GDALGetGCPs(hDS);
367 0 : GDALGetGCPProjection(hDS);
368 0 : GDALGetMetadata(hDS, nullptr);
369 0 : GDALGetMetadataItem(hDS, "foo", nullptr);
370 0 : CSLDestroy(GDALGetFileList(hDS));
371 0 : if (nBands > 0)
372 : {
373 0 : GDALRasterBandH hBand = GDALGetRasterBand(hDS, 1);
374 :
375 0 : int bFound = FALSE;
376 0 : GDALGetRasterNoDataValue(hBand, &bFound);
377 0 : GDALGetRasterOffset(hBand, &bFound);
378 0 : GDALGetRasterScale(hBand, &bFound);
379 0 : GDALGetRasterUnitType(hBand);
380 0 : GDALGetMetadata(hBand, nullptr);
381 0 : GDALGetMetadataItem(hBand, "foo", nullptr);
382 :
383 0 : int nFlags = GDALGetMaskFlags(hBand);
384 0 : GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand);
385 0 : GDALGetRasterBandXSize(hMaskBand);
386 0 : if (bDoCheckSum && nFlags == GMF_PER_DATASET)
387 : {
388 0 : int nBXSize = 0, nBYSize = 0;
389 0 : GDALGetBlockSize(hMaskBand, &nBXSize, &nBYSize);
390 0 : if (nBXSize == 0 || nBYSize == 0 ||
391 0 : nBXSize > INT_MAX / 2 / nBYSize)
392 : {
393 : // do nothing
394 : }
395 : else
396 : {
397 0 : GDALChecksumImage(hMaskBand, 0, 0, nXSizeToRead,
398 : nYSizeToRead);
399 : }
400 : }
401 :
402 0 : int nOverviewCount = GDALGetOverviewCount(hBand);
403 0 : for (int i = 0; i < nOverviewCount; i++)
404 : {
405 0 : GDALGetOverview(hBand, i);
406 : }
407 : }
408 :
409 0 : GDALClose(hDS);
410 : }
411 :
412 : auto poDS = std::unique_ptr<GDALDataset>(
413 1 : GDALDataset::Open(pszGDALFilename, GDAL_OF_MULTIDIM_RASTER));
414 1 : if (poDS)
415 : {
416 0 : auto poDriver = poDS->GetDriver();
417 0 : const char *pszDriverName = nullptr;
418 0 : if (poDriver)
419 0 : pszDriverName = poDriver->GetDescription();
420 0 : auto poRootGroup = poDS->GetRootGroup();
421 0 : poDS.reset();
422 0 : if (poRootGroup)
423 0 : ExploreGroup(poRootGroup, pszDriverName);
424 : }
425 :
426 1 : CPLPopErrorHandler();
427 : #ifdef USE_FILESYSTEM
428 : VSIUnlink(szTempFilename);
429 : #else
430 1 : VSIUnlink(MEM_FILENAME);
431 : #endif
432 2 : return 0;
433 : }
|