CVE-2017-7854: Out-of-bounds Read (CWE-125)
value: The consume_init_expr function in wasm.c in radare2 1.3.0 allows remote attackers to cause a denial of service (heap-based buffer over-read and application crash) via a crafted Web Assembly file.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 5.5
Published: 2017-04-13T16:59Z
Repository: https://github.com/radare/radare2
Language: C
Files changed: libr/bin/format/wasm/wasm.c
Commit date: 2017-04-13 15:31:24 +0200
Commit message: Fix crash in fuzzed wasm r2_hoobr_consume_init_expr

Diff: diff --git a/libr/bin/format/wasm/wasm.c b/libr/bin/format/wasm/wasm.c
index a950737fc8a..4df4802ed2d 100644
--- a/libr/bin/format/wasm/wasm.c
+++ b/libr/bin/format/wasm/wasm.c
@@ -65,15 +65,16 @@ static size_t consume_str (ut8 *buf, ut8 *max, size_t sz, char *out, ut32 *offse
 	}
 	strncpy ((char*)out, (char*)buf, R_MIN (R_BIN_WASM_STRING_LENGTH-1, sz));
 	if (offset) *offset += sz;
 	return sz;
 }
+
 static size_t consume_init_expr (ut8 *buf, ut8 *max, ut8 eoc, void *out, ut32 *offset) {
 	ut32 i = 0;
 	while (buf + i < max && buf[i] != eoc) {
 		// TODO: calc the expresion with the bytcode (ESIL?)
-		i += 1;
+		i++;
 	}
 	if (buf[i] != eoc) {
 		return 0;
 	}
 	if (offset) {
@@ -446,55 +447,54 @@ static RList *r_bin_wasm_get_code_entries (RBinWasmObj *bin, RBinWasmSection *se
 
 	return ret;
 }
 
 static RList *r_bin_wasm_get_data_entries (RBinWasmObj *bin, RBinWasmSection *sec) {
-
 	RList *ret = NULL;
 	RBinWasmDataEntry *ptr = NULL;
+	ut32 len =  sec->payload_len;
 
 	if (!(ret = r_list_newf ((RListFree)free))) {
 		return NULL;
 	}
 
 	ut8* buf = bin->buf->buf + (ut32)sec->payload_data;
-	ut32 len =  sec->payload_len;
+	int buflen = bin->buf->length - (ut32)sec->payload_data;
 	ut32 count = sec->count;
 	ut32 i = 0, r = 0;
 	size_t n = 0;
 
-	while (i < len && r < count) {
-
+	while (i < len && len < buflen && r < count) {
 		if (!(ptr = R_NEW0 (RBinWasmDataEntry))) {
 			return ret;
 		}
-
 		if (!(consume_u32 (buf + i, buf + len, &ptr->index, &i))) {
-			free (ptr);
-			return ret;
+			goto beach;
+		}
+		if (i + 4 >= buflen) {
+			goto beach;
 		}
-
 		if (!(n = consume_init_expr (buf + i, buf + len, R_BIN_WASM_END_OF_CODE, NULL, &i))) {
-			free (ptr);
-			return ret;
+			goto beach;
 		}
-
 		ptr->offset.len = n;
-
 		if (!(consume_u32 (buf + i, buf + len, &ptr->size, &i))) {	
-			free (ptr);
-			return ret;
+			goto beach;
+		}
+		if (i + 4 >= buflen) {
+			goto beach;
 		}
-
 		ptr->data = sec->payload_data + i;
 
 		r_list_append (ret, ptr);
 
 		r += 1;
 
 	}
-
+	return ret;
+beach:
+	free (ptr);
 	return ret;
 }
 
 static RBinWasmStartEntry *r_bin_wasm_get_start (RBinWasmObj *bin, RBinWasmSection *sec) {
 
@@ -591,20 +591,17 @@ static RList *r_bin_wasm_get_table_entries (RBinWasmObj *bin, RBinWasmSection *s
 }
 
 static RList *r_bin_wasm_get_global_entries (RBinWasmObj *bin, RBinWasmSection *sec) {
 	RList *ret = NULL;
 	RBinWasmGlobalEntry *ptr = NULL;
-	int buflen = bin->buf->length;
-	if (sec->payload_data + 32 > buflen) {
-		return NULL;
-	}
 
 	if (!(ret = r_list_newf ((RListFree)free))) {
 		return NULL;
 	}
 
 	ut8* buf = bin->buf->buf + (ut32)sec->payload_data;
+	int buflen = bin->buf->length - (ut32)sec->payload_data;
 	ut32 len =  sec->payload_len;
 	ut32 count = sec->count;
 	ut32 i = 0, r = 0;
 
 	while (i < len && len < buflen && r < count) {
@@ -629,60 +626,52 @@ beach:
 	free (ptr);
 	return ret;
 }
 
 static RList *r_bin_wasm_get_element_entries (RBinWasmObj *bin, RBinWasmSection *sec) {
-
 	RList *ret = NULL;
 	RBinWasmElementEntry *ptr = NULL;
 
 	if (!(ret = r_list_newf ((RListFree)free))) {
 		return NULL;
 	}
 
 	ut8* buf = bin->buf->buf + (ut32)sec->payload_data;
+	int buflen = bin->buf->length - (ut32)sec->payload_data;
 	ut32 len =  sec->payload_len;
 	ut32 count = sec->count;
 	ut32 i = 0, r = 0;
 
-	while (i < len && r < count) {
-
+	while (i < len && len < buflen && r < count) {
 		if (!(ptr = R_NEW0 (RBinWasmElementEntry))) {
 			return ret;
 		}
-
 		if (!(consume_u32 (buf + i, buf + len, &ptr->index, &i))) {
-			free (ptr);
-			return ret;
+			goto beach;
 		}
-
 		if (!(consume_init_expr (buf + i, buf + len, R_BIN_WASM_END_OF_CODE, NULL, &i))) {
-			free (ptr);
-			return ret;
+			goto beach;
 		}
-
 		if (!(consume_u32 (buf + i, buf + len, &ptr->num_elem, &i))) {
-			free (ptr);
-			return ret;
+			goto beach;
 		}
-
 		ut32 j = 0;
-		while (i < len && j < ptr->num_elem	) {
+		while (i < len && j < ptr->num_elem) {
 			// TODO: allocate space and fill entry
 			ut32 e;
 			if (!(consume_u32 (buf + i, buf + len, &e, &i))) {
 				free (ptr);
 				return ret;
 			}
 		}
-
 		r_list_append (ret, ptr);
 
 		r += 1;
-
 	}
-
+	return ret;
+beach:
+	free (ptr);
 	return ret;
 }
 
 // Public functions
 RBinWasmObj *r_bin_wasm_init (RBinFile *arch) {

Vulnerable code: 		i += 1;

	ut32 len =  sec->payload_len;
	while (i < len && r < count) {


			free (ptr);
			return ret;

			free (ptr);
			return ret;


			free (ptr);
			return ret;


	int buflen = bin->buf->length;
	if (sec->payload_data + 32 > buflen) {
		return NULL;
	}

	while (i < len && r < count) {


			free (ptr);
			return ret;

			free (ptr);
			return ret;

			free (ptr);
			return ret;

		while (i < len && j < ptr->num_elem	) {



Fixed code: 
		i++;
	ut32 len =  sec->payload_len;
	int buflen = bin->buf->length - (ut32)sec->payload_data;
	while (i < len && len < buflen && r < count) {
			goto beach;
		}
		if (i + 4 >= buflen) {
			goto beach;
			goto beach;
			goto beach;
		}
		if (i + 4 >= buflen) {
			goto beach;
	return ret;
beach:
	free (ptr);
	int buflen = bin->buf->length - (ut32)sec->payload_data;
	int buflen = bin->buf->length - (ut32)sec->payload_data;
	while (i < len && len < buflen && r < count) {
			goto beach;
			goto beach;
			goto beach;
		while (i < len && j < ptr->num_elem) {
	return ret;
beach:
	free (ptr);