Fixed an out of bounds read on corrupted input.
authorDan Fandrich <dan@coneharvesters.com>
Thu, 12 Jul 2012 17:13:03 +0000 (10:13 -0700)
committerDan Fandrich <dan@coneharvesters.com>
Thu, 12 Jul 2012 17:13:03 +0000 (10:13 -0700)
The EXIF_TAG_COPYRIGHT tag ought to be, but perhaps is not,
NUL-terminated.
This fixes CVE-2012-2812

libexif/exif-entry.c

index c69891d..42a68fd 100644 (file)
@@ -611,6 +611,30 @@ exif_entry_dump (ExifEntry *e, unsigned int indent)
        printf ("%s  Value: %s\n", buf, exif_entry_get_value (e, value, sizeof(value)));
 }
 
+/*! Check if a string consists entirely of a single, repeated character.
+ * Up to first n bytes are checked.
+ * 
+ * \param[in] data pointer of string to check
+ * \param[in] ch character to match
+ * \param[in] n maximum number of characters to match
+ *
+ * \return 0 if the string matches or is of zero length, nonzero otherwise
+ */
+static int
+match_repeated_char(const unsigned char *data, unsigned char ch, size_t n)
+{
+       int i;
+       for (i=n; i; --i, ++data) {
+               if (*data == 0) {
+                       i = 0;  /* all bytes before NUL matched */
+                       break;
+               }
+               if (*data != ch)
+                       break;
+       }
+       return i;
+}
+
 #define CF(entry,target,v,maxlen)                                      \
 {                                                                      \
        if (entry->format != target) {                                  \
@@ -806,7 +830,6 @@ const char *
 exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
 {
        unsigned int i, j, k;
-       const unsigned char *t;
        ExifShort v_short, v_short2, v_short3, v_short4;
        ExifByte v_byte;
        ExifRational v_rat;
@@ -948,9 +971,9 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                /*
                 * First part: Photographer.
                 * Some cameras store a string like "   " here. Ignore it.
+                * Remember that a corrupted tag might not be NUL-terminated
                 */
-               if (e->size && e->data &&
-                   (strspn ((char *)e->data, " ") != strlen ((char *) e->data)))
+               if (e->size && e->data && match_repeated_char(e->data, ' ', e->size))
                        strncpy (val, (char *) e->data, MIN (maxlen, e->size));
                else
                        strncpy (val, _("[None]"), maxlen);
@@ -959,15 +982,20 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
 
                /* Second part: Editor. */
                strncat (val, " - ", maxlen - strlen (val));
+               k = 0;
                if (e->size && e->data) {
-                       size_t ts;
-                       t = e->data + strlen ((char *) e->data) + 1;
-                       ts = e->data + e->size - t;
-                       if ((ts > 0) && (strspn ((char *)t, " ") != ts))
-                               strncat (val, (char *)t, MIN (maxlen - strlen (val), ts));
-               } else {
-                       strncat (val, _("[None]"), maxlen - strlen (val));
+                       const unsigned char *tagdata = memchr(e->data, 0, e->size);
+                       if (tagdata++) {
+                               int editor_ofs = tagdata - e->data;
+                               int remaining = e->size - editor_ofs;
+                               if (match_repeated_char(tagdata, ' ', remaining)) {
+                                       strncat (val, (const char*)tagdata, MIN (maxlen - strlen (val), remaining));
+                                       ++k;
+                               }
+                       }
                }
+               if (!k)
+                       strncat (val, _("[None]"), maxlen - strlen (val));
                strncat (val, " ", maxlen - strlen (val));
                strncat (val, _("(Editor)"), maxlen - strlen (val));