[Bf-blender-cvs] [7b8b621c1db] blender-v2.79a-release: Fix SGI foramt reader CVE-2017-2901

Campbell Barton noreply at git.blender.org
Fri Jan 12 11:14:33 CET 2018


Commit: 7b8b621c1db4027ef451cb67c0a91ac6bbd51454
Author: Campbell Barton
Date:   Sun Sep 17 16:22:56 2017 +1000
Branches: blender-v2.79a-release
https://developer.blender.org/rB7b8b621c1db4027ef451cb67c0a91ac6bbd51454

Fix SGI foramt reader CVE-2017-2901

Integer Overflow Code Execution Vulnerability.

Reader no longer crashes on corrupt images (from own fuzz testing).

===================================================================

M	source/blender/imbuf/intern/iris.c

===================================================================

diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 385ed338a5f..f492821a479 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -109,10 +109,14 @@ typedef struct MFileOffset {
 	uint _file_offset;
 } MFileOffset;
 
-#define MFILE_DATA(inf) ((void)0, (inf)->_file_data + (inf)->_file_offset)
+#define MFILE_DATA(inf) ((void)0, ((inf)->_file_data + (inf)->_file_offset))
 #define MFILE_STEP(inf, step) { (inf)->_file_offset += step; } ((void)0)
 #define MFILE_SEEK(inf, pos)  { (inf)->_file_offset  = pos;  } ((void)0)
 
+/* error flags */
+#define DIRTY_FLAG_EOF (1 << 0)
+#define DIRTY_FLAG_ENCODING (1 << 1)
+
 /* funcs */
 static void readheader(MFileOffset *inf, IMAGE *image);
 static int writeheader(FILE *outf, IMAGE *image);
@@ -124,8 +128,8 @@ static int putlong(FILE *outf, uint val);
 static int writetab(FILE *outf, uint *tab, int len);
 static void readtab(MFileOffset *inf, uint *tab, int len);
 
-static void expandrow(uchar *optr, const uchar *iptr, int z);
-static void expandrow2(float *optr, const uchar *iptr, int z);
+static int expandrow(uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
+static int expandrow2(float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
 static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
 static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
 static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt);
@@ -265,40 +269,46 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 	float *fbase, *fptr = NULL;
 	uint *zbase, *zptr;
 	const uchar *rledat;
-	uint *starttab, *lengthtab;
+	const uchar *mem_end = mem + size;
 	MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data;
 	IMAGE image;
 	int x, y, z, tablen;
-	int xsize, ysize, zsize;
 	int bpp, rle, cur, badorder;
 	ImBuf *ibuf;
+	uchar dirty_flag = 0;
 
-	(void)size; /* unused */
-	
-	if (!imb_is_a_iris(mem)) return NULL;
+	if (size < HEADER_SIZE) {
+		return NULL;
+	}
+
+	if (!imb_is_a_iris(mem)) {
+		return NULL;
+	}
 
 	/* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */
 	colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
 
-	/*printf("new iris\n");*/
-	
 	readheader(inf, &image);
 	if (image.imagic != IMAGIC) {
 		fprintf(stderr, "longimagedata: bad magic number in image file\n");
 		return(NULL);
 	}
-	
+
 	rle = ISRLE(image.type);
 	bpp = BPP(image.type);
 	if (bpp != 1 && bpp != 2) {
 		fprintf(stderr, "longimagedata: image must have 1 or 2 byte per pix chan\n");
 		return(NULL);
 	}
-	
-	xsize = image.xsize;
-	ysize = image.ysize;
-	zsize = image.zsize;
-	
+	if ((uint)image.zsize > 8) {
+		fprintf(stderr, "longimagedata: channels over 8 not supported\n");
+		return(NULL);
+	}
+
+	const int xsize = image.xsize;
+	const int ysize = image.ysize;
+	const int zsize = image.zsize;
+
 	if (flags & IB_test) {
 		ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0);
 		if (ibuf) ibuf->ftype = IMB_FTYPE_IMAGIC;
@@ -306,12 +316,17 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 	}
 	
 	if (rle) {
-		
 		tablen = ysize * zsize * sizeof(int);
-		starttab = (uint *)MEM_mallocN(tablen, "iris starttab");
-		lengthtab = (uint *)MEM_mallocN(tablen, "iris endtab");
 		MFILE_SEEK(inf, HEADER_SIZE);
-		
+
+		uint *starttab = MEM_mallocN(tablen, "iris starttab");
+		uint *lengthtab = MEM_mallocN(tablen, "iris endtab");
+
+#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
+		if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_rle; } ((void)0)
+
+		MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(MFILE_DATA(inf) + ((4 * 2) * tablen));
+
 		readtab(inf, starttab, tablen);
 		readtab(inf, lengthtab, tablen);
 	
@@ -344,9 +359,11 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 						MFILE_SEEK(inf, starttab[y + z * ysize]);
 						rledat = MFILE_DATA(inf);
 						MFILE_STEP(inf, lengthtab[y + z * ysize]);
-						
-						expandrow((uchar *)lptr, rledat, 3 - z);
-						lptr += xsize;
+						const uchar *rledat_next = MFILE_DATA(inf);
+						uint *lptr_next = lptr + xsize;
+						MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+						dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
+						lptr = lptr_next;
 					}
 				}
 			}
