CVE-2017-9204: Out-of-bounds Read (CWE-125)
value: The iw_get_ui16le function in imagew-util.c:405:23 in libimageworsener.a in ImageWorsener 1.3.1 allows remote attackers to cause a denial of service (invalid read and SEGV) via a crafted image, related to imagew-jpeg.c.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 6.5
Published: 2017-05-23T04:29Z
Repository: https://github.com/jsummers/imageworsener
Language: C
Files changed: src/imagew-jpeg.c
Commit date: 2017-05-14 13:53:03 -0400
Commit message: Fixed invalid memory access bugs when decoding JPEG Exif data

Fixes issues #22, #23, #24, #25

Diff: diff --git a/src/imagew-jpeg.c b/src/imagew-jpeg.c
index 43bf946..e810539 100644
--- a/src/imagew-jpeg.c
+++ b/src/imagew-jpeg.c
@@ -56,29 +56,41 @@ struct iw_exif_state {
 	int endian;
 	const iw_byte *d;
 	size_t d_len;
 };
 
+static unsigned int get_exif_ui16(struct iw_exif_state *e, unsigned int pos)
+{
+	if(e->d_len<2 || pos>e->d_len-2) return 0;
+	return iw_get_ui16_e(&e->d[pos], e->endian);
+}
+
+static unsigned int get_exif_ui32(struct iw_exif_state *e, unsigned int pos)
+{
+	if(e->d_len<4 || pos>e->d_len-4) return 0;
+	return iw_get_ui32_e(&e->d[pos], e->endian);
+}
+
 // Try to read an Exif tag into an integer.
 // Returns zero on failure.
 static int get_exif_tag_int_value(struct iw_exif_state *e, unsigned int tag_pos,
 	unsigned int *pv)
 {
 	unsigned int field_type;
 	unsigned int value_count;
 
-	field_type = iw_get_ui16_e(&e->d[tag_pos+2],e->endian);
-	value_count = iw_get_ui32_e(&e->d[tag_pos+4],e->endian);
+	field_type = get_exif_ui16(e, tag_pos+2);
+	value_count = get_exif_ui32(e, tag_pos+4);
 
 	if(value_count!=1) return 0;
 
 	if(field_type==3) { // SHORT (uint16)
-		*pv = iw_get_ui16_e(&e->d[tag_pos+8],e->endian);
+		*pv = get_exif_ui16(e, tag_pos+8);
 		return 1;
 	}
 	else if(field_type==4) { // LONG (uint32)
-		*pv = iw_get_ui32_e(&e->d[tag_pos+8],e->endian);
+		*pv = get_exif_ui32(e, tag_pos+8);
 		return 1;
 	}
 
 	return 0;
 }
@@ -91,26 +103,26 @@ static int get_exif_tag_dbl_value(struct iw_exif_state *e, unsigned int tag_pos,
 	unsigned int field_type;
 	unsigned int value_count;
 	unsigned int value_pos;
 	unsigned int numer, denom;
 
-	field_type = iw_get_ui16_e(&e->d[tag_pos+2],e->endian);
-	value_count = iw_get_ui32_e(&e->d[tag_pos+4],e->endian);
+	field_type = get_exif_ui16(e, tag_pos+2);
+	value_count = get_exif_ui32(e, tag_pos+4);
 
 	if(value_count!=1) return 0;
 
 	if(field_type!=5) return 0; // 5=Rational (two uint32's)
 
 	// A rational is 8 bytes. Since 8>4, it is stored indirectly. First, read
 	// the location where it is stored.
 
-	value_pos = iw_get_ui32_e(&e->d[tag_pos+8],e->endian);
+	value_pos = get_exif_ui32(e, tag_pos+8);
 	if(value_pos > e->d_len-8) return 0;
 
 	// Read the actual value.
-	numer = iw_get_ui32_e(&e->d[value_pos  ],e->endian);
-	denom = iw_get_ui32_e(&e->d[value_pos+4],e->endian);
+	numer = get_exif_ui32(e, value_pos);
+	denom = get_exif_ui32(e, value_pos+4);
 	if(denom==0) return 0;
 
 	*pv = ((double)numer)/denom;
 	return 1;
 }
