Fixed some problems in MakerNote parsing that could cause a
authorDan Fandrich <dan@coneharvesters.com>
Fri, 25 Sep 2009 06:35:48 +0000 (23:35 -0700)
committerDan Fandrich <dan@coneharvesters.com>
Fri, 25 Sep 2009 06:35:48 +0000 (23:35 -0700)
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.

ChangeLog
NEWS
libexif/canon/exif-mnote-data-canon.c
libexif/exif-mem.c
libexif/fuji/exif-mnote-data-fuji.c
libexif/olympus/exif-mnote-data-olympus.c
libexif/pentax/exif-mnote-data-pentax.c

index ed24902..820ab3a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-09-24  Dan Fandrich <dan@coneharvesters.com>
+
+       * 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 <dan@coneharvesters.com>
 
        * Removed bogus "APEX" value from shutter speed display (thanks to
diff --git a/NEWS b/NEWS
index d628739..dc26e3c 100644 (file)
--- 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
index 6a6999e..b26d075 100644 (file)
@@ -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);
 
index 7290b9d..b4d7ece 100644 (file)
@@ -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)
 {
index 0e346e2..9f0a23b 100644 (file)
@@ -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
index 874ef98..a954f31 100644 (file)
@@ -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);
                }
 
index 099c9eb..e755ee9 100644 (file)
@@ -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