Index: libexif/sources/libexif/exif-data.c |
=================================================================== |
--- libexif/sources/libexif/exif-data.c (revision 143189) |
+++ libexif/sources/libexif/exif-data.c (working copy) |
@@ -781,15 +781,15 @@ |
void |
exif_data_load_data (ExifData *data, const unsigned char *d_orig, |
- unsigned int ds_orig) |
+ unsigned int ds) |
{ |
unsigned int l; |
ExifLong offset; |
ExifShort n; |
const unsigned char *d = d_orig; |
- unsigned int ds = ds_orig, len; |
+ unsigned int len, fullds; |
- if (!data || !data->priv || !d || !ds) |
+ if (!data || !data->priv || !d || !ds) |
return; |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
@@ -807,21 +807,21 @@ |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
"Found EXIF header."); |
} else { |
- while (1) { |
- while ((d[0] == 0xff) && ds) { |
+ while (ds >= 3) { |
+ while (ds && (d[0] == 0xff)) { |
d++; |
ds--; |
} |
/* JPEG_MARKER_SOI */ |
- if (d[0] == JPEG_MARKER_SOI) { |
+ if (ds && d[0] == JPEG_MARKER_SOI) { |
d++; |
ds--; |
continue; |
} |
/* JPEG_MARKER_APP0 */ |
- if (d[0] == JPEG_MARKER_APP0) { |
+ if (ds >= 3 && d[0] == JPEG_MARKER_APP0) { |
d++; |
ds--; |
l = (d[0] << 8) | d[1]; |
@@ -833,7 +833,7 @@ |
} |
/* JPEG_MARKER_APP1 */ |
- if (d[0] == JPEG_MARKER_APP1) |
+ if (ds && d[0] == JPEG_MARKER_APP1) |
break; |
/* Unknown marker or data. Give up. */ |
@@ -841,12 +841,12 @@ |
"ExifData", _("EXIF marker not found.")); |
return; |
} |
- d++; |
- ds--; |
- if (ds < 2) { |
+ if (ds < 3) { |
LOG_TOO_SMALL; |
return; |
} |
+ d++; |
+ ds--; |
len = (d[0] << 8) | d[1]; |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
"We have to deal with %i byte(s) of EXIF data.", |
@@ -872,9 +872,18 @@ |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
"Found EXIF header."); |
- /* Byte order (offset 6, length 2) */ |
+ /* Sanity check the data length */ |
if (ds < 14) |
return; |
+ |
+ /* The JPEG APP1 section can be no longer than 64 KiB (including a |
+ 16-bit length), so cap the data length to protect against overflow |
+ in future offset calculations */ |
+ fullds = ds; |
+ if (ds > 0xfffe) |
+ ds = 0xfffe; |
+ |
+ /* Byte order (offset 6, length 2) */ |
if (!memcmp (d + 6, "II", 2)) |
data->priv->order = EXIF_BYTE_ORDER_INTEL; |
else if (!memcmp (d + 6, "MM", 2)) |
@@ -894,24 +903,25 @@ |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
"IFD 0 at %i.", (int) offset); |
+ /* Sanity check the offset, being careful about overflow */ |
+ if (offset > ds || offset + 6 + 2 > ds) |
+ return; |
+ |
/* Parse the actual exif data (usually offset 14 from start) */ |
exif_data_load_data_content (data, EXIF_IFD_0, d + 6, ds - 6, offset, 0); |
/* IFD 1 offset */ |
- if (offset + 6 + 2 > ds) { |
- return; |
- } |
n = exif_get_short (d + 6 + offset, data->priv->order); |
- if (offset + 6 + 2 + 12 * n + 4 > ds) { |
+ if (offset + 6 + 2 + 12 * n + 4 > ds) |
return; |
- } |
+ |
offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order); |
if (offset) { |
exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", |
"IFD 1 at %i.", (int) offset); |
/* Sanity check. */ |
- if (offset > ds - 6) { |
+ if (offset > ds || offset + 6 > ds) { |
exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, |
"ExifData", "Bogus offset of IFD1."); |
} else { |
@@ -925,7 +935,7 @@ |
* space between IFDs. Here is the only place where we have access |
* to that data. |
*/ |
- interpret_maker_note(data, d, ds); |
+ interpret_maker_note(data, d, fullds); |
/* Fixup tags if requested */ |
if (data->priv->options & EXIF_DATA_OPTION_FOLLOW_SPECIFICATION) |