@@ -123,19 +135,19 @@ static void iwjpeg_scan_exif_ifd(struct iwjpegrcontext *rctx,
 	unsigned int tag_pos;
 	unsigned int tag_id;
 	unsigned int v;
 	double v_dbl;
 
-	if(ifd<8 || ifd>e->d_len-18) return;
+	if(ifd<8 || e->d_len<18 || ifd>e->d_len-18) return;
 
-	tag_count = iw_get_ui16_e(&e->d[ifd],e->endian);
+	tag_count = get_exif_ui16(e, ifd);
 	if(tag_count>1000) return; // Sanity check.
 
 	for(i=0;i<tag_count;i++) {
 		tag_pos = ifd+2+i*12;
 		if(tag_pos+12 > e->d_len) return; // Avoid overruns.
-		tag_id = iw_get_ui16_e(&e->d[tag_pos],e->endian);
+		tag_id = get_exif_ui16(e, tag_pos);
 
 		switch(tag_id) {
 		case 274: // 274 = Orientation
 			if(get_exif_tag_int_value(e,tag_pos,&v)) {
 				rctx->exif_orientation = v;
@@ -175,11 +187,11 @@ static void iwjpeg_scan_exif(struct iwjpegrcontext *rctx,
 	e.d = d;
 	e.d_len = d_len;
 
 	e.endian = d[0]=='I' ? IW_ENDIAN_LITTLE : IW_ENDIAN_BIG;
 
-	ifd = iw_get_ui32_e(&d[4],e.endian);
+	ifd = get_exif_ui32(&e, 4);
 
 	iwjpeg_scan_exif_ifd(rctx,&e,ifd);
 }
 
 // Look at the saved JPEG markers.

Vulnerable code: 	field_type = iw_get_ui16_e(&e->d[tag_pos+2],e->endian);
	value_count = iw_get_ui32_e(&e->d[tag_pos+4],e->endian);
		*pv = iw_get_ui16_e(&e->d[tag_pos+8],e->endian);
		*pv = iw_get_ui32_e(&e->d[tag_pos+8],e->endian);
	field_type = iw_get_ui16_e(&e->d[tag_pos+2],e->endian);
	value_count = iw_get_ui32_e(&e->d[tag_pos+4],e->endian);
	value_pos = iw_get_ui32_e(&e->d[tag_pos+8],e->endian);
	numer = iw_get_ui32_e(&e->d[value_pos  ],e->endian);
	denom = iw_get_ui32_e(&e->d[value_pos+4],e->endian);
	if(ifd<8 || ifd>e->d_len-18) return;
	tag_count = iw_get_ui16_e(&e->d[ifd],e->endian);
		tag_id = iw_get_ui16_e(&e->d[tag_pos],e->endian);
	ifd = iw_get_ui32_e(&d[4],e.endian);
Fixed code: static unsigned int get_exif_ui16(struct iw_exif_state *e, unsigned int pos)
{
	if(e->d_len<2 || pos>e->d_len-2) return 0;
	return iw_get_ui16_e(&e->d[pos], e->endian);
}

static unsigned int get_exif_ui32(struct iw_exif_state *e, unsigned int pos)
{
	if(e->d_len<4 || pos>e->d_len-4) return 0;
	return iw_get_ui32_e(&e->d[pos], e->endian);
}

	field_type = get_exif_ui16(e, tag_pos+2);
	value_count = get_exif_ui32(e, tag_pos+4);
		*pv = get_exif_ui16(e, tag_pos+8);
		*pv = get_exif_ui32(e, tag_pos+8);
	field_type = get_exif_ui16(e, tag_pos+2);
	value_count = get_exif_ui32(e, tag_pos+4);
	value_pos = get_exif_ui32(e, tag_pos+8);
	numer = get_exif_ui32(e, value_pos);
	denom = get_exif_ui32(e, value_pos+4);
	if(ifd<8 || e->d_len<18 || ifd>e->d_len-18) return;
	tag_count = get_exif_ui16(e, ifd);
		tag_id = get_exif_ui16(e, tag_pos);
	ifd = get_exif_ui32(&e, 4);