Skip to content

Commit 435e21f

Browse files
dfandrichmsmeissn
authored andcommitted
Fix MakerNote tag size overflow issues at read time.
Check for a size overflow while reading tags, which ensures that the size is always consistent for the given components and type of the entry, making checking further down superfluous. This provides an alternate fix for https://sourceforge.net/p/libexif/bugs/125/ CVE-2016-6328 and for all the MakerNote types. Likely, this makes both commits 41bd042 and 89e5b1c redundant as it ensures that MakerNote entries are well-formed when they're populated. Some improvements on top by Marcus Meissner <marcus@jet.franken.de> CVE-2020-13112
1 parent a5a1f5e commit 435e21f

File tree

4 files changed

+69
-22
lines changed

4 files changed

+69
-22
lines changed

Diff for: libexif/canon/exif-mnote-data-canon.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <libexif/exif-utils.h>
3131
#include <libexif/exif-data.h>
3232

33+
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))
34+
3335
static void
3436
exif_mnote_data_canon_clear (ExifMnoteDataCanon *n)
3537
{
@@ -209,7 +211,7 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
209211
return;
210212
}
211213
datao = 6 + n->offset;
212-
if ((datao + 2 < datao) || (datao + 2 < 2) || (datao + 2 > buf_size)) {
214+
if (CHECKOVERFLOW(datao, buf_size, 2)) {
213215
exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
214216
"ExifMnoteCanon", "Short MakerNote");
215217
return;
@@ -233,11 +235,12 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
233235
tcount = 0;
234236
for (i = c, o = datao; i; --i, o += 12) {
235237
size_t s;
236-
if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
238+
239+
if (CHECKOVERFLOW(o,buf_size,12)) {
237240
exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
238241
"ExifMnoteCanon", "Short MakerNote");
239242
break;
240-
}
243+
}
241244

242245
n->entries[tcount].tag = exif_get_short (buf + o, n->order);
243246
n->entries[tcount].format = exif_get_short (buf + o + 2, n->order);
@@ -248,6 +251,16 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
248251
"Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
249252
mnote_canon_tag_get_name (n->entries[tcount].tag));
250253

