CVE-2023-27114: NULL Pointer Dereference (CWE-476)
value: radare2 v5.8.3 was discovered to contain a segmentation fault via the component wasm_dis at p/wasm/wasm.c.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 5.5
Published: 2023-03-10T02:15Z
Repository: https://github.com/radareorg/radare2
Language: Other
Files changed: libr/arch/p/wasm/wasm.c, test/db/anal/wasm
Commit date: 2023-02-20 14:08:25 +0100
Commit message: Fix #21363 - null deref in the wasm disassembler ##crash

Diff: diff --git a/libr/arch/p/wasm/wasm.c b/libr/arch/p/wasm/wasm.c
index e7a8bcf17f80..ff8eff56617b 100644
--- a/libr/arch/p/wasm/wasm.c
+++ b/libr/arch/p/wasm/wasm.c
@@ -1,13 +1,10 @@
-/* radare - LGPL - Copyright 2017-2022 - pancake, cgvwzq */
+/* radare - LGPL - Copyright 2017-2023 - pancake, cgvwzq */
 
 // http://webassembly.org/docs/binary-encoding/#module-structure
 
-#include <r_asm.h>
-#include <r_lib.h>
-#include <string.h>
-
+#include <r_arch.h>
 #include "wasm.h"
 #include "../../../bin/format/wasm/wasm.h"
 
 static WasmOpDef opcodes[256] = {
 	[WASM_OP_TRAP] = { "trap", 1, 1 },
@@ -609,11 +606,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 		case WASM_OP_I32REINTERPRETF32:
 		case WASM_OP_I64REINTERPRETF64:
 		case WASM_OP_F32REINTERPRETI32:
 		case WASM_OP_F64REINTERPRETI64:
 		case WASM_OP_END:
-			if (txt) {
+			if (txt && opdef->txt) {
 				op->txt = strdup (opdef->txt);
 			}
 			break;
 		case WASM_OP_BLOCK:
 		case WASM_OP_LOOP:
@@ -622,11 +619,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				st32 val = 0;
 				size_t n = read_i32_leb128 (buf + 1, buf + buf_len, &val);
 				if (!(n > 0 && n < buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					switch (val) {
 					case R_BIN_WASM_VALUETYPE_VOID:
 						op->txt = strdup (opdef->txt);
 						break;
 					case R_BIN_WASM_VALUETYPE_i32:
@@ -658,11 +655,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 			{
 				size_t n = read_u32_leb128 (buf + 1, buf + buf_len, &op->val);
 				if (n <= 0 || n >= buf_len) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d", opdef->txt, op->val);
 				}
 				op->len += n;
 			}
 			break;
@@ -691,11 +688,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				n = read_u32_leb128 (buf + op->len, buf + buf_len, &def);
 				if (!(n > 0 && n + op->len < buf_len)) {
 					goto beach;
 				}
 				op->len += n;
-				if (txt) {
+				if (txt && opdef->txt) {
 					RStrBuf *sb = r_strbuf_new ("");
 					if (sb) {
 						r_strbuf_setf (sb, "%s %d ", opdef->txt, count);
 						for (i = 0; i < count; i++) {
 							r_strbuf_appendf (sb, "%d ", table[i]);
@@ -722,11 +719,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				n = read_u32_leb128 (buf + op->len, buf + buf_len, &reserved);
 				if (!(n == 1 && op->len + n <= buf_len)) {
 					goto err;
 				}
 				reserved &= 0x1;
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d %d", opdef->txt, val, reserved);
 				}
 				op->len += n;
 			}
 			break;
@@ -739,11 +736,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				ut32 val = 0;
 				size_t n = read_u32_leb128 (buf + 1, buf + buf_len, &val);
 				if (!(n > 0 && n < buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d", opdef->txt, val);
 				}
 				op->len += n;
 			}
 			break;
@@ -779,11 +776,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				op->len += n;
 				n = read_u32_leb128 (buf + op->len, buf + buf_len, &offset);
 				if (!(n > 0 && op->len + n <= buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d %d", opdef->txt, flag, offset);
 				}
 				op->len += n;
 			}
 			break;
@@ -794,11 +791,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				size_t n = read_u32_leb128 (buf + 1, buf + buf_len, &reserved);
 				if (!(n == 1 && n < buf_len)) {
 					goto err;
 				}
 				reserved &= 0x1;
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d", opdef->txt, reserved);
 				}
 				op->len += n;
 			}
 			break;
@@ -807,11 +804,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				st32 val = 0;
 				size_t n = read_i32_leb128 (buf + 1, buf + buf_len, &val);
 				if (!(n > 0 && n < buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %" PFMT32d, opdef->txt, val);
 				}
 				op->len += n;
 			}
 			break;
@@ -820,11 +817,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				st64 val = 0;
 				size_t n = read_i64_leb128 (buf + 1, buf + buf_len, &val);
 				if (!(n > 0 && n < buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %" PFMT64d, opdef->txt, val);
 				}
 				op->len += n;
 			}
 			break;
@@ -833,11 +830,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				union fi {
 					ut32  v;
 					float f;
 				} u;
 				u.v = r_read_at_le32 (buf, 1);
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %f", opdef->txt, u.f);
 				}
 				op->len += 4;
 			} else {
 				goto err;
@@ -848,11 +845,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				union di {
 					ut64   v;
 					double f;
 				} u;
 				u.v = r_read_at_le64 (buf, 1);
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %f", opdef->txt, u.f);
 				}
 				op->len += 8;
 			} else {
 				goto err;
@@ -934,11 +931,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				op->len += n;
 				n = read_u32_leb128 (buf + op->len, buf + buf_len, &offset);
 				if (!(n > 0 && op->len + n <= buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d %d", opdef->txt, flag, offset);
 				}
 				op->len += n;
 			}
 			break;
@@ -1106,11 +1103,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 		case WASM_OP_I8X16AVGRU:
 		case WASM_OP_I16X8AVGRU:
 		case WASM_OP_I8X16ABS:
 		case WASM_OP_I16X8ABS:
 		case WASM_OP_I32X4ABS:
-			if (txt) {
+			if (txt && opdef->txt) {
 				op->txt = strdup (opdef->txt);
 			}
 			break;
 		case WASM_OP_V128LOAD:
 		case WASM_OP_I16X8LOAD8X8S:
@@ -1134,11 +1131,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				n = read_u32_leb128 (buf + 1 + simdop_size + n, buf + buf_len, &align);
 				op->len += n;
 				if (!(n > 0 && n < buf_len)) {
 					goto err;
 				}
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s o:%d a:2^%d", opdef->txt, offset, align);
 				}
 			}
 			break;
 		case WASM_OP_V128CONST:
@@ -1154,11 +1151,11 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 					bytes[i] = buf[i + 1 + simdop_size];
 				}
 				if (txt) {
 					op->txt = r_str_newf ("%s %02x %02x %02x %02x %02x %02x %02x " \
 						"%02x %02x %02x %02x %02x %02x %02x %02x %02x",
-						opdef->txt, bytes[0], bytes[1], bytes[2], bytes[3],
+						r_str_get (opdef->txt), bytes[0], bytes[1], bytes[2], bytes[3],
 						bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
 						bytes[9], bytes[10], bytes[11], bytes[12], bytes[13],
 						bytes[14], bytes[15]);
 				}
 			}
