Coverage Report

Created: 2025-07-09 06:48

/src/libtiff/contrib/oss-fuzz/tiff_read_rgba_fuzzer.cc
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 1988-1997 Sam Leffler
2
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software and
5
 * its documentation for any purpose is hereby granted without fee, provided
6
 * that (i) the above copyright notices and this permission notice appear in
7
 * all copies of the software and related documentation, and (ii) the names of
8
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
9
 * publicity relating to the software without the specific, prior written
10
 * permission of Sam Leffler and Silicon Graphics.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
13
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
14
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
15
 *
16
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
17
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
18
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
20
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21
 * OF THIS SOFTWARE.
22
 */
23
24
#include <cstdint>
25
#include <cstdlib>
26
#include <cstring>
27
#include <sstream>
28
#include <tiffio.h>
29
#include <tiffio.hxx>
30
31
/* stolen from tiffiop.h, which is a private header so we can't just include it
32
 */
33
/* safe multiply returns either the multiplied value or 0 if it overflowed */
34
#define __TIFFSafeMultiply(t, v, m)                                            \
35
15.2k
    ((((t)(m) != (t)0) && (((t)(((v) * (m)) / (m))) == (t)(v)))                \
36
15.2k
         ? (t)((v) * (m))                                                      \
37
15.2k
         : (t)0)
38
39
const uint64_t MAX_SIZE = 500000000;
40
41
extern "C" void handle_error(const char *unused, const char *unused2,
42
                             va_list unused3)
43
2.76M
{
44
2.76M
    return;
45
2.76M
}
46
47
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
48
8.02k
{
49
8.02k
#ifndef STANDALONE
50
8.02k
    TIFFSetErrorHandler(handle_error);
51
8.02k
    TIFFSetWarningHandler(handle_error);
52
8.02k
#endif
53
8.02k
#if defined(__has_feature)
54
#if __has_feature(memory_sanitizer)
55
    // libjpeg-turbo has issues with MSAN and SIMD code
56
    // See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=7547
57
    // and https://github.com/libjpeg-turbo/libjpeg-turbo/pull/365
58
    setenv("JSIMD_FORCENONE", "1", 1);
59
#endif
60
8.02k
#endif
61
8.02k
    std::istringstream s(std::string(Data, Data + Size));
62
8.02k
    TIFF *tif = TIFFStreamOpen("MemTIFF", &s);
63
8.02k
    if (!tif)
64
2.63k
    {
65
2.63k
        return 0;
66
2.63k
    }
67
5.38k
    uint32_t w, h;
68
5.38k
    uint32_t *raster;
69
70
5.38k
    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
71
5.38k
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
72
    /* don't continue if file size is ludicrous */
73
5.38k
    if (TIFFTileSize64(tif) > MAX_SIZE)
74
203
    {
75
203
        TIFFClose(tif);
76
203
        return 0;
77
203
    }
78
5.18k
    uint64_t bufsize = TIFFTileSize64(tif);
79
    /* don't continue if the buffer size greater than the max allowed by the
80
     * fuzzer */
81
5.18k
    if (bufsize > MAX_SIZE || bufsize == 0)
82
114
    {
83
114
        TIFFClose(tif);
84
114
        return 0;
85
114
    }
86
87
5.07k
    if (TIFFIsTiled(tif))
88
3.45k
    {
89
        /* another hack to work around an OOM in tif_fax3.c */
90
3.45k
        uint32_t tilewidth = 0;
91
3.45k
        uint32_t imagewidth = 0;
92
3.45k
        TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tilewidth);
93
3.45k
        TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imagewidth);
94
3.45k
        tilewidth = __TIFFSafeMultiply(uint32_t, tilewidth, 2);
95
3.45k
        imagewidth = __TIFFSafeMultiply(uint32_t, imagewidth, 2);
96
3.45k
        if (tilewidth * 2 > MAX_SIZE || imagewidth * 2 > MAX_SIZE ||
97
3.45k
            tilewidth == 0 || imagewidth == 0)
98
2
        {
99
2
            TIFFClose(tif);
100
2
            return 0;
101
2
        }
102
3.45k
    }
103
1.62k
    else
104
1.62k
    {
105
        // check the size of the non-tiled image
106
1.62k
        uint32_t rowsize = 0;
107
1.62k
        TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsize);
108
1.62k
        uint32_t stripsize = TIFFStripSize(tif);
109
1.62k
        rowsize = __TIFFSafeMultiply(uint32_t, rowsize, 2);
110
1.62k
        stripsize = __TIFFSafeMultiply(uint32_t, stripsize, 2);
