/src/gdal/fuzzers/gdal_translate_fuzzer.cpp
Line | Count | Source (jump to first uncovered line) |
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 "gdal.h" |
30 | | #include "cpl_conv.h" |
31 | | #include "cpl_string.h" |
32 | | #include "cpl_vsi.h" |
33 | | #include "gdal_priv.h" |
34 | | #include "gdal_utils.h" |
35 | | |
36 | | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv); |
37 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); |
38 | | |
39 | | int LLVMFuzzerInitialize(int * /*argc*/, char ***argv) |
40 | 86 | { |
41 | 86 | const char *exe_path = (*argv)[0]; |
42 | 86 | if (CPLGetConfigOption("GDAL_DATA", nullptr) == nullptr) |
43 | 86 | { |
44 | 86 | CPLSetConfigOption("GDAL_DATA", CPLGetPathSafe(exe_path).c_str()); |
45 | 86 | } |
46 | 86 | CPLSetConfigOption("CPL_TMPDIR", "/tmp"); |
47 | 86 | CPLSetConfigOption("DISABLE_OPEN_REAL_NETCDF_FILES", "YES"); |
48 | | // Disable PDF text rendering as fontconfig cannot access its config files |
49 | 86 | CPLSetConfigOption("GDAL_PDF_RENDERING_OPTIONS", "RASTER,VECTOR"); |
50 | | // to avoid timeout in WMS driver |
51 | 86 | CPLSetConfigOption("GDAL_WMS_ABORT_CURL_REQUEST", "YES"); |
52 | 86 | CPLSetConfigOption("GDAL_HTTP_TIMEOUT", "1"); |
53 | 86 | CPLSetConfigOption("GDAL_HTTP_CONNECTTIMEOUT", "1"); |
54 | 86 | CPLSetConfigOption("GDAL_CACHEMAX", "1000"); // Limit to 1 GB |
55 | 86 | GDALAllRegister(); |
56 | 86 | return 0; |
57 | 86 | } |
58 | | |
59 | | int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) |
60 | 18.8k | { |
61 | 18.8k | VSILFILE *fp = VSIFileFromMemBuffer( |
62 | 18.8k | "/vsimem/test.tar", |
63 | 18.8k | reinterpret_cast<GByte *>(const_cast<uint8_t *>(buf)), len, FALSE); |
64 | 18.8k | VSIFCloseL(fp); |
65 | | |
66 | 18.8k | CPLPushErrorHandler(CPLQuietErrorHandler); |
67 | | |
68 | 18.8k | char **papszArgv = nullptr; |
69 | | |
70 | | // Prevent generating too big output raster. Make sure they are set at |
71 | | // the beginning to avoid being accidentally eaten by invalid arguments |
72 | | // afterwards. |
73 | 18.8k | papszArgv = CSLAddString(papszArgv, "-limit_outsize"); |
74 | 18.8k | papszArgv = CSLAddString(papszArgv, "1000000"); |
75 | | |
76 | 18.8k | fp = VSIFOpenL("/vsitar//vsimem/test.tar/cmd.txt", "rb"); |
77 | 18.8k | if (fp != nullptr) |
78 | 9.34k | { |
79 | 9.34k | const char *pszLine = nullptr; |
80 | 1.43M | while ((pszLine = CPLReadLineL(fp)) != nullptr) |
81 | 1.42M | { |
82 | 1.42M | if (!EQUAL(pszLine, "-limit_outsize")) |
83 | 1.42M | papszArgv = CSLAddString(papszArgv, pszLine); |
84 | 1.42M | } |
85 | 9.34k | VSIFCloseL(fp); |
86 | 9.34k | } |
87 | | |
88 | 18.8k | int nXDim = -1; |
89 | 18.8k | int nYDim = -1; |
90 | 18.8k | bool bXDimPct = false; |
91 | 18.8k | bool bYDimPct = false; |
92 | 18.8k | bool bNonNearestResampling = false; |
93 | 18.8k | int nBlockXSize = 0; |
94 | 18.8k | int nBlockYSize = 0; |
95 | 18.8k | bool bStatsEnabled = false; |
96 | 18.8k | bool bHFA = false; |
97 | 18.8k | if (papszArgv != nullptr) |
98 | 18.8k | { |
99 | 18.8k | int nCount = CSLCount(papszArgv); |
100 | 1.47M | for (int i = 0; i < nCount; i++) |
101 | 1.45M | { |
102 | 1.45M | if (EQUAL(papszArgv[i], "-outsize") && i + 2 < nCount) |
103 | 7.93k | { |
104 | 7.93k | nXDim = atoi(papszArgv[i + 1]); |
105 | 7.93k | bXDimPct = |
106 | 7.93k | (papszArgv[i + 1][0] != '\0' && |
107 | 7.93k | papszArgv[i + 1][strlen(papszArgv[i + 1]) - 1] == '%'); |
108 | 7.93k | nYDim = atoi(papszArgv[i + 2]); |
109 | 7.93k | bYDimPct = |
110 | 7.93k | (papszArgv[i + 2][0] != '\0' && |
111 | 7.93k | papszArgv[i + 2][strlen(papszArgv[i + 2]) - 1] == '%'); |
112 | 7.93k | } |
113 | 1.45M | else if (EQUAL(papszArgv[i], "-r") && i + 1 < nCount) |
114 | 2.77k | { |
115 | 2.77k | bNonNearestResampling = |
116 | 2.77k | !STARTS_WITH_CI(papszArgv[i + 1], "NEAR"); |
117 | 2.77k | } |
118 | 1.44M | else if (EQUAL(papszArgv[i], "-co") && i + 1 < nCount) |
119 | 147k | { |
120 | 147k | if (STARTS_WITH_CI(papszArgv[i + 1], "BLOCKSIZE=")) |
121 | 258 | { |
122 | 258 | nBlockXSize = |
123 | 258 | std::max(nBlockXSize, |
124 | 258 | atoi(papszArgv[i + 1] + strlen("BLOCKSIZE="))); |
125 | 258 | nBlockYSize = |
126 | 258 | std::max(nBlockYSize, |
127 | 258 | atoi(papszArgv[i + 1] + strlen("BLOCKSIZE="))); |
128 | 258 | } |
129 | 147k | else if (STARTS_WITH_CI(papszArgv[i + 1], "BLOCKXSIZE=")) |
130 | 0 | { |
131 | 0 | nBlockXSize = |
132 | 0 | std::max(nBlockXSize, atoi(papszArgv[i + 1] + |
133 | 0 | strlen("BLOCKXSIZE="))); |
134 | 0 | } |
135 | 147k | else if (STARTS_WITH_CI(papszArgv[i + 1], "BLOCKYSIZE=")) |
136 | 0 | { |
137 | 0 | nBlockYSize = |
138 | 0 | std::max(nBlockYSize, atoi(papszArgv[i + 1] + |
139 | 0 | strlen("BLOCKYSIZE="))); |
140 | 0 | } |
141 | 147k | } |
142 | 1.30M | else if (EQUAL(papszArgv[i], "-stats")) |
143 | 225 | { |
144 | 225 | bStatsEnabled = true; |
145 | 225 | } |
146 | 1.30M | else if (EQUAL(papszArgv[i], "-of") && i + 1 < nCount) |
147 | 5.76k | { |
148 | 5.76k | bHFA = EQUAL(papszArgv[i + 1], "HFA"); |
149 | 5.76k | } |
150 | 1.45M | } |
151 | 18.8k | if (bHFA) |
152 | 1.26k | { |
153 | | // Disable statistics computation for HFA, as it can be time |
154 | | // consuming. |
155 | | // See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10067 |
156 | 1.26k | papszArgv = CSLInsertString(papszArgv, 0, "-co"); |
157 | 1.26k | papszArgv = CSLInsertString(papszArgv, 1, "STATISTICS=NO"); |
158 | 1.26k | } |
159 | 18.8k | } |
160 | | |
161 | 18.8k | if (papszArgv != nullptr) |
162 | 18.8k | { |
163 | 18.8k | GDALTranslateOptions *psOptions = |
164 | 18.8k | GDALTranslateOptionsNew(papszArgv, nullptr); |
165 | 18.8k | if (psOptions) |
166 | 18.4k | { |
167 | 18.4k | GDALDatasetH hSrcDS = |
168 | 18.4k | GDALOpen("/vsitar//vsimem/test.tar/in", GA_ReadOnly); |
169 | 18.4k | if (hSrcDS != nullptr) |
170 | 12.2k | { |
171 | | // Also check that reading the source doesn't involve too |
172 | | // much memory |
173 | 12.2k | GDALDataset *poSrcDS = reinterpret_cast<GDALDataset *>(hSrcDS); |
174 | 12.2k | const int nBands = poSrcDS->GetRasterCount(); |
175 | 12.2k | const int nXSize = poSrcDS->GetRasterXSize(); |
176 | 12.2k | const int nYSize = poSrcDS->GetRasterYSize(); |
177 | 12.2k | if (nBands < 10) |
178 | 12.2k | { |
179 | | // Prevent excessive downsampling which might require huge |
180 | | // memory allocation |
181 | 12.2k | bool bOKForResampling = true; |
182 | 12.2k | if (bNonNearestResampling && nXDim >= 0 && nYDim >= 0) |
183 | 2.22k | { |
184 | 2.22k | if (bXDimPct && nXDim > 0) |
185 | 0 | { |
186 | 0 | nXDim = static_cast<int>(nXSize / 100.0 * nXDim); |
187 | 0 | } |
188 | 2.22k | if (bYDimPct && nYDim > 0) |
189 | 0 | { |
190 | 0 | nYDim = static_cast<int>(nYSize / 100.0 * nYDim); |
191 | 0 | } |
192 | 2.22k | if (nXDim > 0 && nXSize / nXDim > 100) |
193 | 1 | bOKForResampling = false; |
194 | 2.22k | if (nYDim > 0 && nYSize / nYDim > 100) |
195 | 4 | bOKForResampling = false; |
196 | 2.22k | } |
197 | | |
198 | 12.2k | bool bOKForSrc = true; |
199 | 12.2k | if (nBands > 0) |
200 | 12.0k | { |
201 | 12.0k | const int nDTSize = GDALGetDataTypeSizeBytes( |
202 | 12.0k | poSrcDS->GetRasterBand(1)->GetRasterDataType()); |
203 | 12.0k | if (nXSize > 0 && nYSize > 0 && |
204 | 12.0k | nBands * nDTSize > |
205 | 11.9k | 10 * 1024 * 1024 / nXSize / nYSize) |
206 | 216 | { |
207 | 216 | bOKForSrc = false; |
208 | 216 | } |
209 | | |
210 | 12.0k | int nBXSize = 0, nBYSize = 0; |
211 | 12.0k | GDALGetBlockSize(GDALGetRasterBand(hSrcDS, 1), &nBXSize, |
212 | 12.0k | &nBYSize); |
213 | 12.0k | const char *pszInterleave = GDALGetMetadataItem( |
214 | 12.0k | hSrcDS, "INTERLEAVE", "IMAGE_STRUCTURE"); |
215 | 12.0k | int nSimultaneousBands = |
216 | 12.0k | (pszInterleave && EQUAL(pszInterleave, "PIXEL")) |
217 | 12.0k | ? nBands |
218 | 12.0k | : 1; |
219 | 12.0k | if (static_cast<GIntBig>(nSimultaneousBands) * nBXSize * |
220 | 12.0k | nBYSize * nDTSize > |
221 | 12.0k | 10 * 1024 * 1024) |
222 | 47 | { |
223 | 47 | bOKForSrc = false; |
224 | 47 | } |
225 | | |
226 | 12.0k | if (static_cast<GIntBig>(nBlockXSize) * nBlockYSize > |
227 | 12.0k | 10 * 1024 * 1024 / (nBands * nDTSize)) |
228 | 0 | { |
229 | 0 | bOKForSrc = false; |
230 | 0 | } |
231 | 12.0k | } |
232 | | |
233 | 12.2k | bool bOKForStats = true; |
234 | 12.2k | if (nBands && bStatsEnabled) |
235 | 113 | { |
236 | | // Other types might be too slow with sanitization |
237 | | // enabled See |
238 | | // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10029 |
239 | 113 | bOKForStats = |
240 | 113 | poSrcDS->GetRasterBand(1)->GetRasterDataType() == |
241 | 113 | GDT_Byte; |
242 | 113 | } |
243 | | |
244 | 12.2k | if (bOKForSrc && bOKForResampling && bOKForStats) |
245 | 12.0k | { |
246 | 12.0k | GDALDatasetH hOutDS = GDALTranslate( |
247 | 12.0k | "/vsimem/out", hSrcDS, psOptions, nullptr); |
248 | 12.0k | if (hOutDS) |
249 | 6.98k | GDALClose(hOutDS); |
250 | 12.0k | } |
251 | 12.2k | } |
252 | 12.2k | GDALClose(hSrcDS); |
253 | 12.2k | } |
254 | 18.4k | GDALTranslateOptionsFree(psOptions); |
255 | 18.4k | } |
256 | 18.8k | } |
257 | 18.8k | CSLDestroy(papszArgv); |
258 | | |
259 | 18.8k | VSIRmdirRecursive("/vsimem/"); |
260 | | |
261 | 18.8k | CPLPopErrorHandler(); |
262 | | |
263 | 18.8k | return 0; |
264 | 18.8k | } |