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 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include <algorithm>
35
36 #include "gdal.h"
37 #include "cpl_conv.h"
38 #include "cpl_string.h"
39 #include "cpl_vsi.h"
40 #include "gdal_alg.h"
41 #include "gdal_priv.h"
42 #include "gdal_frmts.h"
43
44 #ifndef REGISTER_FUNC
45 #define REGISTER_FUNC GDALAllRegister
46 #endif
47
48 #ifndef GDAL_SKIP
49 #define GDAL_SKIP "CAD"
50 #endif
51
52 #ifndef EXTENSION
53 #define EXTENSION "bin"
54 #endif
55
56 #ifndef MEM_FILENAME
57 #define MEM_FILENAME "/vsimem/test"
58 #endif
59
60 #ifndef GDAL_FILENAME
61 #define GDAL_FILENAME MEM_FILENAME
62 #endif
63
64 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv);
65 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len);
66
LLVMFuzzerInitialize(int *,char *** argv)67 int LLVMFuzzerInitialize(int* /*argc*/, char*** argv)
68 {
69 const char* exe_path = (*argv)[0];
70 if( CPLGetConfigOption("GDAL_DATA", nullptr) == nullptr )
71 {
72 CPLSetConfigOption("GDAL_DATA", CPLGetPath(exe_path));
73 }
74 CPLSetConfigOption("CPL_TMPDIR", "/tmp");
75 CPLSetConfigOption("DISABLE_OPEN_REAL_NETCDF_FILES", "YES");
76 // Disable PDF text rendering as fontconfig cannot access its config files
77 CPLSetConfigOption("GDAL_PDF_RENDERING_OPTIONS", "RASTER,VECTOR");
78 // to avoid timeout in WMS driver
79 CPLSetConfigOption("GDAL_WMS_ABORT_CURL_REQUEST", "YES");
80 CPLSetConfigOption("GDAL_HTTP_TIMEOUT", "1");
81 CPLSetConfigOption("GDAL_HTTP_CONNECTTIMEOUT", "1");
82 CPLSetConfigOption("GDAL_CACHEMAX", "1000"); // Limit to 1 GB
83 #ifdef GTIFF_USE_MMAP
84 CPLSetConfigOption("GTIFF_USE_MMAP", "YES");
85 #endif
86 return 0;
87 }
88
LLVMFuzzerTestOneInput(const uint8_t * buf,size_t len)89 int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
90 {
91 #ifdef USE_FILESYSTEM
92 char szTempFilename[64];
93 snprintf(szTempFilename, sizeof(szTempFilename),
94 "/tmp/gdal_fuzzer_%d.%s",
95 (int)getpid(), EXTENSION);
96 VSILFILE* fp = VSIFOpenL(szTempFilename, "wb");
97 if( !fp )
98 {
99 fprintf(stderr, "Cannot create %s\n", szTempFilename);
100 return 1;
101 }
102 VSIFWriteL( buf, 1, len, fp );
103 #else
104 VSILFILE* fp = VSIFileFromMemBuffer( MEM_FILENAME,
105 reinterpret_cast<GByte*>(const_cast<uint8_t*>(buf)), len, FALSE );
106 #endif
107 VSIFCloseL(fp);
108 #ifdef GDAL_SKIP
109 CPLSetConfigOption("GDAL_SKIP", GDAL_SKIP);
110 #endif
111 REGISTER_FUNC();
112 CPLPushErrorHandler(CPLQuietErrorHandler);
113 #ifdef USE_FILESYSTEM
114 const char* pszGDALFilename = szTempFilename;
115 #else
116 const char* pszGDALFilename = GDAL_FILENAME;
117 #endif
118 GDALDatasetH hDS = GDALOpen( pszGDALFilename, GA_ReadOnly );
119 if( hDS )
120 {
121 const int nTotalBands = GDALGetRasterCount(hDS);
122 const int nBands = std::min(10, nTotalBands);
123 bool bDoCheckSum = true;
124 int nXSizeToRead = std::min(1024, GDALGetRasterXSize(hDS));
125 int nYSizeToRead = std::min(1024, GDALGetRasterYSize(hDS));
126 if( nBands > 0 )
127 {
128 const char* pszInterleave =
129 GDALGetMetadataItem( hDS, "INTERLEAVE", "IMAGE_STRUCTURE" );
130 int nSimultaneousBands =
131 (pszInterleave && EQUAL(pszInterleave, "PIXEL")) ?
132 nTotalBands : 1;
133
134 // When using the RGBA interface in pixel-interleaved mode, take
135 // into account the raw number of bands to compute memory
136 // requirements
137 if( nBands == 4 && nSimultaneousBands != 1 &&
138 GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff") )
139 {
140 GDALDatasetH hRawDS = GDALOpen(
141 (CPLString("GTIFF_RAW:")+pszGDALFilename).c_str(),
142 GA_ReadOnly );
143 if( hRawDS )
144 {
145 nSimultaneousBands = GDALGetRasterCount(hRawDS);
146 GDALClose(hRawDS);
147 }
148 }
149
150 // If we know that we will need to allocate a lot of memory
151 // given the block size and interleaving mode, do not read
152 // pixels to avoid out of memory conditions by ASAN
153 GIntBig nPixels = 0;
154 for( int i = 0; i < nBands; i++ )
155 {
156 int nBXSize = 0, nBYSize = 0;
157 GDALGetBlockSize( GDALGetRasterBand(hDS, i+1), &nBXSize,
158 &nBYSize );
159 if( nBXSize == 0 || nBYSize == 0 ||
160 nBXSize > INT_MAX / nBYSize )
161 {
162 bDoCheckSum = false;
163 break;
164 }
165
166 // Limit to 1000 blocks read for each band.
167 while( (nXSizeToRead > 1 || nYSizeToRead > 1) &&
168 (DIV_ROUND_UP(nXSizeToRead, nBXSize) *
169 DIV_ROUND_UP(nYSizeToRead, nBYSize) > 1000) )
170 {
171 if( nXSizeToRead > 1 &&
172 DIV_ROUND_UP(nXSizeToRead, nBXSize) >
173 DIV_ROUND_UP(nYSizeToRead, nBYSize) )
174 nXSizeToRead /= 2;
175 else if( nYSizeToRead > 1 )
176 nYSizeToRead /= 2;
177 else
178 nXSizeToRead /= 2;
179 }
180
181 // Currently decoding of PIXARLOG compressed TIFF requires
182 // a temporary buffer for the whole strip (if stripped) or
183 // image (if tiled), so be careful for a
184 // GTiffSplitBand
185 // Could probably be fixed for the CHUNKY_STRIP_READ_SUPPORT
186 // mode.
187 // Workaround https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2606
188 const char* pszCompress =
189 GDALGetMetadataItem(hDS, "COMPRESSION", "IMAGE_STRUCTURE");
190 if( pszCompress != nullptr &&
191 ((nBYSize == 1 && nYSizeToRead > 1 &&
192 GDALGetMetadataItem(GDALGetRasterBand(hDS, 1),
193 "BLOCK_OFFSET_0_1", "TIFF") == nullptr) ||
194 nBXSize != GDALGetRasterXSize(hDS)) &&
195 GDALGetDatasetDriver(hDS) == GDALGetDriverByName("GTiff") )
196 {
197 if( EQUAL(pszCompress, "PIXARLOG") &&
198 GDALGetRasterYSize(hDS) > (INT_MAX / 2) /
199 static_cast<int>(sizeof(GUInt16)) /
200 nSimultaneousBands / GDALGetRasterXSize(hDS) )
201 {
202 bDoCheckSum = false;
203 }
204 // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2874
205 else if( EQUAL(pszCompress, "SGILOG24") &&
206 GDALGetRasterYSize(hDS) > (INT_MAX / 2) /
207 static_cast<int>(sizeof(GUInt32)) /
208 nSimultaneousBands / GDALGetRasterXSize(hDS) )
209 {
210 bDoCheckSum = false;
211 }
212 }
213
214 GIntBig nNewPixels = static_cast<GIntBig>(nBXSize) * nBYSize;
215 nNewPixels *= DIV_ROUND_UP(nXSizeToRead, nBXSize);
216 nNewPixels *= DIV_ROUND_UP(nYSizeToRead, nBYSize);
217 if( nNewPixels > nPixels )
218 nPixels = nNewPixels;
219 }
220 if( bDoCheckSum )
221 {
222 const GDALDataType eDT =
223 GDALGetRasterDataType( GDALGetRasterBand(hDS, 1) );
224 const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
225 if( nPixels > 10 * 1024 * 1024 / nDTSize / nSimultaneousBands )
226 {
227 bDoCheckSum = false;
228 }
229 }
230 }
231 if( bDoCheckSum )
232 {
233 for( int i = 0; i < nBands; i++ )
234 {
235 GDALRasterBandH hBand = GDALGetRasterBand(hDS, i+1);
236 CPLDebug("FUZZER", "Checksum band %d: %d,%d,%d,%d",
237 i+1,0, 0, nXSizeToRead, nYSizeToRead);
238 GDALChecksumImage(hBand, 0, 0, nXSizeToRead, nYSizeToRead);
239 }
240 }
241
242 // Test other API
243 GDALGetProjectionRef(hDS);
244 double adfGeoTransform[6];
245 GDALGetGeoTransform(hDS, adfGeoTransform);
246 CSLDestroy(GDALGetFileList(hDS));
247 GDALGetGCPCount(hDS);
248 GDALGetGCPs(hDS);
249 GDALGetGCPProjection(hDS);
250 GDALGetMetadata(hDS, nullptr);
251 GDALGetMetadataItem(hDS, "foo", nullptr);
252 CSLDestroy(GDALGetFileList(hDS));
253 if( nBands > 0 )
254 {
255 GDALRasterBandH hBand = GDALGetRasterBand(hDS, 1);
256
257 int bFound = FALSE;
258 GDALGetRasterNoDataValue(hBand, &bFound);
259 GDALGetRasterOffset(hBand, &bFound);
260 GDALGetRasterScale(hBand, &bFound);
261 GDALGetRasterUnitType(hBand);
262 GDALGetMetadata(hBand, nullptr);
263 GDALGetMetadataItem(hBand, "foo", nullptr);
264
265 int nFlags = GDALGetMaskFlags(hBand);
266 GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand);
267 GDALGetRasterBandXSize(hMaskBand);
268 if( bDoCheckSum && nFlags == GMF_PER_DATASET )
269 GDALChecksumImage(hMaskBand, 0, 0, nXSizeToRead, nYSizeToRead);
270
271 int nOverviewCount = GDALGetOverviewCount(hBand);
272 for( int i = 0; i < nOverviewCount; i++ )
273 {
274 GDALGetOverview(hBand, i);
275 }
276 }
277
278 GDALClose(hDS);
279 }
280 CPLPopErrorHandler();
281 #ifdef USE_FILESYSTEM
282 VSIUnlink( szTempFilename );
283 #else
284 VSIUnlink( MEM_FILENAME );
285 #endif
286 return 0;
287 }
288