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