CVE-2017-7854 (published 2017-04-13T16:59Z)

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.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/radare/radare2
commit_details: repo_url: https://github.com/radare/radare2
author: pancake
author_date: 2017-04-13 15:31:24+02:00
msg: Fix crash in fuzzed wasm r2_hoobr_consume_init_expr
repository: repo_url: https://github.com/radare/radare2
repo_name: radareorg/radare2
description: UNIX-like reverse engineering framework and command-line toolset
repo_language: C
owner: radare
file_changes: filename: wasm.c
change_type: ModificationType.MODIFY
diff: @@ -67,11 +67,12 @@ static size_t consume_str (ut8 *buf, ut8 *max, size_t sz, char *out, ut32 *offse
 	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;
@@ -448,43 +449,40 @@ static RList *r_bin_wasm_get_code_entries (RBinWasmObj *bin, RBinWasmSection *se
 }
 
 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);
@@ -492,7 +490,9 @@ static RList *r_bin_wasm_get_data_entries (RBinWasmObj *bin, RBinWasmSection *se
 		r += 1;
 
 	}
-
+	return ret;
+beach:
+	free (ptr);
 	return ret;
 }
 
@@ -593,16 +593,13 @@ 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;
@@ -631,7 +628,6 @@ beach:
 }
 
 static RList *r_bin_wasm_get_element_entries (RBinWasmObj *bin, RBinWasmSection *sec) {
-
 	RList *ret = NULL;
 	RBinWasmElementEntry *ptr = NULL;
 
@@ -640,33 +636,26 @@ static RList *r_bin_wasm_get_element_entries (RBinWasmObj *bin, RBinWasmSection
 	}
 
 	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))) {
@@ -674,13 +663,13 @@ static RList *r_bin_wasm_get_element_entries (RBinWasmObj *bin, RBinWasmSection
 				return ret;
 			}
 		}
-
 		r_list_append (ret, ptr);
 
 		r += 1;
-
 	}
-
+	return ret;
+beach:
+	free (ptr);
 	return ret;
 }
 

programming_language: C