Description: Fix security issue CVE-2012-2836
Author: Dan Fandrich <dan@coneharvesters.com>
Origin: backport
Bug-Debian: http://bugs.debian.org/681454
Applied-Upstream: 0.6.21
Forwarded: not-needed
Last-Update: 2012-07-17
--- a/libexif/exif-data.c
+++ b/libexif/exif-data.c
@@ -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)