254+
/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
255+
* we will check the buffer sizes closer later. */
256+
if ( exif_format_get_size (n->entries[tcount].format) &&
257+
buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
258+
) {
259+
exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
260+
"ExifMnoteCanon", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
261+
continue;
262+
}
263+
251264
/*
252265
* Size? If bigger than 4 bytes, the actual data is not
253266
* in the entry but somewhere else (offset).
@@ -264,7 +277,8 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
264277
} else {
265278
size_t dataofs = o + 8;
266279
if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6;
267-
if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) {
280+
281+
if (CHECKOVERFLOW(dataofs, buf_size, s)) {
268282
exif_log (ne->log, EXIF_LOG_CODE_DEBUG,
269283
"ExifMnoteCanon",
270284
"Tag data past end of buffer (%u > %u)",

Diff for: libexif/fuji/exif-mnote-data-fuji.c

+18-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
#include "exif-mnote-data-fuji.h"
3030

31+
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))
32+
3133
struct _MNoteFujiDataPrivate {
3234
ExifByteOrder order;
3335
};
@@ -162,16 +164,16 @@ exif_mnote_data_fuji_load (ExifMnoteData *en,
162164
return;
163165
}
164166
datao = 6 + n->offset;
165-
if ((datao + 12 < datao) || (datao + 12 < 12) || (datao + 12 > buf_size)) {
167+
if (CHECKOVERFLOW(datao, buf_size, 12)) {
166168
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
167169
"ExifMnoteDataFuji", "Short MakerNote");
168170
return;
169171
}
170172

171173
n->order = EXIF_BYTE_ORDER_INTEL;
174+
172175
datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL);
173-
if ((datao + 2 < datao) || (datao + 2 < 2) ||
174-
(datao + 2 > buf_size)) {
176+
if (CHECKOVERFLOW(datao, buf_size, 2)) {
175177
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
176178
"ExifMnoteDataFuji", "Short MakerNote");
177179
return;
@@ -195,7 +197,8 @@ exif_mnote_data_fuji_load (ExifMnoteData *en,
195197
tcount = 0;
196198
for (i = c, o = datao; i; --i, o += 12) {
197199
size_t s;
198-
if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
200+
201+
if (CHECKOVERFLOW(o, buf_size, 12)) {
199202
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
200203
"ExifMnoteDataFuji", "Short MakerNote");
201204
break;
@@ -210,6 +213,15 @@ exif_mnote_data_fuji_load (ExifMnoteData *en,
210213
"Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
211214
mnote_fuji_tag_get_name (n->entries[tcount].tag));
212215

216+
/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
217+
* we will check the buffer sizes closer later. */
218+
if ( exif_format_get_size (n->entries[tcount].format) &&
219+
buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
220+
) {
221+
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
222+
"ExifMnoteDataFuji", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
223+
continue;
224+
}
213225
/*
214226
* Size? If bigger than 4 bytes, the actual data is not
215227
* in the entry but somewhere else (offset).
@@ -221,8 +233,8 @@ exif_mnote_data_fuji_load (ExifMnoteData *en,
221233
if (s > 4)
222234
/* The data in this case is merely a pointer */
223235
dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset;
224-
if ((dataofs + s < dataofs) || (dataofs + s < s) ||
225-
(dataofs + s >= buf_size)) {
236+
237+
if (CHECKOVERFLOW(dataofs, buf_size, s)) {
226238
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
227239
"ExifMnoteDataFuji", "Tag data past end of "
228240
"buffer (%u >= %u)", (unsigned)(dataofs + s), buf_size);

Diff for: libexif/olympus/exif-mnote-data-olympus.c

+17-8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
*/
3636
/*#define EXIF_OVERCOME_SANYO_OFFSET_BUG */
3737

38+
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))
39+
3840
static enum OlympusVersion
3941
exif_mnote_data_olympus_identify_variant (const unsigned char *buf,
4042
unsigned int buf_size);
@@ -245,7 +247,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
245247
return;
246248
}
247249
o2 = 6 + n->offset; /* Start of interesting data */
248-
if ((o2 + 10 < o2) || (o2 + 10 < 10) || (o2 + 10 > buf_size)) {
250+
if (CHECKOVERFLOW(o2,buf_size,10)) {
249251
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
250252
"ExifMnoteDataOlympus", "Short MakerNote");
251253
return;
@@ -300,7 +302,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
300302
/* Olympus S760, S770 */
301303
datao = o2;
302304
o2 += 8;
303-
if ((o2 + 4 < o2) || (o2 + 4 < 4) || (o2 + 4 > buf_size)) return;
305+
if (CHECKOVERFLOW(o2,buf_size,4)) return;
304306
exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
305307
"Parsing Olympus maker note v2 (0x%02x, %02x, %02x, %02x)...",
306308
buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3]);
@@ -341,7 +343,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
341343

342344
case nikonV2:
343345
o2 += 6;
344-
if ((o2 + 12 < o2) || (o2 + 12 < 12) || (o2 + 12 > buf_size)) return;
346+
if (CHECKOVERFLOW(o2,buf_size,12)) return;
345347
exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
346348
"Parsing Nikon maker note v2 (0x%02x, %02x, %02x, "
347349
"%02x, %02x, %02x, %02x, %02x)...",
@@ -399,7 +401,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
399401
}
400402