@@ -1181,19 +1178,22 @@ R_IPI int wasm_dis(WasmOp *op, const ut8 *buf, int buf_len, bool txt) {
 				if (buf_len < 3) {
 					goto err;
 				}
 				unsigned char lane = buf[1 + simdop_size];
 				++op->len;
-				if (txt) {
+				if (txt && opdef->txt) {
 					op->txt = r_str_newf ("%s %d", opdef->txt, lane);
 				}
 			}
 			break;
 		}
 	} else {
 		goto err;
 	}
+	if (txt && !op->txt) {
+		op->txt = strdup ("incorrect");
+	}
 	return op->len;
 
   err:
 	op->len = 1;
 	if (txt) {
diff --git a/test/db/anal/wasm b/test/db/anal/wasm
new file mode 100644
index 000000000000..3c0066fb3964
--- /dev/null
+++ b/test/db/anal/wasm
@@ -0,0 +1,25 @@
+NAME=wasm crash test
+FILE=bins/wasm/nullderef.wasm
+CMDS=<<EOF
+pd 10
+EOF
+EXPECT=<<EOF
+            ;-- entry0:
+            ;-- fcn.0:
+            0x000000be      4185feff77     i32.const 251657989
+            0x000000c3      fd0f           i8x16.splat
+            0x000000c5      fda001         incorrect
+            0x000000c8      fd64           incorrect
+            0x000000ca      0b             end
+            0x000000cb      00             trap
+            0x000000cc      00             trap
+            0x000000cd      00             trap
+            0x000000ce      00             trap
+            0x000000cf      00             trap
+EOF
+EXPECT_ERR=<<EOF
+ERROR: unknown section id: 13
+ERROR: unknown section id: 109
+EOF
+RUN
+

Vulnerable code: /* radare - LGPL - Copyright 2017-2022 - pancake, cgvwzq */
#include <r_asm.h>
#include <r_lib.h>
#include <string.h>

			if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
				if (txt) {
			if (txt) {
				if (txt) {
						opdef->txt, bytes[0], bytes[1], bytes[2], bytes[3],
				if (txt) {
Fixed code: /* radare - LGPL - Copyright 2017-2023 - pancake, cgvwzq */
#include <r_arch.h>
			if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
				if (txt && opdef->txt) {
			if (txt && opdef->txt) {
				if (txt && opdef->txt) {
						r_str_get (opdef->txt), bytes[0], bytes[1], bytes[2], bytes[3],
				if (txt && opdef->txt) {
	if (txt && !op->txt) {
		op->txt = strdup ("incorrect");
	}
NAME=wasm crash test
FILE=bins/wasm/nullderef.wasm
CMDS=<<EOF
pd 10
EOF
EXPECT=<<EOF
            ;-- entry0:
            ;-- fcn.0:
            0x000000be      4185feff77     i32.const 251657989
            0x000000c3      fd0f           i8x16.splat
            0x000000c5      fda001         incorrect
            0x000000c8      fd64           incorrect
            0x000000ca      0b             end
            0x000000cb      00             trap
            0x000000cc      00             trap
            0x000000cd      00             trap
            0x000000ce      00             trap
            0x000000cf      00             trap
EOF
EXPECT_ERR=<<EOF
ERROR: unknown section id: 13
ERROR: unknown section id: 109
EOF
RUN