@@ -354,17 +371,25 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 				lptr = base;
 				zptr = zbase;
 				for (y = 0; y < ysize; y++) {
-				
+
+					uint *lptr_next = lptr + xsize;
+					uint *zptr_next = zptr + xsize;
+
 					for (z = 0; z < zsize; z++) {
 						MFILE_SEEK(inf, starttab[y + z * ysize]);
 						rledat = MFILE_DATA(inf);
 						MFILE_STEP(inf, lengthtab[y + z * ysize]);
-						
-						if (z < 4) expandrow((uchar *)lptr, rledat, 3 - z);
-						else if (z < 8) expandrow((uchar *)zptr, rledat, 7 - z);
+						const uchar *rledat_next = MFILE_DATA(inf);
+						MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+						if (z < 4) {
+							dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
+						}
+						else if (z < 8) {
+							dirty_flag |= expandrow((uchar *)zptr, (uchar *)zptr_next, rledat, rledat_next, 7 - z);
+						}
 					}
-					lptr += xsize;
-					zptr += xsize;
+					lptr = lptr_next;
+					zptr = zptr_next;
 				}
 			}
 			
@@ -383,14 +408,17 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 						MFILE_SEEK(inf, starttab[y + z * ysize]);
 						rledat = MFILE_DATA(inf);
 						MFILE_STEP(inf, lengthtab[y + z * ysize]);
-						
-						expandrow2(fptr, rledat, 3 - z);
-						fptr += xsize * 4;
+						const uchar *rledat_next = MFILE_DATA(inf);
+						MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+						float *fptr_next = fptr + (xsize * 4);
+						dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
+						fptr = fptr_next;
 					}
 				}
 			}
 			else {
 				fptr = fbase;
+				float *fptr_next = fptr + (xsize * 4);
 
 				for (y = 0; y < ysize; y++) {
 				
@@ -398,20 +426,24 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 						MFILE_SEEK(inf, starttab[y + z * ysize]);
 						rledat = MFILE_DATA(inf);
 						MFILE_STEP(inf, lengthtab[y + z * ysize]);
-						
-						expandrow2(fptr, rledat, 3 - z);
-						
+						const uchar *rledat_next = MFILE_DATA(inf);
+						MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next);
+						dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
 					}
-					fptr += xsize * 4;
+					fptr = fptr_next;
 				}
 			}
 		}
-		
+#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
+fail_rle:
 		MEM_freeN(starttab);
 		MEM_freeN(lengthtab);
-
 	}
 	else {
+
+#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
+		if (UNLIKELY((p) > mem_end)) { dirty_flag |= DIRTY_FLAG_EOF; goto fail_uncompressed; } ((void)0)
+
 		if (bpp == 1) {
 			
 			ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
@@ -427,12 +459,13 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 				
 				if (z < 4) lptr = base;
 				else if (z < 8) lptr = zbase;
-				
-				for (y = 0; y < ysize; y++) {
 
-					interleaverow((uchar *)lptr, rledat, 3 - z, xsize);
-					rledat += xsize;
-					
+				for (y = 0; y < ysize; y++) {
+					const uchar *rledat_next = rledat + xsize;
+					const int z_ofs = 3 - z;
+					MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
+					interleaverow((uchar *)lptr, rledat, z_ofs, xsize);
+					rledat = rledat_next;
 					lptr += xsize;
 				}
 			}
@@ -450,20 +483,23 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 			for (z = 0; z < zsize; z++) {
 				
 				fptr = fbase;
-				
-				for (y = 0; y < ysize; y++) {
 
-					interleaverow2(fptr, rledat, 3 - z, xsize);
-					rledat += xsize * 2;
-					
+				for (y = 0; y < ysize; y++) {
+					const uchar *rledat_next = rledat + xsize * 2;
+					const int z_ofs = 3 - z;
+					MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
+					interleaverow2(fptr, rledat, z_ofs, xsize);
+					rledat = rledat_next;
 					fptr += xsize * 4;
 				}
 			}
 			
 		}
+#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
+fail_uncompressed:
+		(void)0;
 	}
-	
-	
+
 	if (bpp == 1) {
 		uchar *rect;
 		
@@ -528,6 +564,9 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
 		
 	}
 
+	if (dirty_flag) {
+		fprintf(stderr, "longimagedata: corrupt file content (%d)\n", dirty_flag);
+	}
 	ibuf->ftype = IMB_FTYPE_IMAGIC;
 
 	test_endian_zbuf(ibuf);
@@ -560,19 +599,34 @@ static void interleaverow2(float *lptr, const uchar *cptr, int z, int n)
 	}
 }
 
-static void expandrow2(float *optr, const uchar *iptr, int z)
+static int expandrow2(
+        float *optr, const float *optr_end,
+        const uchar *iptr, const uchar *iptr_end, int z)
 {
 	ushort pixel, count;
 	float pixel_f;
 
+#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \
+	if (UNLIKELY(iptr_next > iptr_end)) { goto fail; }
+
+#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \
+	if (UNLIKELY(optr_next > optr_end)) { goto fail; }
+
 	optr += z;
+	optr_end += z;
 	while (1) {
+		const uchar *iptr_next = iptr + 2;
+		EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
 		pixel = (iptr[0] << 8) | (iptr[1] << 0);
-		iptr += 2;
-		
+		iptr = iptr_next;
+
 		if (!(count = (pixel & 0x7f)) )
-			return;
+			return false;
+		const float *optr_next = optr + count;
+		EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next);
 		if (pixel & 0x80) {
+			iptr_next = iptr + (count * 2);
+			EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
 			while (count >= 8) {
 				optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
 				optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / (float)0xFFFF;
@@ -591,10 +645,13 @@ static void expandrow2(float *optr, const uchar *iptr, int z)
 				iptr += 2;
 				optr += 4;
 			}
+			BLI_assert(iptr == iptr_next);
 		}
 		else {
+			iptr_next = iptr + 2;
+			EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next);
 			pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / (fl

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list