From: Dan Fandrich Date: Fri, 25 Sep 2009 06:35:48 +0000 (-0700) Subject: Fixed some problems in MakerNote parsing that could cause a X-Git-Tag: libexif-0_6_21-release~120 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bdd5c7e0f871fa3b1d14a09ccc71c63501c675b7;p=platform%2Fupstream%2Flibexif.git Fixed some problems in MakerNote parsing that could cause a read past the end of a buffer and therefore a segfault. Allow MakerNote parsing to continue even if one tag parses incorrectly. Log an error whenever memory allocation fails in MakerNote parsing. --- diff --git a/ChangeLog b/ChangeLog index ed24902..820ab3a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-09-24 Dan Fandrich + + * Fixed some problems in MakerNote parsing that could cause a + read past the end of a buffer and therefore a segfault. + * Allow MakerNote parsing to continue even if one tag parses + incorrectly. + * Log an error whenever memory allocation fails in MakerNote parsing. + 2009-09-23 Dan Fandrich * Removed bogus "APEX" value from shutter speed display (thanks to diff --git a/NEWS b/NEWS index d628739..dc26e3c 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ libexif-0.6.x: - * Updated translations: nl, pl, sk, vi * New translation: da + * Updated translations: cs, de, en_CA, nl, pl, sk, sv, vi * Added some example programs * libexif is now thread safe when the underlying C library is thread safe and when each object allocated by libexif isn't used by more than one @@ -17,6 +17,11 @@ libexif-0.6.x: removed from a file * Changed exif_tag_get_support_level_in_ifd() to return a value when possible when the data type for the given tag is unknown + * Added support for writing Pentax and Casio type2 MakerNotes + * Improved display of Pentax and Casio type2 MakerNotes + * Completely fixed bug #1617997 to display APEX values correctly + * Stopped some crashes due to read-beyond-buffer accesses in MakerNotes + * Don't abort MakerNote parsing after the first invalid tag libexif-0.6.17 (2008-11-06): * Updated translations: cs, de, pl, sk, vi @@ -114,7 +119,7 @@ General remarks: * This file contains changes visible to users. * Small bug fixes (typos, memory leaks, ...) and feature - enhancements (new tag types, ...) are not mentionened + enhancements (new tag types, ...) are not mentioned explicitly. * Apart from that, I would like to ask committers to update this diff --git a/libexif/canon/exif-mnote-data-canon.c b/libexif/canon/exif-mnote-data-canon.c index 6a6999e..b26d075 100644 --- a/libexif/canon/exif-mnote-data-canon.c +++ b/libexif/canon/exif-mnote-data-canon.c @@ -130,7 +130,10 @@ exif_mnote_data_canon_save (ExifMnoteData *ne, */ *buf_size = 2 + n->count * 12 + 4; *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size); + return; + } /* Save the number of entries */ exif_set_short (*buf, n->order, (ExifShort) n->count); @@ -158,7 +161,10 @@ exif_mnote_data_canon_save (ExifMnoteData *ne, if (s & 1) ts += 1; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); - if (!t) return; + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts); + return; + } *buf = t; *buf_size = ts; doff = *buf_size - s; @@ -195,66 +201,85 @@ exif_mnote_data_canon_load (ExifMnoteData *ne, { ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; ExifShort c; - size_t i, o, s; - MnoteCanonEntry *t; + size_t i, tcount, o, datao = 6 + n->offset; + + if (!n || !buf || !buf_size || (datao + 2 < datao) || + (datao + 2 < 2) || (datao + 2 > buf_size)) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", "Short MakerNote"); + return; + } - if (!n || !buf || !buf_size || (buf_size < 6 + n->offset + 2)) return; + /* Read the number of tags */ + c = exif_get_short (buf + datao, n->order); + datao += 2; - /* Read the number of entries and remove old ones. */ - c = exif_get_short (buf + 6 + n->offset, n->order); + /* Remove any old entries */ exif_mnote_data_canon_clear (n); + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c); + return; + } + /* Parse the entries */ - for (i = 0; i < c; i++) { - o = 6 + 2 + n->offset + 12 * i; - if (o + 8 > buf_size) { + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteCanon", "Short MakerNote"); - return; + break; } - t = exif_mem_realloc (ne->mem, n->entries, - sizeof (MnoteCanonEntry) * (i + 1)); - if (!t) return; /* out of memory */ - n->count = i + 1; - n->entries = t; - memset (&n->entries[i], 0, sizeof (MnoteCanonEntry)); - n->entries[i].tag = exif_get_short (buf + o, n->order); - n->entries[i].format = exif_get_short (buf + o + 2, n->order); - n->entries[i].components = exif_get_long (buf + o + 4, n->order); - n->entries[i].order = n->order; + n->entries[tcount].tag = exif_get_short (buf + o, n->order); + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon", - "Loading entry 0x%x ('%s')...", n->entries[i].tag, - mnote_canon_tag_get_name (n->entries[i].tag)); + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_canon_tag_get_name (n->entries[tcount].tag)); /* * Size? If bigger than 4 bytes, the actual data is not * in the entry but somewhere else (offset). */ - s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; + s = exif_format_get_size (n->entries[tcount].format) * + n->entries[tcount].components; + n->entries[tcount].size = s; if (!s) { exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteCanon", "Invalid zero-length tag size"); - return; - } - o += 8; - if (s > 4) o = exif_get_long (buf + o, n->order) + 6; - if ((o + s < s) || (o + s < o) || (o + s > buf_size)) { - exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, - "ExifMnoteCanon", - "Tag data past end of buffer (%u > %u)", - o + s, buf_size); - return; + continue; + + } else { + size_t dataofs = o + 8; + if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6; + if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", + "Tag data past end of buffer (%u > %u)", + dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (ne->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); } - /* Sanity check */ - n->entries[i].data = exif_mem_alloc (ne->mem, sizeof (char) * s); - if (!n->entries[i].data) return; /* out of memory */ - n->entries[i].size = s; - memcpy (n->entries[i].data, buf + o, s); + /* Tag was successfully parsed */ + ++tcount; } + /* Store the count of successfully parsed tags */ + n->count = tcount; } static unsigned int @@ -325,7 +350,8 @@ exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o) if (!mem) return NULL; d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon)); - if (!d) return NULL; + if (!d) + return NULL; exif_mnote_data_construct (d, mem); diff --git a/libexif/exif-mem.c b/libexif/exif-mem.c index 7290b9d..b4d7ece 100644 --- a/libexif/exif-mem.c +++ b/libexif/exif-mem.c @@ -9,18 +9,21 @@ struct _ExifMem { ExifMemFreeFunc free_func; }; +/*! Default memory allocation function. */ static void * exif_mem_alloc_func (ExifLong ds) { return calloc ((size_t) ds, 1); } +/*! Default memory reallocation function. */ static void * exif_mem_realloc_func (void *d, ExifLong ds) { return realloc (d, (size_t) ds); } +/*! Default memory free function. */ static void exif_mem_free_func (void *d) { diff --git a/libexif/fuji/exif-mnote-data-fuji.c b/libexif/fuji/exif-mnote-data-fuji.c index 0e346e2..9f0a23b 100644 --- a/libexif/fuji/exif-mnote-data-fuji.c +++ b/libexif/fuji/exif-mnote-data-fuji.c @@ -152,63 +152,89 @@ exif_mnote_data_fuji_load (ExifMnoteData *en, { ExifMnoteDataFuji *n = (ExifMnoteDataFuji*) en; ExifLong c; - size_t i, o, s, datao = 6 + n->offset; - MnoteFujiEntry *t; + size_t i, tcount, o, datao = 6 + n->offset; if (!n || !buf || !buf_size || (datao + 12 < datao) || - (datao + 12 < 12) || (datao + 12 > buf_size)) + (datao + 12 < 12) || (datao + 12 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); return; + } - /* Read the number of entries and remove old ones. */ n->order = EXIF_BYTE_ORDER_INTEL; datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL); - if ((datao + 2 < datao) || (datao + 2 < 2)) + if ((datao + 2 < datao) || (datao + 2 < 2) || + (datao + 2 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); return; + } + + /* Read the number of tags */ c = exif_get_short (buf + datao, EXIF_BYTE_ORDER_INTEL); datao += 2; + + /* Remove any old entries */ exif_mnote_data_fuji_clear (n); - /* Parse the entries */ - for (i = 0; i < c; i++) { - o = datao + 12 * i; - if (datao + 12 > buf_size) { + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (en->mem, sizeof (MnoteFujiEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", sizeof (MnoteFujiEntry) * c); + return; + } + + /* Parse all c entries, storing ones that are successfully parsed */ + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataFuji", "Short MakerNote"); - return; + break; } - t = exif_mem_realloc (en->mem, n->entries, - sizeof (MnoteFujiEntry) * (i + 1)); - if (!t) return; - n->count = i + 1; - n->entries = t; - memset (&n->entries[i], 0, sizeof (MnoteFujiEntry)); - n->entries[i].tag = exif_get_short (buf + o, n->order); - n->entries[i].format = exif_get_short (buf + o + 2, n->order); - n->entries[i].components = exif_get_long (buf + o + 4, n->order); - n->entries[i].order = n->order; + n->entries[tcount].tag = exif_get_short (buf + o, n->order); + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; + + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_fuji_tag_get_name (n->entries[tcount].tag)); /* * Size? If bigger than 4 bytes, the actual data is not * in the entry but somewhere else (offset). */ - s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; - if (!s) return; - o += 8; - if (s > 4) o = exif_get_long (buf + o, n->order) + 6 + n->offset; - if ((o + s < o) || (o + s < s) || (o + s > buf_size)) { - exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, - "ExifMnoteDataFuji", "Tag data past end of " - "buffer (%u > %u)", o + s, buf_size); - return; + s = exif_format_get_size (n->entries[tcount].format) * n->entries[tcount].components; + n->entries[tcount].size = s; + if (s) { + size_t dataofs = o + 8; + if (s > 4) + /* The data in this case is merely a pointer */ + dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset; + if ((dataofs + s < dataofs) || (dataofs + s < s) || + (dataofs + s >= buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Tag data past end of " + "buffer (%u >= %u)", dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (en->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); } - /* Sanity check */ - n->entries[i].data = exif_mem_alloc (en->mem, s); - if (!n->entries[i].data) return; - n->entries[i].size = s; - memcpy (n->entries[i].data, buf + o, s); + /* Tag was successfully parsed */ + ++tcount; } + /* Store the count of successfully parsed tags */ + n->count = tcount; } static unsigned int diff --git a/libexif/olympus/exif-mnote-data-olympus.c b/libexif/olympus/exif-mnote-data-olympus.c index 874ef98..a954f31 100644 --- a/libexif/olympus/exif-mnote-data-olympus.c +++ b/libexif/olympus/exif-mnote-data-olympus.c @@ -109,7 +109,10 @@ exif_mnote_data_olympus_save (ExifMnoteData *ne, case sanyoV1: case epsonV1: *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } /* Write the header and the number of entries. */ strcpy ((char *)*buf, n->version==sanyoV1?"SANYO": @@ -120,7 +123,10 @@ exif_mnote_data_olympus_save (ExifMnoteData *ne, case olympusV2: *buf_size += 8-6 + 4; *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } /* Write the header and the number of entries. */ strcpy ((char *)*buf, "OLYMPUS"); @@ -143,7 +149,10 @@ exif_mnote_data_olympus_save (ExifMnoteData *ne, *buf_size += 8 + 2; *buf_size += 4; /* Next IFD pointer */ *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } /* Write the header and the number of entries. */ strcpy ((char *)*buf, "Nikon"); @@ -193,7 +202,10 @@ exif_mnote_data_olympus_save (ExifMnoteData *ne, ts = *buf_size + s; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); - if (!t) return; + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", ts); + return; + } *buf = t; *buf_size = ts; exif_set_long (*buf + o, n->order, datao + doff); @@ -216,12 +228,15 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, { ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en; ExifShort c; - size_t i, tcount, s, o, o2 = 0, datao = 6, base = 0; - - if (!n || !buf) return; + size_t i, tcount, o, o2 = 6 + n->offset, /* Start of interesting data */ + datao = 6, base = 0; - /* Start of interesting data */ - o2 = 6 + n->offset; + if (!n || !buf || !buf_size || (n->offset + 22 < n->offset) || + (n->offset + 22 < 22) || (n->offset + 22 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataOlympus", "Short MakerNote"); + return; + } /* * Olympus headers start with "OLYMP" and need to have at least @@ -244,7 +259,6 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, * two unknown bytes (0), "MM" or "II", another byte 0 and * lastly 0x2A. */ - if (buf_size - n->offset < 22) return; if (!memcmp (buf + o2, "OLYMP", 6) || !memcmp (buf + o2, "SANYO", 6) || !memcmp (buf + o2, "EPSON", 6)) { exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", @@ -262,7 +276,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, else if (buf[o2 + 6 + 1] == 1) n->order = EXIF_BYTE_ORDER_MOTOROLA; o2 += 8; - if (o2 >= buf_size) return; + if (o2 + 2 > buf_size) return; c = exif_get_short (buf + o2, n->order); if ((!(c & 0xFF)) && (c > 0x500)) { if (n->order == EXIF_BYTE_ORDER_INTEL) { @@ -309,7 +323,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, base = MNOTE_NIKON1_TAG_BASE; /* Fix endianness, if needed */ - if (o2 >= buf_size) return; + if (o2 + 2 > buf_size) return; c = exif_get_short (buf + o2, n->order); if ((!(c & 0xFF)) && (c > 0x500)) { if (n->order == EXIF_BYTE_ORDER_INTEL) { @@ -348,7 +362,7 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, o2 += 2; /* Go to where the number of entries is. */ - if (o2 >= buf_size) return; + if (o2 + 4 > buf_size) return; o2 = datao + exif_get_long (buf + o2, n->order); break; @@ -366,21 +380,32 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, return; } - /* Number of entries */ - if (o2 >= buf_size) return; + /* Sanity check the offset */ + if ((o2 + 2 < o2) || (o2 + 2 < 2) || (o2 + 2 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteOlympus", "Short MakerNote"); + return; + } + + /* Read the number of tags */ c = exif_get_short (buf + o2, n->order); o2 += 2; - /* Read the number of entries and remove old ones. */ + /* Remove any old entries */ exif_mnote_data_olympus_clear (n); + /* Reserve enough space for all the possible MakerNote tags */ n->entries = exif_mem_alloc (en->mem, sizeof (MnoteOlympusEntry) * c); - if (!n->entries) return; + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", sizeof (MnoteOlympusEntry) * c); + return; + } /* Parse all c entries, storing ones that are successfully parsed */ - for (i = c, tcount = 0, o = o2; i; --i, o += 12) { - size_t dataofs; - if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { + tcount = 0; + for (i = c, o = o2; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteOlympus", "Short MakerNote"); break; @@ -394,12 +419,12 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, mnote_olympus_tag_get_name (n->entries[tcount].tag)); - exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", +/* exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", "0x%x %d %ld*(%d)", n->entries[tcount].tag, n->entries[tcount].format, n->entries[tcount].components, - (int)exif_format_get_size(n->entries[tcount].format)); + (int)exif_format_get_size(n->entries[tcount].format)); */ /* * Size? If bigger than 4 bytes, the actual data is not @@ -409,8 +434,9 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, n->entries[tcount].components; n->entries[tcount].size = s; if (s) { - dataofs = o + 8; + size_t dataofs = o + 8; if (s > 4) { + /* The data in this case is merely a pointer */ dataofs = exif_get_long (buf + dataofs, n->order) + datao; #ifdef EXIF_OVERCOME_SANYO_OFFSET_BUG /* Some Sanyo models (e.g. VPC-C5, C40) suffer from a bug when @@ -436,9 +462,11 @@ exif_mnote_data_olympus_load (ExifMnoteData *en, continue; } - /* Sanity check */ n->entries[tcount].data = exif_mem_alloc (en->mem, s); - if (!n->entries[tcount].data) continue; + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", s); + continue; + } memcpy (n->entries[tcount].data, buf + dataofs, s); } diff --git a/libexif/pentax/exif-mnote-data-pentax.c b/libexif/pentax/exif-mnote-data-pentax.c index 099c9eb..e755ee9 100644 --- a/libexif/pentax/exif-mnote-data-pentax.c +++ b/libexif/pentax/exif-mnote-data-pentax.c @@ -95,8 +95,10 @@ exif_mnote_data_pentax_save (ExifMnoteData *ne, case casioV2: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; - + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } /* Write the magic header */ strcpy ((char *)*buf, "QVC"); exif_set_short (*buf + 4, n->order, (ExifShort) 0); @@ -106,7 +108,10 @@ exif_mnote_data_pentax_save (ExifMnoteData *ne, case pentaxV3: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } /* Write the magic header */ strcpy ((char *)*buf, "AOC"); @@ -119,7 +124,10 @@ exif_mnote_data_pentax_save (ExifMnoteData *ne, case pentaxV2: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } /* Write the magic header */ strcpy ((char *)*buf, "AOC"); @@ -132,7 +140,10 @@ exif_mnote_data_pentax_save (ExifMnoteData *ne, *buf_size -= 6; o2 -= 6; *buf = exif_mem_alloc (ne->mem, *buf_size); - if (!*buf) return; + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } break; default: @@ -170,7 +181,10 @@ exif_mnote_data_pentax_save (ExifMnoteData *ne, doff = *buf_size; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); - if (!t) return; + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", ts); + return; + } *buf = t; *buf_size = ts; exif_set_long (*buf + o, n->order, datao + doff); @@ -201,11 +215,17 @@ exif_mnote_data_pentax_load (ExifMnoteData *en, const unsigned char *buf, unsigned int buf_size) { ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en; - size_t i, o, s, datao = 6 + n->offset, base = 0; + size_t i, tcount, o, datao = 6 + n->offset, base = 0; ExifShort c; - /* Number of entries */ - if (buf_size < datao + (4 + 2) + 2) return; + if (!n || !buf || !buf_size || (datao + 8 < datao) || + (datao + 8 < 8) || (datao + 8 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataPentax", "Short MakerNote"); + return; + } + + /* Detect varient of Pentax/Casio MakerNote found */ if (!memcmp(buf + datao, "AOC", 4)) { if ((buf[datao + 4] == 'I') && (buf[datao + 5] == 'I')) { n->version = pentaxV3; @@ -233,56 +253,73 @@ exif_mnote_data_pentax_load (ExifMnoteData *en, "Parsing Pentax maker note v1..."); n->version = pentaxV1; } + + /* Read the number of tags */ c = exif_get_short (buf + datao, n->order); + datao += 2; + + /* Remove any old entries */ + exif_mnote_data_pentax_clear (n); + + /* Reserve enough space for all the possible MakerNote tags */ n->entries = exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c); - if (!n->entries) return; + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", sizeof (MnotePentaxEntry) * c); + return; + } - for (i = 0; i < c; i++) { - o = datao + 2 + 12 * i; - if (o + 8 > buf_size) { + /* Parse all c entries, storing ones that are successfully parsed */ + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataPentax", "Short MakerNote"); - return; + break; } - n->count = i + 1; - n->entries[i].tag = exif_get_short (buf + o + 0, n->order) + base; - n->entries[i].format = exif_get_short (buf + o + 2, n->order); - n->entries[i].components = exif_get_long (buf + o + 4, n->order); - n->entries[i].order = n->order; + n->entries[tcount].tag = exif_get_short (buf + o + 0, n->order) + base; + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnotePentax", - "Loading entry 0x%x ('%s')...", n->entries[i].tag, - mnote_pentax_tag_get_name (n->entries[i].tag)); + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_pentax_tag_get_name (n->entries[tcount].tag)); /* * Size? If bigger than 4 bytes, the actual data is not * in the entry but somewhere else (offset). */ - s = exif_format_get_size (n->entries[i].format) * - n->entries[i].components; - if (s > 65536) { - /* Corrupt data: EXIF data size is limited to the - * maximum size of a JPEG segment (64 kb). - */ - continue; - } - if (!s) return; - o += 8; - if (s > 4) o = exif_get_long (buf + o, n->order) + 6; - if ((o + s < o) || (o + s < s) || (o + s > buf_size)) { - exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, - "ExifMnoteDataPentax", "Tag data past end " - "of buffer (%u > %u)", o + s, buf_size); - return; + s = exif_format_get_size (n->entries[tcount].format) * + n->entries[tcount].components; + n->entries[tcount].size = s; + if (s) { + size_t dataofs = o + 8; + if (s > 4) + /* The data in this case is merely a pointer */ + dataofs = exif_get_long (buf + dataofs, n->order) + 6; + if ((dataofs + s < dataofs) || (dataofs + s < s) || + (dataofs + s > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataPentax", "Tag data past end " + "of buffer (%u > %u)", dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (en->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); } - - /* Sanity check */ - n->entries[i].data = exif_mem_alloc (en->mem, s); - if (!n->entries[i].data) return; - n->entries[i].size = s; - memcpy (n->entries[i].data, buf + o, s); - } + + /* Tag was successfully parsed */ + ++tcount; + } + /* Store the count of successfully parsed tags */ + n->count = tcount; } static unsigned int