401403
/* Sanity check the offset */
402-
if ((o2 + 2 < o2) || (o2 + 2 < 2) || (o2 + 2 > buf_size)) {
404+
if (CHECKOVERFLOW(o2,buf_size,2)) {
403405
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
404406
"ExifMnoteOlympus", "Short MakerNote");
405407
return;
@@ -423,7 +425,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
423425
tcount = 0;
424426
for (i = c, o = o2; i; --i, o += 12) {
425427
size_t s;
426-
if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
428+
if (CHECKOVERFLOW(o, buf_size, 12)) {
427429
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
428430
"ExifMnoteOlympus", "Short MakerNote");
429431
break;
@@ -444,6 +446,14 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
444446
n->entries[tcount].components,
445447
(int)exif_format_get_size(n->entries[tcount].format)); */
446448

449+
/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
450+
* we will check the buffer sizes closer later. */
451+
if (exif_format_get_size (n->entries[tcount].format) &&
452+
buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
453+
) {
454+
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteOlympus", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
455+
continue;
456+
}
447457
/*
448458
* Size? If bigger than 4 bytes, the actual data is not
449459
* in the entry but somewhere else (offset).
@@ -462,7 +472,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
462472
* tag in its MakerNote. The offset is actually the absolute
463473
* position in the file instead of the position within the IFD.
464474
*/
465-
if (dataofs + s > buf_size && n->version == sanyoV1) {
475+
if (dataofs > (buf_size - s) && n->version == sanyoV1) {
466476
/* fix pointer */
467477
dataofs -= datao + 6;
468478
exif_log (en->log, EXIF_LOG_CODE_DEBUG,
@@ -471,8 +481,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en,
471481
}
472482
#endif
473483
}
474-
if ((dataofs + s < dataofs) || (dataofs + s < s) ||
475-
(dataofs + s > buf_size)) {
484+
if (CHECKOVERFLOW(dataofs, buf_size, s)) {
476485
exif_log (en->log, EXIF_LOG_CODE_DEBUG,
477486
"ExifMnoteOlympus",
478487
"Tag data past end of buffer (%u > %u)",

Diff for: libexif/pentax/exif-mnote-data-pentax.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <libexif/exif-byte-order.h>
2929
#include <libexif/exif-utils.h>
3030

31+
#define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))
32+
3133
static void
3234
exif_mnote_data_pentax_clear (ExifMnoteDataPentax *n)
3335
{
@@ -224,7 +226,7 @@ exif_mnote_data_pentax_load (ExifMnoteData *en,
224226
return;
225227
}
226228
datao = 6 + n->offset;
227-
if ((datao + 8 < datao) || (datao + 8 < 8) || (datao + 8 > buf_size)) {
229+
if (CHECKOVERFLOW(datao, buf_size, 8)) {
228230
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
229231
"ExifMnoteDataPentax", "Short MakerNote");
230232
return;
@@ -277,7 +279,8 @@ exif_mnote_data_pentax_load (ExifMnoteData *en,
277279
tcount = 0;
278280
for (i = c, o = datao; i; --i, o += 12) {
279281
size_t s;
280-
if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
282+
283+
if (CHECKOVERFLOW(o,buf_size,12)) {
281284
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
282285
"ExifMnoteDataPentax", "Short MakerNote");
283286
break;
@@ -292,6 +295,15 @@ exif_mnote_data_pentax_load (ExifMnoteData *en,
292295
"Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
293296
mnote_pentax_tag_get_name (n->entries[tcount].tag));
294297

298+
/* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection,
299+
* we will check the buffer sizes closer later. */
300+
if ( exif_format_get_size (n->entries[tcount].format) &&
301+
buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components
302+
) {
303+
exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
304+
"ExifMnoteDataPentax", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components);
305+
break;
306+
}
295307
/*
296308
* Size? If bigger than 4 bytes, the actual data is not
297309
* in the entry but somewhere else (offset).
@@ -304,8 +316,8 @@ exif_mnote_data_pentax_load (ExifMnoteData *en,
304316
if (s > 4)
305317
/* The data in this case is merely a pointer */
306318
dataofs = exif_get_long (buf + dataofs, n->order) + 6;
307-
if ((dataofs + s < dataofs) || (dataofs + s < s) ||
308-
(dataofs + s > buf_size)) {
319+
320+
if (CHECKOVERFLOW(dataofs, buf_size, s)) {
309321
exif_log (en->log, EXIF_LOG_CODE_DEBUG,
310322
"ExifMnoteDataPentax", "Tag data past end "
311323
"of buffer (%u > %u)", (unsigned)(dataofs + s), buf_size);

0 commit comments

Comments
 (0)