Coverage Report

Created: 2025-06-09 08:44

/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
}