Browse code

Transforming the PNG checker into a PNG exploit seeker

Aldo Mazzeo authored on 2017/02/22 03:58:09
Showing 5 changed files
... ...
@@ -85,6 +85,7 @@ static const struct ftmap_s {
85 85
     { "CL_TYPE_SCRENC",       CL_TYPE_SCRENC       },
86 86
     { "CL_TYPE_GRAPHICS",     CL_TYPE_GRAPHICS     },
87 87
     { "CL_TYPE_GIF",          CL_TYPE_GIF          },
88
+    { "CL_TYPE_PNG",          CL_TYPE_PNG          },
88 89
     { "CL_TYPE_RIFF",         CL_TYPE_RIFF         },
89 90
     { "CL_TYPE_BINHEX",       CL_TYPE_BINHEX       },
90 91
     { "CL_TYPE_TNEF",         CL_TYPE_TNEF         },
... ...
@@ -67,6 +67,7 @@ typedef enum cli_file {
67 67
     CL_TYPE_SCRENC,
68 68
     CL_TYPE_GRAPHICS,
69 69
     CL_TYPE_GIF,
70
+    CL_TYPE_PNG,
70 71
     CL_TYPE_RIFF,
71 72
     CL_TYPE_BINHEX,
72 73
     CL_TYPE_TNEF,
... ...
@@ -87,7 +87,7 @@ static const char *ftypes_int[] = {
87 87
     "0:0:763a0d0a52656365697665643a20:VPOP3 Mail (DOS):CL_TYPE_ANY:CL_TYPE_MAIL",
88 88
     "0:0:789f3e22:TNEF:CL_TYPE_ANY:CL_TYPE_TNEF",
89 89
     "0:0:7f454c46:ELF:CL_TYPE_ANY:CL_TYPE_ELF",
90
-    "0:0:89504e47:PNG:CL_TYPE_ANY:CL_TYPE_GRAPHICS",
90
+  "0:0:89504e47:PNG:CL_TYPE_ANY:CL_TYPE_PNG",
91 91
     "0:0:b6b9acaefeffffff:CryptFF:CL_TYPE_ANY:CL_TYPE_CRYPTFF",
92 92
     "0:0:d0cf11e0a1b11ae1:OLE2 container:CL_TYPE_ANY:CL_TYPE_MSOLE2",
93 93
     "0:0:ffd8ff:JPEG:CL_TYPE_ANY:CL_TYPE_GRAPHICS",
... ...
@@ -36,79 +36,17 @@
36 36
 #include "clamav.h"
37 37
 #include "others.h"
38 38
 #include "png.h"
39
+#include "scanners.h"
39 40
 
40
-typedef unsigned char uch;
41
-typedef unsigned short ush;
42
-typedef unsigned long ulg;
43
-
44
-#define BS 32000 /* size of read block for CRC calculation (and zlib) */
41
+#define BS 32768 /* size of read block  */
45 42
 
46 43
 /* Mark's macros to extract big-endian short and long ints: */
47
-#define SH(p) ((ush)(uch)((p)[1]) | ((ush)(uch)((p)[0]) << 8))
48
-#define LG(p) ((ulg)(SH((p) + 2)) | ((ulg)(SH(p)) << 16))
49
-
50
-#define isASCIIalpha(x) (ascii_alpha_table[x] & 0x1)
51
-
52
-#define ANCILLARY(chunkID) ((chunkID)[0] & 0x20)
53
-#define PRIVATE(chunkID) ((chunkID)[1] & 0x20)
54
-#define RESERVED(chunkID) ((chunkID)[2] & 0x20)
55
-#define SAFECOPY(chunkID) ((chunkID)[3] & 0x20)
56
-#define CRITICAL(chunkID) (!ANCILLARY(chunkID))
57
-#define PUBLIC(chunkID) (!PRIVATE(chunkID))
58
-
59
-/* GRR FIXME:  could merge all three of these into single table (bit fields) */
60
-
61
-/* GRR 20061203:  for "isalpha()" that works even on EBCDIC machines */
62
-static const uch ascii_alpha_table[256] = {
63
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65
-    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
66
-    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
67
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
71
-
72
-/* GRR 20070707:  list of forbidden characters in various keywords */
73
-static const uch latin1_keyword_forbidden[256] = {
74
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
78
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
79
-    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
82
-
83
-/* GRR 20070707:  list of discouraged (control) characters in tEXt/zTXt text */
84
-static const uch latin1_text_discouraged[256] = {
85
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
86
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
89
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
90
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
93
-
94
-/* PNG stuff */
44
+#define SH(p) ((unsigned short)(unsigned char)((p)[1]) | ((unsigned short)(unsigned char)((p)[0]) << 8))
45
+#define LG(p) ((unsigned long)(SH((p)+2)) | ((unsigned long)(SH(p)) << 16))
95 46
 
96
-static const char *png_type[] = {/* IHDR, tRNS, BASI, summary */
97
-                                 "grayscale",
98
-                                 "INVALID",
99
-                                 "RGB",
100
-                                 "palette",
101
-                                 "grayscale+alpha",
102
-                                 "INVALID",
103
-                                 "RGB+alpha"};
104
-
105
-#define CRCCOMPL(c) c
106
-#define CRCINIT (0)
107
-#define update_crc crc32
108
-
109
-static ulg getlong(fmap_t *map, unsigned int *offset, const char *where)
47
+static unsigned long getlong(fmap_t *map, unsigned int *offset, const char *where)
110 48
 {
111
-    ulg res = 0;
49
+  unsigned long res = 0;
112 50
     int j;
113 51
 
114 52
     for (j = 0; j < 4; ++j) {
... ...
@@ -125,254 +63,32 @@ static ulg getlong(fmap_t *map, unsigned int *offset, const char *where)
125 125
     return res;
126 126
 }
127 127
 
128
-static int keywordlen(uch *buf, int maxsize)
129
-{
130
-    int j = 0;
131
-
132
-    while (j < maxsize && buf[j])
133
-        ++j;
134
-
135
-    return j;
136
-}
137
-
138
-static const char *getmonth(int m)
139
-{
140
-    static const char *month[] = {
141
-        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
142
-        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
143
-
144
-    return (m < 1 || m > 12) ? "INVALID" : month[m - 1];
145
-}
146
-
147
-/* GRR 20061203:  now EBCDIC-safe */
148
-static int check_chunk_name(char *chunk_name)
149
-{
150
-    if (isASCIIalpha((int)chunk_name[0]) && isASCIIalpha((int)chunk_name[1]) &&
151
-        isASCIIalpha((int)chunk_name[2]) && isASCIIalpha((int)chunk_name[3]))
152
-        return 0;
153
-
154
-    cli_dbgmsg("PNG: invalid chunk name\n");
155
-    return CL_EPARSE; /* usually means we've "jumped the tracks": bail! */
156
-}
157
-
158
-/* GRR 20050724 */
159
-/* caller must do return CL_EPARSE based on return value (0 == OK) */
160
-/* keyword_name is "keyword" for most chunks, but it can instead be "name" or
161
- * "identifier" or whatever makes sense for the chunk in question */
162
-static int check_keyword(uch *buffer, int maxsize, int *pKeylen)
163
-{
164
-    int j, prev_space = 0;
165
-    int keylen = keywordlen(buffer, maxsize);
166
-
167
-    if (pKeylen)
168
-        *pKeylen = keylen;
169
-
170
-    if (keylen == 0) {
171
-        cli_dbgmsg("PNG: zero length keyword\n");
172
-        return 1;
173
-    }
174
-
175
-    if (keylen > 79) {
176
-        cli_dbgmsg("PNG: keyword is longer than 79 characters\n");
177
-        return 2;
178
-    }
179
-
180
-    if (buffer[0] == ' ') {
181
-        cli_dbgmsg("PNG: keyword has leading space(s)\n");
182
-        return 3;
183
-    }
184
-
185
-    if (buffer[keylen - 1] == ' ') {
186
-        cli_dbgmsg("PNG: keyword has trailing space(s)\n");
187
-        return 4;
188
-    }
189
-
190
-    for (j = 0; j < keylen; ++j) {
191
-        if (buffer[j] == ' ') {
192
-            if (prev_space) {
193
-                cli_dbgmsg("PNG: keyword has consecutive spaces\n");
194
-                return 5;
195
-            }
196
-            prev_space = 1;
197
-        } else {
198
-            prev_space = 0;
199
-        }
200
-    }
201
-
202
-    for (j = 0; j < keylen; ++j) {
203
-        if (latin1_keyword_forbidden[buffer[j]]) { /* [0,31] || [127,160] */
204
-            cli_dbgmsg("PNG: keyword has control character(s)\n");
205
-            return 6;
206
-        }
207
-    }
208
-    return 0;
209
-}
210
-
211
-/* GRR 20070707 */
212
-/* caller must do return CL_EPARSE based on return value (0 == OK) */
213
-static int check_text(uch *buffer, int maxsize)
214
-{
215
-    int j;
216
-
217
-    for (j = 0; j < maxsize; ++j) {
218
-        if (buffer[j] == 0) {
219
-            cli_dbgmsg("PNG: text contains NULL character(s)\n");
220
-            return 1;
221
-        } else if (latin1_text_discouraged[buffer[j]]) {
222
-            cli_dbgmsg("PNG: text has control character(s)\n");
223
-            return 1;
224
-        }
225
-    }
226
-    return 0;
227
-}
228
-
229
-/* GRR 20061203 (used only for sCAL) */
230
-static int check_ascii_float(uch *buffer, int len)
231
-{
232
-    uch *qq = buffer, *bufEnd = buffer + len;
233
-    int have_sign = 0, have_integer = 0, have_dot = 0, have_fraction = 0;
234
-    int have_E = 0, have_Esign = 0, have_exponent = 0, in_digits = 0;
235
-    int have_nonzero = 0;
236
-    int rc           = 0;
237
-
238
-    for (qq = buffer; qq < bufEnd && !rc; ++qq) {
239
-        switch (*qq) {
240
-            case '+':
241
-            case '-':
242
-                if (qq == buffer) {
243
-                    have_sign = 1;
244
-                    in_digits = 0;
245
-                } else if (have_E && !have_Esign) {
246
-                    have_Esign = 1;
247
-                    in_digits  = 0;
248
-                } else {
249
-                    cli_dbgmsg("PNG: invalid sign character\n");
250
-                    rc = 1;
251
-                }
252
-                break;
253
-
254
-            case '.':
255
-                if (!have_dot && !have_E) {
256
-                    have_dot  = 1;
257
-                    in_digits = 0;
258
-                } else {
259
-                    cli_dbgmsg("PNG: invalid decimal point\n");
260
-                    rc = 2;
261
-                }
262
-                break;
263
-
264
-            case 'e':
265
-            case 'E':
266
-                if (have_integer || have_fraction) {
267
-                    have_E    = 1;
268
-                    in_digits = 0;
269
-                } else {
270
-                    cli_dbgmsg("PNG: invalid exponent before mantissa\n");
271
-                    rc = 3;
272
-                }
273
-                break;
274
-
275
-            default:
276
-                if (*qq < '0' || *qq > '9') {
277
-                    cli_dbgmsg("PNG: invalid character\n");
278
-                    rc = 4;
279
-                } else if (in_digits) {
280
-                    /* still in digits:  do nothing except check for non-zero digits */
281
-                    if (!have_exponent && *qq != '0')
282
-                        have_nonzero = 1;
283
-                } else if (!have_integer && !have_dot) {
284
-                    have_integer = 1;
285
-                    in_digits    = 1;
286
-                    if (*qq != '0')
287
-                        have_nonzero = 1;
288
-                } else if (have_dot && !have_fraction) {
289
-                    have_fraction = 1;
290
-                    in_digits     = 1;
291
-                    if (*qq != '0')
292
-                        have_nonzero = 1;
293
-                } else if (have_E && !have_exponent) {
294
-                    have_exponent = 1;
295
-                    in_digits     = 1;
296
-                } else {
297
-                    /* is this case possible? */
298
-                    cli_dbgmsg("PNG: invalid digits\n");
299
-                    rc = 5;
300
-                }
301
-                break;
302
-        }
303
-    }
304
-
305
-    /* must have either integer part or fractional part; all else is optional */
306
-    if (rc == 0 && !have_integer && !have_fraction) {
307
-        cli_dbgmsg("PNG: missing mantissa\n");
308
-        rc = 6;
309
-    }
310
-
311
-    /* non-exponent part must be non-zero (=> must have seen a non-zero digit) */
312
-    if (rc == 0 && !have_nonzero) {
313
-        cli_dbgmsg("PNG: invalid zero value(s)\n");
314
-        rc = 7;
315
-    }
316
-
317
-    return rc;
318
-}
319
-
320 128
 int cli_parsepng(cli_ctx *ctx)
321 129
 {
322
-    long sz_long;
323
-    size_t sz;
324
-    uch magic[8];
130
+  long sz;
325 131
     char chunkid[5] = {'\0', '\0', '\0', '\0', '\0'};
326 132
     size_t toread;
327 133
     int c;
328
-    int have_IHDR = 0, have_IEND = 0;
329
-    int have_PLTE = 0;
330
-    int have_IDAT = 0, have_JDAT = 0, last_is_IDAT = 0, last_is_JDAT = 0;
331
-    int have_bKGD = 0, have_cHRM = 0, have_gAMA = 0, have_hIST = 0, have_iCCP = 0;
332
-    int have_oFFs = 0, have_pCAL = 0, have_pHYs = 0, have_sBIT = 0, have_sCAL = 0;
333
-    int have_sRGB = 0, have_sTER = 0, have_tIME = 0, have_tRNS = 0;
334
-    ulg zhead = 1; /* 0x10000 indicates both zlib header bytes read */
335
-    ulg crc, filecrc;
134
+  int have_IEND = 0, have_PLTE = 0;
135
+  unsigned long zhead = 1;   /* 0x10000 indicates both zlib header bytes read */
336 136
     long num_chunks = 0L;
337 137
     long w = 0L, h = 0L;
338 138
     int bitdepth = 0, sampledepth = 0, lace = 0;
339 139
     size_t nplte      = 0;
340 140
     unsigned int ityp = 1;
341
-    uch buffer[BS];
342
-    int first_idat           = 1; /* flag:  is this the first IDAT chunk? */
343
-    int zlib_error           = 0; /* reset in IHDR section; used for IDAT */
344
-    int check_zlib           = 1; /* validate zlib stream (just IDATs for now) */
345
-    unsigned zlib_windowbits = 15;
346
-    uch outbuf[BS];
347
-    z_stream zstrm;
348
-    unsigned int offset = 0;
141
+  unsigned char buffer[BS];
142
+  unsigned int offset = 8;
349 143
     fmap_t *map         = *ctx->fmap;
350 144
 
351 145
     cli_dbgmsg("in cli_parsepng()\n");
352 146
 
353
-    if (fmap_readn(map, magic, offset, 8) != 8)
354
-        return CL_SUCCESS; /* Ignore */
355
-
356
-    if (memcmp(magic, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8))
357
-        return CL_SUCCESS; /* Not a PNG file */
147
+  while(fmap_readn(map, &c, offset, sizeof(c)) == sizeof(c)) {
358 148
 
359
-    offset += 8;
360
-
361
-    /*-------------------- BEGINNING OF IMMENSE WHILE-LOOP --------------------*/
362
-
363
-    while (fmap_readn(map, &c, offset, sizeof(c)) == sizeof(c)) {
364
-
365
-        if (have_IEND) {
366
-            cli_dbgmsg("PNG: additional data after END chunk\n");
367
-            return CL_EPARSE;
368
-        }
369
-
370
-        sz_long = getlong(map, &offset, "chunk length");
371
-        if (sz_long < 0 || sz_long > 0x7fffffff) { /* FIXME:  convert to ulg, lose "< 0" */
149
+    sz = getlong(map, &offset, "chunk length");
150
+    if (sz < 0 || sz > 0x7fffffff) {   /* FIXME:  convert to ulg, lose "< 0" */
372 151
             cli_dbgmsg("PNG: invalid chunk length (too large)\n");
373 152
             return CL_EPARSE;
374 153
         }
375
-        sz = (size_t)sz_long;
376 154
 
377 155
         if (fmap_readn(map, chunkid, offset, 4) != 4) {
378 156
             cli_dbgmsg("PNG: EOF while reading chunk type\n");
... ...
@@ -385,56 +101,34 @@ int cli_parsepng(cli_ctx *ctx)
385 385
         chunkid[4] = '\0';
386 386
         ++num_chunks;
387 387
 
388
-        if (check_chunk_name(chunkid) != 0)
389
-            return CL_EPARSE;
390
-
391
-        if (!have_IHDR && strcmp(chunkid, "IHDR") != 0) {
392
-            cli_dbgmsg("PNG: first chunk must be IHDR\n");
393
-            return CL_EPARSE;
394
-        }
395
-
396
-        crc    = update_crc(CRCINIT, (uch *)chunkid, 4);
397 388
         toread = (sz > BS) ? BS : sz;
398
-        if (toread && fmap_readn(map, buffer, offset, toread) != toread) {
399
-            cli_dbgmsg("PNG: EOF while reading data\n");
400
-            return CL_EPARSE;
401
-        }
389
+    toread = fmap_readn(map, buffer, offset, toread);
402 390
         offset += toread;
403 391
 
404
-        crc = update_crc(crc, (uch *)buffer, toread);
405
-
406 392
         /*------*
407 393
          | IHDR |
408 394
          *------*/
409 395
         if (strcmp(chunkid, "IHDR") == 0) {
410
-            if (have_IHDR) {
411
-                cli_dbgmsg("PNG: multiple IHDR not allowed\n");
412
-                return CL_EPARSE;
413
-            } else if (sz != 13) {
396
+      if (sz != 13) {
414 397
                 cli_dbgmsg("PNG: invalid IHDR length\n");
415
-                return CL_EPARSE;
398
+        break;
416 399
             } else {
417
-                int compr, filt;
418
-
419 400
                 w = LG(buffer);
420 401
                 h = LG(buffer + 4);
421 402
                 if (w <= 0 || h <= 0 || w > 2147483647 || h > 2147483647) {
422 403
                     cli_dbgmsg("PNG: invalid image dimensions\n");
423
-                    return CL_EPARSE;
424
-                }
425
-                bitdepth = sampledepth = (uch)buffer[8];
426
-                ityp                   = (uch)buffer[9];
427
-                if (ityp == 1 || ityp == 5 || ityp > sizeof(png_type) / sizeof(char *)) {
428
-                    cli_dbgmsg("PNG: invalid image type (%d)\n", ityp);
429
-                    return CL_EPARSE;
404
+          break;
430 405
                 }
406
+        bitdepth = sampledepth = (unsigned char)buffer[8];
407
+        ityp = (unsigned char)buffer[9];
408
+        lace = (unsigned char)buffer[12];
431 409
                 switch (sampledepth) {
432 410
                     case 1:
433 411
                     case 2:
434 412
                     case 4:
435 413
                         if (ityp == 2 || ityp == 4 || ityp == 6) { /* RGB or GA or RGBA */
436 414
                             cli_dbgmsg("PNG: invalid sample depth (%d)\n", sampledepth);
437
-                            return CL_EPARSE;
415
+              break;
438 416
                         }
439 417
                         break;
440 418
                     case 8:
... ...
@@ -442,36 +136,12 @@ int cli_parsepng(cli_ctx *ctx)
442 442
                     case 16:
443 443
                         if (ityp == 3) { /* palette */
444 444
                             cli_dbgmsg("PNG: invalid sample depth (%d)\n", sampledepth);
445
-                            return CL_EPARSE;
445
+              break;
446 446
                         }
447 447
                         break;
448 448
                     default:
449 449
                         cli_dbgmsg("PNG: invalid sample depth (%d)\n", sampledepth);
450
-                        return CL_EPARSE;
451
-                }
452
-                compr = (uch)buffer[10];
453
-                if (compr > 127) {
454
-                    cli_dbgmsg("PNG: private (invalid?) compression method (%d)\n", compr);
455
-                    return CL_EPARSE;
456
-                } else if (compr > 0) {
457
-                    cli_dbgmsg("PNG: invalid compression method (%d)\n", compr);
458
-                    return CL_EPARSE;
459
-                }
460
-                filt = (uch)buffer[11];
461
-                if (filt > 127) {
462
-                    cli_dbgmsg("PNG: private (invalid?) filter method (%d)\n", filt);
463
-                    return CL_EPARSE;
464
-                } else if (filt > 0) {
465
-                    cli_dbgmsg("PNG: invalid filter method (%d)\n", filt);
466
-                    return CL_EPARSE;
467
-                }
468
-                lace = (uch)buffer[12];
469
-                if (lace > 127) {
470
-                    cli_dbgmsg("PNG: private (invalid?) interlace method (%d)\n", lace);
471
-                    return CL_EPARSE;
472
-                } else if (lace > 1) {
473
-                    cli_dbgmsg("PNG: invalid interlace method (%d)\n", lace);
474
-                    return CL_EPARSE;
450
+              break;
475 451
                 }
476 452
                 switch (ityp) {
477 453
                     case 2:
... ...
@@ -485,10 +155,6 @@ int cli_parsepng(cli_ctx *ctx)
485 485
                         break;
486 486
                 }
487 487
             }
488
-            have_IHDR    = 1;
489
-            last_is_IDAT = last_is_JDAT = 0;
490
-            first_idat                  = 1; /* flag:  next IDAT will be the first in this subimage */
491
-            zlib_error                  = 0; /* flag:  no zlib errors yet in this file */
492 488
                                              /* GRR 20000304:  data dump not yet compatible with interlaced images: */
493 489
             /*================================================*
494 490
              * PNG chunks (with the exception of IHDR, above) *
... ...
@@ -498,52 +164,18 @@ int cli_parsepng(cli_ctx *ctx)
498 498
              | PLTE |
499 499
              *------*/
500 500
         } else if (strcmp(chunkid, "PLTE") == 0) {
501
-            if (have_PLTE) {
502
-                cli_dbgmsg("PNG: multiple PLTE not allowed\n");
503
-                return CL_EPARSE;
504
-            } else if (ityp != 3 && ityp != 2 && ityp != 6) {
505
-                cli_dbgmsg("PNG: PLTE not allowed in %s image\n", png_type[ityp]);
506
-                return CL_EPARSE;
507
-            } else if (have_IDAT) {
508
-                cli_dbgmsg("PNG: PLTE must precede IDAT\n");
509
-                return CL_EPARSE;
510
-            } else if (have_bKGD) {
511
-                cli_dbgmsg("PNG: PLTE must precede bKGD\n");
512
-                return CL_EPARSE;
513
-            } else if (sz > 768 || sz % 3 != 0) {
514
-                cli_dbgmsg("PNG: invalid number of PLTE entries (%g)\n", (double)sz / 3);
515
-                return CL_EPARSE;
516
-            } else {
501
+      if (!(sz > 768 || sz % 3 != 0)) {
517 502
                 nplte = sz / 3;
518
-                if (((bitdepth == 1 && nplte > 2) ||
519
-                     (bitdepth == 2 && nplte > 4) || (bitdepth == 4 && nplte > 16))) {
520
-                    cli_dbgmsg("PNG: invalid number of PLTE entries (%zu) for %d-bit image\n", nplte, bitdepth);
521
-                    return CL_EPARSE;
522
-                }
523 503
             }
524 504
             if (ityp == 1) /* for MNG and tRNS */
525 505
                 ityp = 3;
526 506
             have_PLTE    = 1;
527
-            last_is_IDAT = last_is_JDAT = 0;
528
-
529
-        } else if (strcmp(chunkid, "IDAT") == 0) {
530
-            /* GRR FIXME:  need to check for consecutive IDATs within MNG segments */
531
-            if (have_IDAT && !last_is_IDAT) {
532
-                cli_dbgmsg("PNG: IDAT chunks must be consecutive\n");
533
-                return CL_EPARSE;
534
-            } else if (ityp == 3 && !have_PLTE) {
535
-                cli_dbgmsg("PNG: IDAT must follow PLTE in %s image\n", png_type[ityp]);
536
-                return CL_EPARSE;
537
-            }
538 507
 
539
-            /* We just want to check that we have read at least the minimum (10)
540
-             * IDAT bytes possible, but avoid any overflow for short ints.  We
541
-             * must also take into account that 0-length IDAT chunks are legal.
542
-             */
543
-            if (have_IDAT <= 0)
544
-                have_IDAT = (sz > 0) ? sz : -1; /* -1 as marker for IDAT(s), no data */
545
-            else if (have_IDAT < 10)
546
-                have_IDAT += (sz > 10) ? 10 : sz; /* FIXME? could cap at 10 always */
508
+    /*------*
509
+     | IDAT |
510
+     *------*/
511
+    } else if (lace == 0 && strcmp(chunkid, "IDAT") == 0) {
512
+      unsigned zlib_windowbits = 15;
547 513
 
548 514
             /* Dump the zlib header from the first two bytes. */
549 515
             if (zhead < 0x10000 && sz > 0) {
... ...
@@ -551,893 +183,108 @@ int cli_parsepng(cli_ctx *ctx)
551 551
                 if (sz > 1 && zhead < 0x10000)
552 552
                     zhead = (zhead << 8) + buffer[1];
553 553
                 if (zhead >= 0x10000) {
554
-                    /* formerly print_zlibheader(zhead & 0xffff); */
555
-                    /* See the code in zlib deflate.c that writes out the header when
556
-                       s->status is INIT_STATE.  In fact this code is based on the zlib
557
-                       specification in RFC 1950 (ftp://ds.internic.net/rfc/rfc1950.txt),
558
-                       with the implicit assumption that the zlib header *is* written (it
559
-                       always should be inside a valid PNG file).  The variable names are
560
-                       taken, verbatim, from the RFC. */
561 554
                     unsigned int CINFO = (zhead & 0xf000) >> 12;
562
-                    unsigned int CM    = (zhead & 0xf00) >> 8;
563 555
                     zlib_windowbits    = CINFO + 8;
564
-                    if ((zhead & 0xffff) % 31) {
565
-                        cli_dbgmsg("PNG: compression header fails checksum\n");
566
-                        return CL_EPARSE;
567
-                    } else if (CM != 8) {
568
-                        cli_dbgmsg("PNG: non-deflate compression method (%d)\n", CM);
569
-                        return CL_EPARSE;
570
-                    }
571 556
                 }
572 557
             }
573 558
 
574
-            if (check_zlib && !zlib_error) {
575
-                static uch *p; /* always points to next filter byte */
576
-                static int cur_y, cur_pass, cur_xoff, cur_yoff, cur_xskip, cur_yskip;
577
-                static long cur_width, cur_linebytes;
578
-                static long numfilt, numfilt_this_block, numfilt_total, numfilt_pass[7];
579
-                uch *eod;
559
+      {
560
+        int cur_xoff, cur_xskip;
561
+        unsigned long cur_width, cur_linebytes, cur_imagesize;
580 562
                 int err = Z_OK;
563
+        unsigned char* outbuf = (unsigned char *)malloc(BS);
564
+        z_stream zstrm;
565
+        size_t left_comp_read = MIN(map->len - offset + sz - 8, sz), uncomp_data = 0;
581 566
 
582 567
                 zstrm.next_in  = buffer;
583
-                zstrm.avail_in = toread;
568
+        zstrm.avail_in = MIN(toread, left_comp_read);
569
+        left_comp_read -= zstrm.avail_in;
584 570
 
585 571
                 /* initialize zlib and bit/byte/line variables if not already done */
586
-                if (first_idat) {
587
-                    zstrm.next_out = p = outbuf;
588
-                    zstrm.avail_out    = BS;
589 572
                     zstrm.zalloc       = (alloc_func)Z_NULL;
590 573
                     zstrm.zfree        = (free_func)Z_NULL;
591 574
                     zstrm.opaque       = (voidpf)Z_NULL;
592 575
                     if ((err = inflateInit2(&zstrm, zlib_windowbits)) != Z_OK) {
593 576
                         cli_dbgmsg("PNG: zlib: can't initialize (error = %d)\n", err);
594
-                        return CL_EUNPACK;
595 577
                     }
596
-                    cur_y    = 0;
597
-                    cur_pass = 1; /* interlace pass:  1 through 7 */
598
-                    cur_xoff = cur_yoff = 0;
599
-                    cur_xskip = cur_yskip = lace ? 8 : 1;
578
+        else
579
+        {
580
+          cur_xoff = 0;
581
+          cur_xskip = lace ? 8 : 1;
600 582
                     cur_width             = (w - cur_xoff + cur_xskip - 1) / cur_xskip; /* round up */
601 583
                     cur_linebytes         = ((cur_width * bitdepth + 7) >> 3) + 1;      /* round, fltr */
602
-                    numfilt               = 0L;
603
-                    first_idat            = 0;
604
-                    if (lace) { /* loop through passes to calculate total filters */
605
-                        int passm1, yskip = 0, yoff = 0, xoff = 0;
584
+          cur_imagesize = cur_linebytes * h;
606 585
 
607
-                        for (passm1 = 0; passm1 < 7; ++passm1) {
608
-                            switch (passm1) { /* (see table below for full summary) */
609
-                                case 0:
610
-                                    yskip = 8;
611
-                                    yoff  = 0;
612
-                                    xoff  = 0;
613
-                                    break;
614
-                                case 1:
615
-                                    yskip = 8;
616
-                                    yoff  = 0;
617
-                                    xoff  = 4;
618
-                                    break;
619
-                                case 2:
620
-                                    yskip = 8;
621
-                                    yoff  = 4;
622
-                                    xoff  = 0;
623
-                                    break;
624
-                                case 3:
625
-                                    yskip = 4;
626
-                                    yoff  = 0;
627
-                                    xoff  = 2;
628
-                                    break;
629
-                                case 4:
630
-                                    yskip = 4;
631
-                                    yoff  = 2;
632
-                                    xoff  = 0;
633
-                                    break;
634
-                                case 5:
635
-                                    yskip = 2;
636
-                                    yoff  = 0;
637
-                                    xoff  = 1;
638
-                                    break;
639
-                                case 6:
640
-                                    yskip = 2;
641
-                                    yoff  = 1;
642
-                                    xoff  = 0;
643
-                                    break;
644
-                            }
645
-                            /* effective height is reduced if odd pass:  subtract yoff (but
646
-                             * if effective width of pass is 0 => no rows and no filters) */
647
-                            numfilt_pass[passm1] =
648
-                                (w <= xoff) ? 0 : (h - yoff + yskip - 1) / yskip;
649
-                            if (passm1 > 0) /* now make it cumulative */
650
-                                numfilt_pass[passm1] += numfilt_pass[passm1 - 1];
651
-                        }
652
-                    } else {
653
-                        numfilt_pass[0] = h; /* if non-interlaced */
654
-                        numfilt_pass[1] = numfilt_pass[2] = numfilt_pass[3] = h;
655
-                        numfilt_pass[4] = numfilt_pass[5] = numfilt_pass[6] = h;
656
-                    }
657
-                    numfilt_total = numfilt_pass[6];
586
+          while (err != Z_STREAM_END) {
587
+            if (zstrm.avail_in == 0)
588
+            {
589
+              // The zlib stream is over. Quit the while loop
590
+              if (left_comp_read == 0)
591
+                break;
592
+
593
+              toread = MIN(sizeof(buffer), left_comp_read);
594
+              toread = fmap_readn(map, buffer, offset, toread);
595
+              offset += toread;
596
+              zstrm.next_in = buffer;
597
+              zstrm.avail_in = toread;
598
+              left_comp_read -= toread;
658 599
                 }
659
-                numfilt_this_block = 0L;
660 600
 
661
-                while (err != Z_STREAM_END && zstrm.avail_in > 0) {
662
-                    /* know zstrm.avail_out > 0:  get some image/filter data */
663
-                    err = inflate(&zstrm, Z_SYNC_FLUSH);
601
+            zstrm.next_out = outbuf;
602
+            zstrm.avail_out = BS;
603
+            err = inflate(&zstrm, Z_NO_FLUSH);
604
+            uncomp_data += (BS - zstrm.avail_out);
664 605
                     if (err != Z_OK && err != Z_STREAM_END) {
665 606
                         cli_dbgmsg("PNG: zlib: inflate error\n");
666
-                        inflateEnd(&zstrm);
667
-                        return CL_EPARSE;
668
-                    }
669
-
670
-                    /* now have uncompressed, filtered image data in outbuf */
671
-                    eod = outbuf + BS - zstrm.avail_out;
672
-                    while (p < eod) {
673
-
674
-                        if (cur_linebytes) { /* GRP 20000727:  bugfix */
675
-                            int filttype = p[0];
676
-                            if (filttype > 127) {
677
-                                if (lace > 1)
678
-                                    break; /* assume it's due to unknown interlace method */
679
-                                if (numfilt_this_block == 0) {
680
-                                    /* warn only on first one per block; don't break */
681
-                                    cli_dbgmsg("PNG: private (invalid?) row-filter type (%d)\n", filttype);
682
-                                    inflateEnd(&zstrm);
683
-                                    return CL_EPARSE;
684
-                                }
685
-                            } else if (filttype > 4) {
686
-                                if (lace <= 1) {
687
-                                    cli_dbgmsg("PNG: invalid row-filter type (%d)\n", filttype);
688
-                                    inflateEnd(&zstrm);
689
-                                    return CL_EPARSE;
690
-                                } /* else assume it's due to unknown interlace method */
691 607
                                 break;
692 608
                             }
693
-                            ++numfilt;
694
-                            p += cur_linebytes;
695 609
                         }
696
-                        cur_y += cur_yskip;
697
-
698
-                        if (lace) {
699
-                            while (cur_y >= h) { /* may loop if very short image */
700
-                                /*
701
-                                    pass  xskip yskip  xoff yoff
702
-                                      1     8     8      0    0
703
-                                      2     8     8      4    0
704
-                                      3     4     8      0    4
705
-                                      4     4     4      2    0
706
-                                      5     2     4      0    2
707
-                                      6     2     2      1    0
708
-                                      7     1     2      0    1
709
-                                 */
710
-                                ++cur_pass;
711
-                                if (cur_pass & 1) { /* beginning an odd pass */
712
-                                    cur_yoff = cur_xoff;
713
-                                    cur_xoff = 0;
714
-                                    cur_xskip >>= 1;
715
-                                } else { /* beginning an even pass */
716
-                                    if (cur_pass == 2)
717
-                                        cur_xoff = 4;
718
-                                    else {
719
-                                        cur_xoff = cur_yoff >> 1;
720
-                                        cur_yskip >>= 1;
721
-                                    }
722
-                                    cur_yoff = 0;
723
-                                }
724
-                                cur_y = cur_yoff;
725
-                                /* effective width is reduced if even pass: subtract cur_xoff */
726
-                                cur_width     = (w - cur_xoff + cur_xskip - 1) / cur_xskip;
727
-                                cur_linebytes = ((cur_width * bitdepth + 7) >> 3) + 1;
728
-                                if (cur_linebytes == 1) /* just the filter byte?  no can do */
729
-                                    cur_linebytes = 0;  /* GRP 20000727:  added fix */
730
-                            }
731
-                        } else if (cur_y >= h) {
732 610
                             inflateEnd(&zstrm);
733
-                            if (eod - p > 0) {
734
-                                cli_dbgmsg("PNG:  %u bytes remaining in buffer before inflateEnd()", (unsigned int)(eod - p));
735
-                                return CL_EPARSE;
736
-                            }
737
-                            err        = Z_STREAM_END;
738
-                            zlib_error = 1;
739
-                        }
740
-                    }
741
-                    p -= (eod - outbuf); /* wrap p back into outbuf region */
742
-                    zstrm.next_out  = outbuf;
743
-                    zstrm.avail_out = BS;
611
+          free(outbuf);
744 612
 
745
-                    /* get more input (waiting until buffer empties is not necessary best
746
-                     * zlib strategy, but simpler than shifting leftover data around) */
747
-                    if (zstrm.avail_in == 0 && sz > toread) {
748
-                        sz -= toread;
749
-                        toread = (sz > BS) ? BS : sz;
750
-                        if (fmap_readn(map, buffer, offset, toread) != toread) {
751
-                            cli_dbgmsg("PNG: EOF while reading %s data\n", chunkid);
752
-                            return CL_EPARSE;
753
-                        }
754
-                        offset += toread;
755
-                        crc            = update_crc(crc, buffer, toread);
756
-                        zstrm.next_in  = buffer;
757
-                        zstrm.avail_in = toread;
613
+          if (uncomp_data > cur_imagesize && err == Z_STREAM_END)
614
+          {
615
+            cli_append_virus(ctx, "Heuristics.CVE-2010-1205");
616
+            return CL_VIRUS;
758 617
                     }
759 618
                 }
760 619
             }
761
-            last_is_IDAT = 1;
762
-            last_is_JDAT = 0;
763 620
 
764 621
             /*------*
765 622
              | IEND |
766 623
              *------*/
767 624
         } else if (strcmp(chunkid, "IEND") == 0) {
768
-            if (have_IEND) {
769
-                cli_dbgmsg("PNG: multiple IEND not allowed\n");
770
-                return CL_EPARSE;
771
-            } else if (sz != 0) {
772
-                cli_dbgmsg("PNG: invalid IEND length\n");
773
-                return CL_EPARSE;
774
-            } else if (have_IDAT <= 0) {
775
-                cli_dbgmsg("PNG: no IDAT chunks\n");
776
-                return CL_EPARSE;
777
-            } else if (have_IDAT < 10) {
778
-                cli_dbgmsg("PNG: not enough IDAT data\n");
779
-                return CL_EPARSE;
780
-            }
781 625
             have_IEND    = 1;
782
-            last_is_IDAT = last_is_JDAT = 0;
783
-
784
-            /*------*
785
-             | bKGD |
786
-             *------*/
787
-        } else if (strcmp(chunkid, "bKGD") == 0) {
788
-            if (have_bKGD) {
789
-                cli_dbgmsg("PNG: multiple bKGD not allowed\n");
790
-                return CL_EPARSE;
791
-            } else if ((have_IDAT || have_JDAT)) {
792
-                cli_dbgmsg("PNG: bKGD must precede IDAT\n");
793
-                return CL_EPARSE;
794
-            }
795
-            switch (ityp) {
796
-                case 0:
797
-                case 4:
798
-                    if (sz != 2) {
799
-                        cli_dbgmsg("PNG: invalid bKGD length\n");
800
-                        return CL_EPARSE;
801
-                    }
802
-                    break;
803
-                case 1: /* MNG top-level chunk (default values):  "as if 16-bit RGBA" */
804
-                case 2:
805
-                case 6:
806
-                    if (sz != 6) {
807
-                        cli_dbgmsg("PNG: invalid bKGD length\n");
808
-                        return CL_EPARSE;
809
-                    }
810
-                    break;
811
-                case 3:
812
-                    if (sz != 1) {
813
-                        cli_dbgmsg("PNG: invalid bKGD length\n");
814
-                        return CL_EPARSE;
815
-                    } else if (buffer[0] >= nplte) {
816
-                        cli_dbgmsg("PNG: bKGD index falls outside PLTE\n");
817
-                        return CL_EPARSE;
818
-                    }
819 626
                     break;
820
-            }
821
-            have_bKGD    = 1;
822
-            last_is_IDAT = last_is_JDAT = 0;
823
-
824
-            /*------*
825
-             | cHRM |
826
-             *------*/
827
-        } else if (strcmp(chunkid, "cHRM") == 0) {
828
-            if (have_cHRM) {
829
-                cli_dbgmsg("PNG: multiple cHRM not allowed\n");
830
-                return CL_EPARSE;
831
-            } else if (have_PLTE) {
832
-                cli_dbgmsg("PNG: cHRM must precede PLTE\n");
833
-                return CL_EPARSE;
834
-            } else if ((have_IDAT || have_JDAT)) {
835
-                cli_dbgmsg("PNG: cHRM must precede IDAT\n");
836
-                return CL_EPARSE;
837
-            } else if (sz != 32) {
838
-                cli_dbgmsg("PNG: invalid cHRM length\n");
839
-                return CL_EPARSE;
840
-            } else {
841
-                double wx, wy, rx, ry, gx, gy, bx, by;
842
-
843
-                wx = (double)LG(buffer) / 100000;
844
-                wy = (double)LG(buffer + 4) / 100000;
845
-                rx = (double)LG(buffer + 8) / 100000;
846
-                ry = (double)LG(buffer + 12) / 100000;
847
-                gx = (double)LG(buffer + 16) / 100000;
848
-                gy = (double)LG(buffer + 20) / 100000;
849
-                bx = (double)LG(buffer + 24) / 100000;
850
-                by = (double)LG(buffer + 28) / 100000;
851
-
852
-                if (wx < 0 || wx > 0.8 || wy < 0 || wy > 0.8 || wx + wy > 1.0) {
853
-                    cli_dbgmsg("PNG: invalid cHRM white point\n");
854
-                    return CL_EPARSE;
855
-                } else if (rx < 0 || rx > 0.8 || ry < 0 || ry > 0.8 || rx + ry > 1.0) {
856
-                    cli_dbgmsg("PNG: invalid cHRM red point\n");
857
-                    return CL_EPARSE;
858
-                } else if (gx < 0 || gx > 0.8 || gy < 0 || gy > 0.8 || gx + gy > 1.0) {
859
-                    cli_dbgmsg("PNG: invalid cHRM green point\n");
860
-                    return CL_EPARSE;
861
-                } else if (bx < 0 || bx > 0.8 || by < 0 || by > 0.8 || bx + by > 1.0) {
862
-                    cli_dbgmsg("PNG: invalid cHRM blue point\n");
863
-                    return CL_EPARSE;
864
-                }
865
-            }
866
-            have_cHRM    = 1;
867
-            last_is_IDAT = last_is_JDAT = 0;
868
-
869
-            /*------*
870
-             | fRAc |
871
-             *------*/
872
-        } else if (strcmp(chunkid, "fRAc") == 0) {
873
-            last_is_IDAT = last_is_JDAT = 0;
874
-
875
-            /*------*
876
-             | gAMA |
877
-             *------*/
878
-        } else if (strcmp(chunkid, "gAMA") == 0) {
879
-            if (have_gAMA) {
880
-                cli_dbgmsg("PNG: multiple gAMA not allowed\n");
881
-                return CL_EPARSE;
882
-            } else if (have_IDAT || have_JDAT) {
883
-                cli_dbgmsg("PNG: gAMA must precede IDAT\n");
884
-                return CL_EPARSE;
885
-            } else if (have_PLTE) {
886
-                cli_dbgmsg("PNG: gAMA must precede PLTE\n");
887
-                return CL_EPARSE;
888
-            } else if (sz != 4) {
889
-                cli_dbgmsg("PNG: invalid gAMA length\n");
890
-                return CL_EPARSE;
891
-            } else if (LG(buffer) == 0) {
892
-                cli_dbgmsg("PNG: invalid gAMA value (0.0000)\n");
893
-                return CL_EPARSE;
894
-            }
895
-            have_gAMA    = 1;
896
-            last_is_IDAT = last_is_JDAT = 0;
897
-
898
-            /*------*
899
-             | gIFg |
900
-             *------*/
901
-        } else if (strcmp(chunkid, "gIFg") == 0) {
902
-            if (sz != 4) {
903
-                cli_dbgmsg("PNG: invalid gIFg length\n");
904
-                return CL_EPARSE;
905
-            }
906
-            last_is_IDAT = last_is_JDAT = 0;
907
-
908
-            /*------*
909
-             | gIFt |
910
-             *------*/
911
-        } else if (strcmp(chunkid, "gIFt") == 0) {
912
-            if (sz < 24) {
913
-                cli_dbgmsg("PNG: invalid gIFt length\n");
914
-                return CL_EPARSE;
915
-            }
916
-            last_is_IDAT = last_is_JDAT = 0;
917
-
918
-            /*------*
919
-             | gIFx |
920
-             *------*/
921
-        } else if (strcmp(chunkid, "gIFx") == 0) {
922
-            if (sz < 11) {
923
-                cli_dbgmsg("PNG: invalid gIFx length\n");
924
-                return CL_EPARSE;
925
-            }
926
-            last_is_IDAT = last_is_JDAT = 0;
927
-
928
-            /*------*
929
-             | hIST |
930
-             *------*/
931
-        } else if (strcmp(chunkid, "hIST") == 0) {
932
-            if (have_hIST) {
933
-                cli_dbgmsg("PNG: multiple hIST not allowed\n");
934
-                return CL_EPARSE;
935
-            } else if (!have_PLTE) {
936
-                cli_dbgmsg("PNG: hIST must follow PLTE\n");
937
-                return CL_EPARSE;
938
-            } else if (have_IDAT) {
939
-                cli_dbgmsg("PNG: hIST must precede IDAT\n");
940
-                return CL_EPARSE;
941
-            } else if (sz != nplte * 2) {
942
-                cli_dbgmsg("PNG: invalid number of hIST entries (%g)\n", (double)sz / 2);
943
-                return CL_EPARSE;
944
-            }
945
-            have_hIST    = 1;
946
-            last_is_IDAT = last_is_JDAT = 0;
947
-
948
-            /*------*
949
-             | iCCP |
950
-             *------*/
951
-        } else if (strcmp(chunkid, "iCCP") == 0) {
952
-            int name_len;
953
-
954
-            if (have_iCCP) {
955
-                cli_dbgmsg("PNG: multiple iCCP not allowed\n");
956
-                return CL_EPARSE;
957
-            } else if (have_sRGB) {
958
-                cli_dbgmsg("PNG: iCCP not allowed with sRGB\n");
959
-                return CL_EPARSE;
960
-            } else if (have_PLTE) {
961
-                cli_dbgmsg("PNG: iCCP must precede PLTE\n");
962
-                return CL_EPARSE;
963
-            } else if (have_IDAT || have_JDAT) {
964
-                cli_dbgmsg("PNG: iCCP must precede IDAT\n");
965
-                return CL_EPARSE;
966
-            } else if (check_keyword(buffer, toread, &name_len)) {
967
-                return CL_EPARSE;
968
-            } else {
969
-                int remainder = toread - name_len - 3;
970
-                uch compr     = buffer[name_len + 1];
971
-
972
-                if (remainder < 0) {
973
-                    cli_dbgmsg("PNG: invalid iCCP length\n");
974
-                    return CL_EPARSE;
975
-                } else if (buffer[name_len] != 0) {
976
-                    cli_dbgmsg("PNG: missing NULL after iCCP profile name\n");
977
-                    return CL_EPARSE;
978
-                } else if (compr > 0 && compr < 128) {
979
-                    cli_dbgmsg("PNG: invalid iCCP compression method (%d)\n", compr);
980
-                    return CL_EPARSE;
981
-                } else if (compr >= 128) {
982
-                    return CL_EPARSE;
983
-                }
984
-            }
985
-            have_iCCP    = 1;
986
-            last_is_IDAT = last_is_JDAT = 0;
987
-
988
-            /*------*
989
-             | iTXt |
990
-             *------*/
991
-        } else if (strcmp(chunkid, "iTXt") == 0) {
992
-            int keylen;
993
-
994
-            if (check_keyword(buffer, toread, &keylen))
995
-                return CL_EPARSE;
996
-            else {
997
-                int compressed = 0, compr = 0;
998
-
999
-                if (keylen + 1 >= BS)
1000
-                    return CL_EPARSE;
1001
-                compressed = buffer[keylen + 1];
1002
-                if (compressed < 0 || compressed > 1) {
1003
-                    cli_dbgmsg("PNG: invalid iTXt compression flag (%d)\n", compressed);
1004
-                    return CL_EPARSE;
1005
-                } else if ((compr = (uch)buffer[keylen + 2]) > 127) {
1006
-                    cli_dbgmsg("PNG: private (invalid?) iTXt compression method (%d)\n", compr);
1007
-                    return CL_EPARSE;
1008
-                } else if (compr > 0) {
1009
-                    cli_dbgmsg("PNG: invalid iTXt compression method (%d)\n", compr);
1010
-                    return CL_EPARSE;
1011
-                }
1012
-            }
1013
-            last_is_IDAT = last_is_JDAT = 0;
1014
-
1015
-            /*------*
1016
-             | oFFs |
1017
-             *------*/
1018
-        } else if (strcmp(chunkid, "oFFs") == 0) {
1019
-            if (have_oFFs) {
1020
-                cli_dbgmsg("PNG: multiple oFFs not allowed\n");
1021
-                return CL_EPARSE;
1022
-            } else if (have_IDAT || have_JDAT) {
1023
-                cli_dbgmsg("PNG: oFFs must precede IDAT\n");
1024
-                return CL_EPARSE;
1025
-            } else if (sz != 9) {
1026
-                cli_dbgmsg("PNG: invalid oFFs length\n");
1027
-                return CL_EPARSE;
1028
-            } else if (buffer[8] > 1) {
1029
-                cli_dbgmsg("PNG: invalid oFFs unit specifier (%u)\n", buffer[8]);
1030
-                return CL_EPARSE;
1031
-            }
1032
-            have_oFFs    = 1;
1033
-            last_is_IDAT = last_is_JDAT = 0;
1034
-
1035
-            /*------*
1036
-             | pCAL |
1037
-             *------*/
1038
-        } else if (strcmp(chunkid, "pCAL") == 0) {
1039
-            if (have_pCAL) {
1040
-                cli_dbgmsg("PNG: multiple pCAL not allowed\n");
1041
-                return CL_EPARSE;
1042
-            } else if (have_IDAT) {
1043
-                cli_dbgmsg("PNG: pCAL must precede IDAT\n");
1044
-                return CL_EPARSE;
1045
-            }
1046
-            have_pCAL    = 1;
1047
-            last_is_IDAT = last_is_JDAT = 0;
1048 627
 
1049 628
             /*------*
1050 629
              | pHYs |
1051 630
              *------*/
1052 631
         } else if (strcmp(chunkid, "pHYs") == 0) {
1053
-            if (have_pHYs) {
1054
-                cli_dbgmsg("PNG: multiple pHYs not allowed\n");
1055
-                return CL_EPARSE;
1056
-            } else if (have_IDAT || have_JDAT) {
1057
-                cli_dbgmsg("PNG: pHYS must precede DAT\n");
1058
-                return CL_EPARSE;
1059
-            } else if (sz != 9) {
632
+      if (sz != 9) {
633
+        // Could it be CVE-2007-2365?
1060 634
                 cli_dbgmsg("PNG: invalid pHYS length\n");
1061
-                return CL_EPARSE;
1062
-            } else if (buffer[8] > 1) {
1063
-                cli_dbgmsg("PNG: invalid pHYs unit specifier (%u)\n", buffer[8]);
1064
-                return CL_EPARSE;
1065 635
             }
1066
-            have_pHYs    = 1;
1067
-            last_is_IDAT = last_is_JDAT = 0;
1068
-
1069
-            /*------*
1070
-             | sBIT |
1071
-             *------*/
1072
-        } else if (strcmp(chunkid, "sBIT") == 0) {
1073
-            int maxbits = (ityp == 3) ? 8 : sampledepth;
1074
-
1075
-            if (have_sBIT) {
1076
-                cli_dbgmsg("PNG: multiple sBIT not allowed\n");
1077
-                return CL_EPARSE;
1078
-            } else if (have_PLTE) {
1079
-                cli_dbgmsg("PNG: sBIT must precede PLTE\n");
1080
-                return CL_EPARSE;
1081
-            } else if (have_IDAT) {
1082
-                cli_dbgmsg("PNG: sBIT must precede IDAT\n");
1083
-                return CL_EPARSE;
1084
-            }
1085
-            switch (ityp) {
1086
-                case 0:
1087
-                    if (sz != 1) {
1088
-                        cli_dbgmsg("PNG: invalid sBIT length\n");
1089
-                        return CL_EPARSE;
1090
-                    } else if (buffer[0] == 0 || buffer[0] > maxbits) {
1091
-                        cli_dbgmsg("PNG: sBIT grey bits invalid for sample image\n");
1092
-                        return CL_EPARSE;
1093
-                    }
1094
-                    break;
1095
-                case 2:
1096
-                case 3:
1097
-                    if (sz != 3) {
1098
-                        cli_dbgmsg("PNG: invalid sBIT length\n");
1099
-                        return CL_EPARSE;
1100
-                    } else if (buffer[0] == 0 || buffer[0] > maxbits) {
1101
-                        cli_dbgmsg("PNG: sBIT red bits invalid for sample image\n");
1102
-                        return CL_EPARSE;
1103
-                    } else if (buffer[1] == 0 || buffer[1] > maxbits) {
1104
-                        cli_dbgmsg("PNG: sBIT green bits invalid for sample image\n");
1105
-                        return CL_EPARSE;
1106
-                    } else if (buffer[2] == 0 || buffer[2] > maxbits) {
1107
-                        cli_dbgmsg("PNG: sBIT blue bits invalid for sample image\n");
1108
-                        return CL_EPARSE;
1109
-                    }
1110
-                    break;
1111
-                case 4:
1112
-                    if (sz != 2) {
1113
-                        cli_dbgmsg("PNG: invalid length\n");
1114
-                        return CL_EPARSE;
1115
-                    } else if (buffer[0] == 0 || buffer[0] > maxbits) {
1116
-                        cli_dbgmsg("PNG: grey bits invalid for sample image\n");
1117
-                        return CL_EPARSE;
1118
-                    } else if (buffer[1] == 0 || buffer[1] > maxbits) {
1119
-                        cli_dbgmsg("PNG: alpha bits invalid for sample image\n");
1120
-                        return CL_EPARSE;
1121
-                    }
1122
-                    break;
1123
-                case 6:
1124
-                    if (sz != 4) {
1125
-                        cli_dbgmsg("PNG: invalid sBIT length\n");
1126
-                        return CL_EPARSE;
1127
-                    } else if (buffer[0] == 0 || buffer[0] > maxbits) {
1128
-                        cli_dbgmsg("PNG: red bits invalid for sample image\n");
1129
-                        return CL_EPARSE;
1130
-                    } else if (buffer[1] == 0 || buffer[1] > maxbits) {
1131
-                        cli_dbgmsg("PNG: green bits invalid for sample image\n");
1132
-                        return CL_EPARSE;
1133
-                    } else if (buffer[2] == 0 || buffer[2] > maxbits) {
1134
-                        cli_dbgmsg("PNG: blue bits invalid for sample image\n");
1135
-                        return CL_EPARSE;
1136
-                    } else if (buffer[3] == 0 || buffer[3] > maxbits) {
1137
-                        cli_dbgmsg("PNG: alpha bits invalid for sample image\n");
1138
-                        return CL_EPARSE;
1139
-                    }
1140
-                    break;
1141
-            }
1142
-            have_sBIT    = 1;
1143
-            last_is_IDAT = last_is_JDAT = 0;
1144
-
1145
-            /*------*
1146
-             | sCAL |
1147
-             *------*/
1148
-        } else if (strcmp(chunkid, "sCAL") == 0) {
1149
-            int unittype   = buffer[0];
1150
-            uch *pPixwidth = buffer + 1, *pPixheight = NULL;
1151
-
1152
-            if (have_sCAL) {
1153
-                cli_dbgmsg("PNG: multiple sCAL not allowed\n");
1154
-                return CL_EPARSE;
1155
-            } else if (have_IDAT || have_JDAT) {
1156
-                cli_dbgmsg("PNG: sCAL must precede IDAT\n");
1157
-                return CL_EPARSE;
1158
-            } else if (sz < 4) {
1159
-                cli_dbgmsg("PNG: invalid sCAL length\n");
1160
-                return CL_EPARSE;
1161
-            } else if (unittype < 1 || unittype > 2) {
1162
-                cli_dbgmsg("PNG: invalid sCAL unit specifier (%d)\n", unittype);
1163
-                return CL_EPARSE;
1164
-            } else {
1165
-                uch *qq;
1166
-                for (qq = pPixwidth; qq < buffer + sz; ++qq) {
1167
-                    if (*qq == 0)
1168
-                        break;
1169
-                }
1170
-                if (qq == buffer + sz) {
1171
-                    cli_dbgmsg("PNG: missing sCAL null separator\n");
1172
-                    return CL_EPARSE;
1173
-                } else {
1174
-                    pPixheight = qq + 1;
1175
-                    if (pPixheight == buffer + sz || *pPixheight == 0) {
1176
-                        cli_dbgmsg("PNG: missing sCAL pixel height\n");
1177
-                        return CL_EPARSE;
1178
-                    }
1179
-                }
1180
-                for (qq = pPixheight; qq < buffer + sz; ++qq) {
1181
-                    if (*qq == 0)
1182
-                        break;
1183
-                }
1184
-                if (qq != buffer + sz) {
1185
-                    cli_dbgmsg("PNG: extra sCAL null separator\n");
1186
-                    return CL_EPARSE;
1187
-                }
1188
-                if (*pPixwidth == '-' || *pPixheight == '-') {
1189
-                    cli_dbgmsg("PNG: invalid negative sCAL value(s)\n");
1190
-                    return CL_EPARSE;
1191
-                } else if (check_ascii_float(pPixwidth, pPixheight - pPixwidth - 1) ||
1192
-                           check_ascii_float(pPixheight, buffer + sz - pPixheight)) {
1193
-                    return CL_EPARSE;
1194
-                }
1195
-            }
1196
-            have_sCAL    = 1;
1197
-            last_is_IDAT = last_is_JDAT = 0;
1198
-
1199
-            /*------*
1200
-             | sPLT |
1201
-             *------*/
1202
-        } else if (strcmp(chunkid, "sPLT") == 0) {
1203
-            int name_len;
1204
-
1205
-            if (have_IDAT) {
1206
-                cli_dbgmsg("PNG: sPLT must precede IDAT\n");
1207
-                return CL_EPARSE;
1208
-            } else if (check_keyword(buffer, toread, &name_len)) {
1209
-                return CL_EPARSE;
1210
-            } else {
1211
-                uch bps       = buffer[name_len + 1];
1212
-                int remainder = toread - name_len - 2;
1213
-                int bytes     = (bps >> 3);
1214
-                int entry_sz  = 4 * bytes + 2;
1215
-
1216
-                if (remainder < 0) {
1217
-                    cli_dbgmsg("PNG: invalid sPLT length\n");
1218
-                    return CL_EPARSE;
1219
-                } else if (buffer[name_len] != 0) {
1220
-                    cli_dbgmsg("PNG: missing NULL after sPLT palette name\n");
1221
-                    return CL_EPARSE;
1222
-                } else if (bps != 8 && bps != 16) {
1223
-                    cli_dbgmsg("PNG: invalid sPLT sample depth\n");
1224
-                    return CL_EPARSE;
1225
-                } else if (remainder % entry_sz != 0) {
1226
-                    cli_dbgmsg("PNG: invalid number of sPLT entries\n");
1227
-                    return CL_EPARSE;
1228
-                }
1229
-            }
1230
-            last_is_IDAT = last_is_JDAT = 0;
1231
-
1232
-            /*------*
1233
-             | sRGB |
1234
-             *------*/
1235
-        } else if (strcmp(chunkid, "sRGB") == 0) {
1236
-            if (have_sRGB) {
1237
-                cli_dbgmsg("PNG: multiple sRGB not allowed\n");
1238
-                return CL_EPARSE;
1239
-            } else if (have_iCCP) {
1240
-                cli_dbgmsg("PNG: sRGB not allowed with iCCP\n");
1241
-                return CL_EPARSE;
1242
-            } else if (have_PLTE) {
1243
-                cli_dbgmsg("PNG: sRGB must precede PLTE\n");
1244
-                return CL_EPARSE;
1245
-            } else if (have_IDAT || have_JDAT) {
1246
-                cli_dbgmsg("PNG: sRGB must precede IDAT\n");
1247
-                return CL_EPARSE;
1248
-            } else if (sz != 1) {
1249
-                cli_dbgmsg("PNG: invalid sRGB length\n");
1250
-                return CL_EPARSE;
1251
-            } else if (buffer[0] > 3) {
1252
-                cli_dbgmsg("PNG: sRGB invalid rendering intent\n");
1253
-                return CL_EPARSE;
1254
-            }
1255
-            have_sRGB    = 1;
1256
-            last_is_IDAT = last_is_JDAT = 0;
1257
-
1258
-            /*------*
1259
-             | sTER |
1260
-             *------*/
1261
-        } else if (strcmp(chunkid, "sTER") == 0) {
1262
-            if (have_sTER) {
1263
-                cli_dbgmsg("PNG: multiple sTER not allowed\n");
1264
-                return CL_EPARSE;
1265
-            } else if (have_IDAT || have_JDAT) {
1266
-                cli_dbgmsg("PNG: sTER must precede IDAT\n");
1267
-                return CL_EPARSE;
1268
-            } else if (sz != 1) {
1269
-                cli_dbgmsg("PNG: invalid sTER length\n");
1270
-                return CL_EPARSE;
1271
-            } else if (buffer[0] > 1) {
1272
-                cli_dbgmsg("PNG: invalid sTER layout mode\n");
1273
-                return CL_EPARSE;
1274
-            }
1275
-            have_sTER    = 1;
1276
-            last_is_IDAT = last_is_JDAT = 0;
1277
-
1278
-            /*------*  *------*
1279
-             | tEXt |  | zTXt |
1280
-             *------*  *------*/
1281
-        } else if (strcmp(chunkid, "tEXt") == 0 || strcmp(chunkid, "zTXt") == 0) {
1282
-            int ztxt = (chunkid[0] == 'z');
1283
-            int keylen;
1284
-
1285
-            if (check_keyword(buffer, toread, &keylen))
1286
-                return CL_EPARSE;
1287
-            else if (ztxt) {
1288
-                int compr = (uch)buffer[keylen + 1];
1289
-                if (compr > 127) {
1290
-                    cli_dbgmsg("PNG: private (possibly invalid) compression method\n");
1291
-                    return CL_EPARSE;
1292
-                } else if (compr > 0) {
1293
-                    cli_dbgmsg("PNG: invalid compression method\n");
1294
-                    return CL_EPARSE;
1295
-                }
1296
-            } else if (check_text(buffer + keylen + 1, toread - keylen - 1)) {
1297
-                return CL_EPARSE;
1298
-            }
1299
-            last_is_IDAT = last_is_JDAT = 0;
1300
-
1301
-            /*------*
1302
-             | tIME |
1303
-             *------*/
1304
-        } else if (strcmp(chunkid, "tIME") == 0) {
1305
-            if (have_tIME) {
1306
-                cli_dbgmsg("PNG: multiple tIME not allowed\n");
1307
-                return CL_EPARSE;
1308
-            } else if (sz != 7) {
1309
-                cli_dbgmsg("PNG: invalid tIME length\n");
1310
-                return CL_EPARSE;
1311
-            } else {
1312
-                int yr = SH(buffer);
1313
-                int mo = buffer[2];
1314
-                int dy = buffer[3];
1315
-                int hh = buffer[4];
1316
-                int mm = buffer[5];
1317
-                int ss = buffer[6];
1318
-
1319
-                if (yr < 1995) {
1320
-                    /* conversion to PNG format counts as modification... */
1321
-                    /* FIXME:  also test for future dates? (may allow current year + 1) */
1322
-                    cli_dbgmsg("PNG: invalid year\n");
1323
-                    return CL_EPARSE;
1324
-                } else if (mo < 1 || mo > 12) {
1325
-                    cli_dbgmsg("PNG: invalid month\n");
1326
-                    return CL_EPARSE;
1327
-                } else if (dy < 1 || dy > 31) {
1328
-                    /* FIXME:  also validate day given specified month? */
1329
-                    cli_dbgmsg("PNG: invalid day\n");
1330
-                    return CL_EPARSE;
1331
-                } else if (hh < 0 || hh > 23) {
1332
-                    cli_dbgmsg("PNG: invalid hour\n");
1333
-                    return CL_EPARSE;
1334
-                } else if (mm < 0 || mm > 59) {
1335
-                    cli_dbgmsg("PNG: invalid minute\n");
1336
-                    return CL_EPARSE;
1337
-                } else if (ss < 0 || ss > 60) {
1338
-                    cli_dbgmsg("PNG: invalid second\n");
1339
-                    return CL_EPARSE;
1340
-                }
1341
-                cli_dbgmsg("PNG: Time: %2d %s %4d %02d:%02d:%02d UTC\n", dy, getmonth(mo), yr, hh, mm, ss);
1342
-            }
1343
-            have_tIME    = 1;
1344
-            last_is_IDAT = last_is_JDAT = 0;
1345
-
1346 636
             /*------*
1347 637
              | tRNS |
1348 638
              *------*/
1349 639
         } else if (strcmp(chunkid, "tRNS") == 0) {
1350
-            if (have_tRNS) {
1351
-                cli_dbgmsg("PNG: multiple tRNS not allowed\n");
1352
-                return CL_EPARSE;
1353
-            } else if (ityp == 3 && !have_PLTE) {
1354
-                cli_dbgmsg("PNG: tRNS must follow PLTE\n");
1355
-                return CL_EPARSE;
1356
-            } else if (have_IDAT) {
1357
-                cli_dbgmsg("PNG: tRNS must precede IDAT\n");
1358
-                return CL_EPARSE;
1359
-            } else {
1360
-                switch (ityp) {
1361
-                    case 0:
1362
-                        if (sz != 2) {
1363
-                            cli_dbgmsg("PNG: invalid tRNS length for %s image\n", png_type[ityp]);
1364
-                            return CL_EPARSE;
640
+      if (ityp == 3)
641
+      {
642
+        if ((sz > 256 || sz > nplte) && !have_PLTE)
643
+        {
644
+          cli_append_virus(ctx, "Heuristics.CVE-2004-0597");
645
+          return CL_VIRUS;
1365 646
                         }
1366
-                        break;
1367
-                    case 2:
1368
-                        if (sz != 6) {
1369
-                            cli_dbgmsg("PNG: invalid tRNS length for %s image\n", png_type[ityp]);
1370
-                            return CL_EPARSE;
1371 647
                         }
1372
-                        break;
1373
-                    case 3:
1374
-                        if (sz > nplte) {
1375
-                            cli_dbgmsg("PNG: invalid tRNS length for %s image\n", png_type[ityp]);
1376
-                            return CL_EPARSE;
1377 648
                         }
1378
-                        break;
1379
-                    default:
1380
-                        cli_dbgmsg("PNG: tRNS not allowed in %s image\n", png_type[ityp]);
1381
-                        return CL_EPARSE;
1382
-                        break;
1383
-                }
1384
-            }
1385
-            have_tRNS    = 1;
1386
-            last_is_IDAT = last_is_JDAT = 0;
1387
-
1388
-            /*===============*
1389
-             * unknown chunk *
1390
-             *===============*/
1391
-
1392
-        } else {
1393
-            if (CRITICAL(chunkid) && SAFECOPY(chunkid)) {
1394
-                /* a critical, safe-to-copy chunk is an error */
1395
-                cli_dbgmsg("PNG: illegal critical, safe-to-copy chunk\n");
1396
-                return CL_EPARSE;
1397
-            } else if (RESERVED(chunkid)) {
1398
-                /* a chunk with the reserved bit set is an error (or spec updated) */
1399
-                cli_dbgmsg("PNG: illegal reserved-bit-set chunk\n");
1400
-                return CL_EPARSE;
1401
-            } else if (PUBLIC(chunkid)) {
1402
-                /* GRR 20050725:  all registered (public) PNG/MNG/JNG chunks are now
1403
-                 *  known to pngcheck, so any unknown public ones are invalid (or have
1404
-                 *  been proposed and approved since the last release of pngcheck) */
1405
-                cli_dbgmsg("PNG: illegal (unless recently approved) unknown, public\n");
1406
-                return CL_EPARSE;
1407
-            } else if (/* !PUBLIC(chunkid) && */ CRITICAL(chunkid)) {
1408
-                cli_dbgmsg("PNG: private, critical chunk (warning)\n");
1409
-                return CL_EPARSE; /* not an error if used only internally */
1410
-            }
1411
-            last_is_IDAT = last_is_JDAT = 0;
1412
-        }
1413 649
 
1414
-        while (sz > toread) {
1415
-            sz -= toread;
1416
-            toread = (sz > BS) ? BS : sz;
1417
-
1418
-            if (fmap_readn(map, buffer, offset, toread) != toread) {
1419
-                cli_dbgmsg("PNG: EOF while reading final data\n");
1420
-                return CL_EPARSE;
650
+    offset += (sz - toread) + 4;
1421 651
             }
1422
-            offset += toread;
1423
-            crc = update_crc(crc, (uch *)buffer, toread);
1424
-        }
1425 652
 
1426
-        filecrc = getlong(map, &offset, "CRC value");
1427
-
1428
-        if (filecrc != CRCCOMPL(crc)) {
1429
-            cli_dbgmsg("PNG: CRC error in chunk %s (computed %08lx, expected %08lx)\n",
1430
-                       chunkid, CRCCOMPL(crc), filecrc);
1431
-            return CL_EPARSE;
1432
-        }
1433
-    }
1434
-
1435
-    /*----------------------- END OF IMMENSE WHILE-LOOP -----------------------*/
1436
-
1437
-    if (!have_IEND) {
1438
-        cli_dbgmsg("PNG: file doesn't end with a IEND chunk\n");
1439
-        return CL_EPARSE;
1440
-    }
653
+  // Is there an overlay?
654
+  if (have_IEND && (map->len - (offset + 4) > 0))
655
+    return cli_map_scan(map, offset + 4, map->len - (offset + 4), ctx, CL_TYPE_ANY);
1441 656
 
1442 657
     return CL_SUCCESS;
1443 658
 }
... ...
@@ -4001,6 +4001,11 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
4001 4001
                 ret = cli_parsegif(ctx);
4002 4002
             break;
4003 4003
 
4004
+        case CL_TYPE_PNG:
4005
+            if (SCAN_HEURISTICS)
4006
+                ret = cli_parsepng(ctx);
4007
+            break;
4008
+
4004 4009
         case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
4005 4010
             if (SCAN_PARSE_PDF && (DCONF_DOC & DOC_CONF_PDF))
4006 4011
                 ret = cli_scanpdf(ctx, 0);