CVE-2017-15368: Out-of-bounds Read (CWE-125)
value: The wasm_dis function in libr/asm/arch/wasm/wasm.c in radare2 2.0.0 allows remote attackers to cause a denial of service (stack-based buffer over-read and application crash) or possibly have unspecified other impact via a crafted WASM file that triggers an incorrect r_hex_bin2str call.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2017-10-16T01:29Z
Repository: https://github.com/radare/radare2
Language: C
Files changed: libr/asm/arch/wasm/wasm.c, libr/flag/flag.c
Commit date: 2017-10-11 19:02:25 +0200
Commit message: Fix crash in wasm disassembler

Diff: diff --git a/libr/asm/arch/wasm/wasm.c b/libr/asm/arch/wasm/wasm.c
index 29fa579ae6..b400565f1f 100644
--- a/libr/asm/arch/wasm/wasm.c
+++ b/libr/asm/arch/wasm/wasm.c
@@ -414,11 +414,13 @@ int wasm_asm(const char *str, unsigned char *buf, int buf_len) {
 }
 
 int wasm_dis(WasmOp *op, const unsigned char *buf, int buf_len) {
 	op->len = 1;
 	op->op = buf[0];
-	if (op->op > 0xbf) return 1;
+	if (op->op > 0xbf) {
+		return 1;
+	}
 	// add support for extension opcodes (SIMD + atomics)
 	WasmOpDef *opdef = &opcodes[op->op];
 	switch (op->op) {
 	case WASM_OP_TRAP:
 	case WASM_OP_NOP:
@@ -597,32 +599,41 @@ int wasm_dis(WasmOp *op, const unsigned char *buf, int buf_len) {
 		break;
 	case WASM_OP_BRTABLE:
 		{
 			ut32 count = 0, *table = NULL, def = 0;
 			size_t n = read_u32_leb128 (buf + 1, buf + buf_len, &count);
-			if (!(n > 0 && n < buf_len)) goto err;
-			if (!(table = calloc (count, sizeof (ut32)))) goto err;
+			if (!(n > 0 && n < buf_len)) {
+				goto err;
+			}
+			if (!(table = calloc (count, sizeof (ut32)))) {
+				goto err;
+			}
 			int i = 0;
 			op->len += n;
 			for (i = 0; i < count; i++) {
 				n = read_u32_leb128 (buf + op->len, buf + buf_len, &table[i]);
-				if (!(op->len + n <= buf_len)) goto beach;
+				if (!(op->len + n <= buf_len)) {
+					goto beach;
+				}
 				op->len += n;
 			}
 			n = read_u32_leb128 (buf + op->len, buf + buf_len, &def);
-			if (!(n > 0 && n + op->len < buf_len)) goto beach;
+			if (!(n > 0 && n + op->len < buf_len)) {
+				goto beach;
+			}
 			op->len += n;
 			snprintf (op->txt, R_ASM_BUFSIZE, "%s %d ", opdef->txt, count);
-			for (i = 0; i < count && strlen (op->txt) < R_ASM_BUFSIZE; i++) {
-				snprintf (op->txt + strlen (op->txt), R_ASM_BUFSIZE, "%d ", table[i]);
+			for (i = 0; i < count && strlen (op->txt) + 10 < R_ASM_BUFSIZE; i++) {
+				int optxtlen = strlen (op->txt);
+				snprintf (op->txt + optxtlen, R_ASM_BUFSIZE - optxtlen, "%d ", table[i]);
 			}	
 			snprintf (op->txt + strlen (op->txt), R_ASM_BUFSIZE, "%d", def);
 			free (table);
 			break;
 			beach:
-				free (table);
-				goto err;
+			free (table);
+			goto err;
 		}
 		break;
 	case WASM_OP_CALLINDIRECT:
 		{
 			ut32 val = 0, reserved = 0;
@@ -742,6 +753,5 @@ int wasm_dis(WasmOp *op, const unsigned char *buf, int buf_len) {
 err:
 	op->len = 1;
 	snprintf (op->txt, R_ASM_BUFSIZE, "invalid");
 	return op->len;
 }
-
diff --git a/libr/flag/flag.c b/libr/flag/flag.c
index 32d19f0997..1e5017155c 100644
--- a/libr/flag/flag.c
+++ b/libr/flag/flag.c
@@ -72,11 +72,11 @@ static ut64 num_callback(RNum *user, const char *name, int *ok) {
 
 /* return the list of flag at the nearest position.
 	dir == -1 -> result <= off
 	dir == 0 ->  result == off
 	dir == 1 ->  result >= off*/
-static  RFlagsAtOffset* r_flag_get_nearest_list(RFlag *f, ut64 off, int dir) {
+static RFlagsAtOffset* r_flag_get_nearest_list(RFlag *f, ut64 off, int dir) {
 	RFlagsAtOffset *flags = NULL;
 	RFlagsAtOffset key;
 	key.off = off;
 	if (dir >= 0) {
 		flags = r_skiplist_get_geq (f->by_off, &key);

Vulnerable code: 	if (op->op > 0xbf) return 1;
			if (!(n > 0 && n < buf_len)) goto err;
			if (!(table = calloc (count, sizeof (ut32)))) goto err;
				if (!(op->len + n <= buf_len)) goto beach;
			if (!(n > 0 && n + op->len < buf_len)) goto beach;
			for (i = 0; i < count && strlen (op->txt) < R_ASM_BUFSIZE; i++) {
				snprintf (op->txt + strlen (op->txt), R_ASM_BUFSIZE, "%d ", table[i]);
				free (table);
				goto err;

static  RFlagsAtOffset* r_flag_get_nearest_list(RFlag *f, ut64 off, int dir) {
Fixed code: 	if (op->op > 0xbf) {
		return 1;
	}
			if (!(n > 0 && n < buf_len)) {
				goto err;
			}
			if (!(table = calloc (count, sizeof (ut32)))) {
				goto err;
			}
				if (!(op->len + n <= buf_len)) {
					goto beach;
				}
			if (!(n > 0 && n + op->len < buf_len)) {
				goto beach;
			}
			for (i = 0; i < count && strlen (op->txt) + 10 < R_ASM_BUFSIZE; i++) {
				int optxtlen = strlen (op->txt);
				snprintf (op->txt + optxtlen, R_ASM_BUFSIZE - optxtlen, "%d ", table[i]);
			free (table);
			goto err;
static RFlagsAtOffset* r_flag_get_nearest_list(RFlag *f, ut64 off, int dir) {