CVE-2020-13114: Allocation of Resources Without Limits or Throttling (CWE-770)
value: An issue was discovered in libexif before 0.6.22. An unrestricted size in handling Canon EXIF MakerNote data could lead to consumption of large amounts of compute time for decoding EXIF data.
CWE description: The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
CVSS v3 base score: 7.5
Published: 2020-05-21T16:15Z
Repository: https://github.com/libexif/libexif
Language: C
Files changed: libexif/canon/exif-mnote-data-canon.c
Commit date: 2020-05-16 19:32:30 +0200
Commit message: Add a failsafe on the maximum number of Canon MakerNote subtags.

A malicious file could be crafted to cause extremely large values in some
tags without tripping any buffer range checks.  This is bad with the libexif
representation of Canon MakerNotes because some arrays are turned into
individual tags that the application must loop around.

The largest value I've seen for failsafe_size in a (very small) sample of valid
Canon files is <5000.  The limit is set two orders of magnitude larger to avoid
tripping up falsely in case some models use much larger values.

Patch from Google.

CVE-2020-13114

Diff: diff --git a/libexif/canon/exif-mnote-data-canon.c b/libexif/canon/exif-mnote-data-canon.c
index b8a21e16..ef4fcc63 100644
--- a/libexif/canon/exif-mnote-data-canon.c
+++ b/libexif/canon/exif-mnote-data-canon.c
@@ -30,10 +30,13 @@
 #include <libexif/exif-utils.h>
 #include <libexif/exif-data.h>
 
 #define CHECKOVERFLOW(offset,datasize,structsize) (( offset >= datasize) || (structsize > datasize) || (offset > datasize - structsize ))
 
+/* Total size limit to prevent abuse by DoS */
+#define FAILSAFE_SIZE_MAX 1000000L
+
 static void
 exif_mnote_data_canon_clear (ExifMnoteDataCanon *n)
 {
 	ExifMnoteData *d = (ExifMnoteData *) n;
 	unsigned int i;
@@ -202,10 +205,11 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
 	const unsigned char *buf, unsigned int buf_size)
 {
 	ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
 	ExifShort c;
 	size_t i, tcount, o, datao;
+	long failsafe_size = 0;
 
 	if (!n || !buf || !buf_size) {
 		exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
 			  "ExifMnoteCanon", "Short MakerNote");
 		return;
@@ -293,10 +297,27 @@ exif_mnote_data_canon_load (ExifMnoteData *ne,
 				continue;
 			}
 			memcpy (n->entries[tcount].data, buf + dataofs, s);
 		}
 
+		/* Track the size of decoded tag data. A malicious file could
+		 * be crafted to cause extremely large values here without
+		 * tripping any buffer range checks.  This is especially bad
+		 * with the libexif representation of Canon MakerNotes because
+		 * some arrays are turned into individual tags that the
+		 * application must loop around. */
+		failsafe_size += mnote_canon_entry_count_values(&n->entries[tcount]);
+
+		if (failsafe_size > FAILSAFE_SIZE_MAX) {
+			/* Abort if the total size of the data in the tags extraordinarily large, */
+			exif_mem_free (ne->mem, n->entries[tcount].data);
+			exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
+					  "ExifMnoteCanon", "Failsafe tag size overflow (%lu > %ld)",
+					  failsafe_size, FAILSAFE_SIZE_MAX);
+			break;
+		}
+
 		/* Tag was successfully parsed */
 		++tcount;
 	}
 	/* Store the count of successfully parsed tags */
 	n->count = tcount;

Fixed code: /* Total size limit to prevent abuse by DoS */
#define FAILSAFE_SIZE_MAX 1000000L

	long failsafe_size = 0;
		/* Track the size of decoded tag data. A malicious file could
		 * be crafted to cause extremely large values here without
		 * tripping any buffer range checks.  This is especially bad
		 * with the libexif representation of Canon MakerNotes because
		 * some arrays are turned into individual tags that the
		 * application must loop around. */
		failsafe_size += mnote_canon_entry_count_values(&n->entries[tcount]);

		if (failsafe_size > FAILSAFE_SIZE_MAX) {
			/* Abort if the total size of the data in the tags extraordinarily large, */
			exif_mem_free (ne->mem, n->entries[tcount].data);
			exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
					  "ExifMnoteCanon", "Failsafe tag size overflow (%lu > %ld)",
					  failsafe_size, FAILSAFE_SIZE_MAX);
			break;
		}