X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libexif%2Fexif-data.c;h=8b280d3a2690b93a40eaba90c331cf177417ea7d;hb=cdf1e32cb71c22c3df5d806d74384b3189008a47;hp=23278f5b81ea7c40a154f1719a09d944a101e87d;hpb=a774b0d4edaf379eee2b14252e85717f1cbe55e5;p=platform%2Fupstream%2Flibexif.git diff --git a/libexif/exif-data.c b/libexif/exif-data.c index 23278f5..8b280d3 100644 --- a/libexif/exif-data.c +++ b/libexif/exif-data.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -191,9 +192,15 @@ exif_data_load_data_entry (ExifData *data, ExifEntry *entry, doff = offset + 8; /* Sanity checks */ - if ((doff + s < doff) || (doff + s < s) || (doff + s > size)) { + if (doff >= size) { exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", - "Tag data past end of buffer (%u > %u)", doff+s, size); + "Tag starts past end of buffer (%u > %u)", doff, size); + return 0; + } + + if (s > size - doff) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Tag data goes past end of buffer (%u > %u)", doff+s, size); return 0; } @@ -202,8 +209,8 @@ exif_data_load_data_entry (ExifData *data, ExifEntry *entry, entry->size = s; memcpy (entry->data, d + doff, s); } else { - /* FIXME: What do our callers do if (entry->data == NULL)? */ EXIF_LOG_NO_MEMORY(data->priv->log, "ExifData", s); + return 0; } /* If this is the MakerNote, remember the offset */ @@ -301,7 +308,9 @@ exif_data_save_data_entry (ExifData *data, ExifEntry *e, /* Write the data. Fill unneeded bytes with 0. Do not crash with * e->data is NULL */ if (e->data) { - memcpy (*d + 6 + doff, e->data, s); + unsigned int len = s; + if (e->size < s) len = e->size; + memcpy (*d + 6 + doff, e->data, len); } else { memset (*d + 6 + doff, 0, s); } @@ -314,13 +323,14 @@ exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d, unsigned int ds, ExifLong o, ExifLong s) { /* Sanity checks */ - if ((o + s < o) || (o + s < s) || (o + s > ds) || (o > ds)) { - exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", - "Bogus thumbnail offset (%u) or size (%u).", - o, s); + if (o >= ds) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Bogus thumbnail offset (%u).", o); + return; + } + if (s > ds - o) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Bogus thumbnail size (%u), max would be %u.", s, ds-o); return; } - if (data->data) exif_mem_free (data->priv->mem, data->data); if (!(data->data = exif_data_alloc (data, s))) { @@ -350,6 +360,20 @@ if (data->ifd[(i)]->count) { \ break; \ } +/*! Calculate the recursion cost added by one level of IFD loading. + * + * The work performed is related to the cost in the exponential relation + * work=1.1**cost + */ +static unsigned int +level_cost(unsigned int n) +{ + static const double log_1_1 = 0.09531017980432493; + + /* Adding 0.1 protects against the case where n==1 */ + return ceil(log(n + 0.1)/log_1_1); +} + /*! Load data for an IFD. * * \param[in,out] data #ExifData @@ -357,13 +381,13 @@ if (data->ifd[(i)]->count) { \ * \param[in] d pointer to buffer containing raw IFD data * \param[in] ds size of raw data in buffer at \c d * \param[in] offset offset into buffer at \c d at which IFD starts - * \param[in] recursion_depth number of times this function has been - * recursively called without returning + * \param[in] recursion_cost factor indicating how expensive this recursive + * call could be */ static void exif_data_load_data_content (ExifData *data, ExifIfd ifd, const unsigned char *d, - unsigned int ds, unsigned int offset, unsigned int recursion_depth) + unsigned int ds, unsigned int offset, unsigned int recursion_cost) { ExifLong o, thumbnail_offset = 0, thumbnail_length = 0; ExifShort n; @@ -378,9 +402,20 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd, if ((((int)ifd) < 0) || ( ((int)ifd) >= EXIF_IFD_COUNT)) return; - if (recursion_depth > 12) { + if (recursion_cost > 170) { + /* + * recursion_cost is a logarithmic-scale indicator of how expensive this + * recursive call might end up being. It is an indicator of the depth of + * recursion as well as the potential for worst-case future recursive + * calls. Since it's difficult to tell ahead of time how often recursion + * will occur, this assumes the worst by assuming every tag could end up + * causing recursion. + * The value of 170 was chosen to limit typical EXIF structures to a + * recursive depth of about 6, but pathological ones (those with very + * many tags) to only 2. + */ exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", - "Deep recursion detected!"); + "Deep/expensive recursion detected!"); return; } @@ -413,6 +448,11 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd, case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: o = exif_get_long (d + offset + 12 * i + 8, data->priv->order); + if (o >= ds) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", + "Tag data past end of buffer (%u > %u)", offset+2, ds); + return; + } /* FIXME: IFD_POINTER tags aren't marked as being in a * specific IFD, so exif_tag_get_name_in_ifd won't work */ @@ -422,15 +462,18 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd, switch (tag) { case EXIF_TAG_EXIF_IFD_POINTER: CHECK_REC (EXIF_IFD_EXIF); - exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, recursion_depth + 1); + exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, + recursion_cost + level_cost(n)); break; case EXIF_TAG_GPS_INFO_IFD_POINTER: CHECK_REC (EXIF_IFD_GPS); - exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, recursion_depth + 1); + exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, + recursion_cost + level_cost(n)); break; case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: CHECK_REC (EXIF_IFD_INTEROPERABILITY); - exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, recursion_depth + 1); + exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, + recursion_cost + level_cost(n)); break; case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: thumbnail_offset = o; @@ -477,6 +520,11 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd, break; } entry = exif_entry_new_mem (data->priv->mem); + if (!entry) { + exif_log (data->priv->log, EXIF_LOG_CODE_NO_MEMORY, "ExifData", + "Could not allocate memory"); + return; + } if (exif_data_load_data_entry (data, entry, d, ds, offset + 12 * i)) exif_content_add_entry (data->ifd[ifd], entry); @@ -835,7 +883,7 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig, is only relevant for files that are nonconformant to the EXIF specification. For conformant files, the APP1 code path above will be taken. */ - if (ds >= 3 && d[0] >= 0xe0 && d[0] <= 0xef) { // JPEG_MARKER_APPn + if (ds >= 3 && d[0] >= 0xe0 && d[0] <= 0xef) { /* JPEG_MARKER_APPn */ d++; ds--; l = (d[0] << 8) | d[1]; @@ -913,7 +961,7 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig, exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "IFD 0 at %i.", (int) offset); - /* Sanity check the offset, being careful about overflow */ + /* ds is restricted to 16 bit above, so offset is restricted too, and offset+8 should not overflow. */ if (offset > ds || offset + 6 + 2 > ds) return; @@ -922,6 +970,7 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig, /* IFD 1 offset */ n = exif_get_short (d + 6 + offset, data->priv->order); + /* offset < 2<<16, n is 16 bit at most, so this op will not overflow */ if (offset + 6 + 2 + 12 * n + 4 > ds) return; @@ -930,8 +979,8 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig, exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "IFD 1 at %i.", (int) offset); - /* Sanity check. */ - if (offset > ds || offset + 6 > ds) { + /* Sanity check. ds is ensured to be above 6 above, offset is 16bit */ + if (offset > ds - 6) { exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", "Bogus offset of IFD1."); } else { @@ -1085,7 +1134,7 @@ exif_data_dump (ExifData *data) } if (data->data) { - printf ("%i byte(s) thumbnail data available.", data->size); + printf ("%i byte(s) thumbnail data available: ", data->size); if (data->size >= 4) { printf ("0x%02x 0x%02x ... 0x%02x 0x%02x\n", data->data[0], data->data[1],