CVE-2012-1571: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: file before 5.11 and libmagic allow remote attackers to cause a denial of service (crash) via a crafted Composite Document File (CDF) file that triggers (1) an out-of-bounds read or (2) an invalid pointer dereference.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2012-07-17T21:55Z
Repository: https://github.com/glensc/file
Language: C
Files changed: src/cdf.c
Commit date: 2012-02-17 04:23:30 +0000
Commit message: add more check found by cert's fuzzer.

Diff: diff --git a/src/cdf.c b/src/cdf.c
index aa2f043..c18ab9a 100644
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -33,11 +33,11 @@
  */
 
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.45 2011/08/28 08:38:48 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.46 2011/09/16 21:23:59 christos Exp $")
 #endif
 
 #include <assert.h>
 #ifdef CDF_DEBUG
 #include <err.h>
@@ -339,22 +339,29 @@ out:
 
 ssize_t
 cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
     const cdf_header_t *h, cdf_secid_t id)
 {
-	assert((size_t)CDF_SEC_SIZE(h) == len);
-	return cdf_read(info, (off_t)CDF_SEC_POS(h, id),
-	    ((char *)buf) + offs, len);
+	size_t ss = CDF_SEC_SIZE(h);
+	size_t pos = CDF_SEC_POS(h, id);
+	assert(ss == len);
+	return cdf_read(info, (off_t)pos, ((char *)buf) + offs, len);
 }
 
 ssize_t
 cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
     size_t len, const cdf_header_t *h, cdf_secid_t id)
 {
-	assert((size_t)CDF_SHORT_SEC_SIZE(h) == len);
+	size_t ss = CDF_SHORT_SEC_SIZE(h);
+	size_t pos = CDF_SHORT_SEC_POS(h, id);
+	assert(ss == len);
+	if (sst->sst_len < (size_t)id) {
+		DPRINTF(("bad sector id %d > %d\n", id, sst->sst_len));
+		return -1;
+	}
 	(void)memcpy(((char *)buf) + offs,
-	    ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len);
+	    ((const char *)sst->sst_tab) + pos, len);
 	return len;
 }
 
 /*
  * Read the sector allocation table.
@@ -866,10 +873,12 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
 				DPRINTF(("l = %d, r = %d, s = %s\n", l,
 				    CDF_ROUND(l, sizeof(l)),
 				    inp[i].pi_str.s_buf));
 				l = 4 + (uint32_t)CDF_ROUND(l, sizeof(l));
 				o += l >> 2;
+				if (q + o >= e)
+					goto out;
 				o4 = o * sizeof(uint32_t);
 			}
 			i--;
 			break;
 		case CDF_FILETIME:

Vulnerable code: FILE_RCSID("@(#)$File: cdf.c,v 1.45 2011/08/28 08:38:48 christos Exp $")
	assert((size_t)CDF_SEC_SIZE(h) == len);
	return cdf_read(info, (off_t)CDF_SEC_POS(h, id),
	    ((char *)buf) + offs, len);
	assert((size_t)CDF_SHORT_SEC_SIZE(h) == len);
	    ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len);
Fixed code: FILE_RCSID("@(#)$File: cdf.c,v 1.46 2011/09/16 21:23:59 christos Exp $")
	size_t ss = CDF_SEC_SIZE(h);
	size_t pos = CDF_SEC_POS(h, id);
	assert(ss == len);
	return cdf_read(info, (off_t)pos, ((char *)buf) + offs, len);
	size_t ss = CDF_SHORT_SEC_SIZE(h);
	size_t pos = CDF_SHORT_SEC_POS(h, id);
	assert(ss == len);
	if (sst->sst_len < (size_t)id) {
		DPRINTF(("bad sector id %d > %d\n", id, sst->sst_len));
		return -1;
	}
	    ((const char *)sst->sst_tab) + pos, len);
				if (q + o >= e)
					goto out;