111
1.62k
        if (rowsize * 2 > MAX_SIZE || stripsize * 2 > MAX_SIZE ||
112
1.62k
            rowsize == 0 || stripsize == 0)
113
5
        {
114
5
            TIFFClose(tif);
115
5
            return 0;
116
5
        }
117
1.62k
    }
118
119
5.06k
    uint32_t size = __TIFFSafeMultiply(uint32_t, w, h);
120
121
5.06k
    if (size > MAX_SIZE || size == 0)
122
5
    {
123
5
        TIFFClose(tif);
124
5
        return 0;
125
5
    }
126
127
5.06k
    raster = (uint32_t *)_TIFFmalloc(size * sizeof(uint32_t));
128
5.06k
    int ret = 0;
129
5.06k
    if (raster != NULL)
130
5.06k
    {
131
5.06k
        TIFFReadRGBAImage(tif, w, h, raster, 0);
132
133
5.06k
        if (!TIFFIsTiled(tif))
134
1.61k
        {
135
            // Allocate a buffer to hold one scanline
136
1.61k
            tsize_t scanlineSize = TIFFScanlineSize(tif);
137
1.61k
            void *buffer = _TIFFmalloc(scanlineSize);
138
1.61k
            if (!buffer)
139
0
            {
140
0
                fprintf(stderr, "Memory allocation failed\n");
141
0
                ret = 1;
142
0
                goto cleanup;
143
0
            }
144
145
            // Read each scanline
146
245k
            for (uint32_t row = 0; row < h; row++)
147
245k
            {
148
245k
                if (TIFFReadScanline(tif, buffer, row, 0) < 0)
149
1.23k
                {
150
1.23k
                    _TIFFfree(buffer);
151
1.23k
                    ret = 1;
152
1.23k
                    goto cleanup;
153
1.23k
                }
154
245k
            }
155
374
            _TIFFfree(buffer);
156
374
        }
157
5.06k
    cleanup:
158
5.06k
        _TIFFfree(raster);
159
5.06k
    }
160
5.06k
    TIFFClose(tif);
161
162
5.06k
    return ret;
163
5.06k
}
164
165
#ifdef STANDALONE
166
167
template <class T> static void CPL_IGNORE_RET_VAL(T) {}
168
169
static void Usage(int, char *argv[])
170
{
171
    fprintf(stderr, "%s [--help] [-repeat N] filename.\n", argv[0]);
172
    exit(1);
173
}
174
175
int main(int argc, char *argv[])
176
{
177
    int nRet = 0;
178
    void *buf = NULL;
179
    int nLen = 0;
180
    int nLoops = 1;
181
    const char *pszFilename = NULL;
182
183
    for (int i = 1; i < argc; i++)
184
    {
185
        if (i + 1 < argc && strcmp(argv[i], "-repeat") == 0)
186
        {
187
            nLoops = atoi(argv[i + 1]);
188
            i++;
189
        }
190
        else if (strcmp(argv[i], "-dummy") == 0)
191
        {
192
            uint8_t dummy = ' ';
193
            return LLVMFuzzerTestOneInput(&dummy, 1);
194
        }
195
        else if (strcmp(argv[i], "--help") == 0)
196
        {
197
            Usage(argc, argv);
198
        }
199
        else if (argv[i][0] == '-')
200
        {
201
            fprintf(stderr, "Unrecognized option: %s", argv[i]);
202
            Usage(argc, argv);
203
        }
204
        else
205
        {
206
            pszFilename = argv[i];
207
        }
208
    }
209
    if (pszFilename == nullptr)
210
    {
211
        fprintf(stderr, "No filename specified\n");
212
        Usage(argc, argv);
213
    }
214
    FILE *f = fopen(pszFilename, "rb");
215
    if (!f)
216
    {
217
        fprintf(stderr, "%s does not exist.\n", pszFilename);
218
        exit(1);
219
    }
220
    fseek(f, 0, SEEK_END);
221
    nLen = (int)ftell(f);
222
    fseek(f, 0, SEEK_SET);
223
    buf = malloc(nLen);
224
    if (!buf)
225
    {
226
        fprintf(stderr, "malloc failed.\n");
227
        fclose(f);
228
        exit(1);
229
    }
230
    CPL_IGNORE_RET_VAL(fread(buf, nLen, 1, f));
231
    fclose(f);
232
    for (int i = 0; i < nLoops; i++)
233
    {
234
        nRet = LLVMFuzzerTestOneInput(static_cast<const uint8_t *>(buf), nLen);
235
        if (nRet != 0)
236
            break;
237
    }
238
    free(buf);
239
    return nRet;
240
}
241
242
#endif