CVE-2019-9278 (published 2019-09-27T19:15Z)

In libexif, there is a possible out of bounds write due to an integer overflow. This could lead to remote escalation of privilege in the media content provider with no additional execution privileges needed. User interaction is needed for exploitation. Product: AndroidVersions: Android-10Android ID: A-112537774

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/libexif/libexif
commit_details: repo_url: https://github.com/libexif/libexif
author: Marcus Meissner
author_date: 2020-01-18 09:29:42+01:00
msg: fix CVE-2019-9278

avoid the use of unsafe integer overflow checking constructs (unsigned integer operations cannot overflow, so "u1 + u2 > u1" can be optimized away)

check for the actual sizes, which should also handle the overflows
document other places google patched, but do not seem relevant due to other restrictions

fixes https://github.com/libexif/libexif/issues/26
repository: repo_url: https://github.com/libexif/libexif
repo_name: libexif/libexif
description: A library for parsing, editing, and saving EXIF data
repo_language: C
owner: libexif
file_changes: filename: exif-data.c
change_type: ModificationType.MODIFY
diff: @@ -192,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;
 	}
 
@@ -315,13 +321,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))) {
@@ -947,7 +954,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;
 
@@ -956,6 +963,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;
 
@@ -964,8 +972,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 {

programming_language: C