CVE-2022-28073: Use After Free (CWE-416)
value: A use after free in r_reg_set_value function in radare2 5.4.2 and 5.4.0.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
CVSS v3 base score: 7.5
Published: 2023-08-22T19:16Z
Repository: https://github.com/radareorg/radare2
Language: C
Files changed: libr/core/anal_tp.c, libr/core/cmd_anal.c, libr/reg/rvalue.c
Commit date: 2021-10-30 14:11:29 +0200
Commit message: Fix uaf crash in aaft (tests_64927) ##crash

Reported by giantbranch of NSFOCUS TIANJI Lab

Diff: diff --git a/libr/core/anal_tp.c b/libr/core/anal_tp.c
index cfc275b6f214..a17a8d817233 100644
--- a/libr/core/anal_tp.c
+++ b/libr/core/anal_tp.c
@@ -508,20 +508,20 @@ R_API void r_core_anal_type_match(RCore *core, RAnalFunction *fcn) {
 	if (!_pc) {
 		free (buf);
 		return;
 	}
 	char *pc = strdup (_pc);
-	RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
-	if (!r) {
-		free (buf);
-		return;
-	}
 	r_cons_break_push (NULL, NULL);
 	r_list_sort (fcn->bbs, bb_cmpaddr); // TODO: The algorithm can be more accurate if blocks are followed by their jmp/fail, not just by address
 	r_list_foreach (fcn->bbs, it, bb) {
 		ut64 addr = bb->addr;
 		int i = 0;
+		RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
+		if (!r) {
+			free (buf);
+			return;
+		}
 		r_reg_set_value (core->dbg->reg, r, addr);
 		while (1) {
 			if (r_cons_is_breaked ()) {
 				goto out_function;
 			}
@@ -547,10 +547,15 @@ R_API void r_core_anal_type_match(RCore *core, RAnalFunction *fcn) {
 				r_anal_op_fini (&aop);
 				break;
 			}
 			sdb_num_set (anal->esil->trace->db, sdb_fmt ("0x%"PFMT64x".count", addr), loop_count + 1, 0);
 			if (r_anal_op_nonlinear (aop.type)) {   // skip the instr
+				RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
+				if (!r) {
+					free (buf);
+					return;
+				}
 				r_reg_set_value (core->dbg->reg, r, addr + ret);
 			} else {
 				r_core_esil_step (core, UT64_MAX, NULL, NULL, false);
 			}
 			bool userfnc = false;
diff --git a/libr/core/cmd_anal.c b/libr/core/cmd_anal.c
index 78473198e57c..c7a796a13dd4 100644
--- a/libr/core/cmd_anal.c
+++ b/libr/core/cmd_anal.c
@@ -4764,11 +4764,11 @@ void cmd_anal_reg(RCore *core, const char *str) {
 	}
 
 	int size = 0, i, type = R_REG_TYPE_GPR;
 	int bits = (core->anal->bits & R_SYS_BITS_64)? 64: 32;
 	int use_colors = r_config_get_i (core->config, "scr.color");
-	RRegItem *r;
+	RRegItem *r = NULL;
 	const char *use_color;
 	const char *name;
 	char *arg;
 
 	if (use_colors) {
@@ -5096,10 +5096,11 @@ void cmd_anal_reg(RCore *core, const char *str) {
 		break;
 	case ' ': { // "ar "
 		arg = strchr (str + 1, '=');
 		if (arg) {
 			*arg = 0;
+			ut64 n = r_num_math (core->num, arg + 1);
 			char *ostr = r_str_trim_dup (str + 1);
 			char *regname = r_str_trim_nc (ostr);
 			r = r_reg_get (core->dbg->reg, regname, -1);
 			if (!r) {
 				int role = r_reg_get_name_idx (regname);
@@ -5111,12 +5112,11 @@ void cmd_anal_reg(RCore *core, const char *str) {
 				}
 			}
 			if (r) {
 				//eprintf ("%s 0x%08"PFMT64x" -> ", str,
 				//	r_reg_get_value (core->dbg->reg, r));
-				r_reg_set_value (core->dbg->reg, r,
-						r_num_math (core->num, arg + 1));
+				r_reg_set_value (core->dbg->reg, r, n); 
 				r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, true);
 				//eprintf ("0x%08"PFMT64x"\n",
 				//	r_reg_get_value (core->dbg->reg, r));
 				r_core_cmdf (core, ".dr*%d", bits);
 			} else {
diff --git a/libr/reg/rvalue.c b/libr/reg/rvalue.c
index 51905b9afd75..9e51cea5c671 100644
--- a/libr/reg/rvalue.c
+++ b/libr/reg/rvalue.c
@@ -139,13 +139,14 @@ R_API ut64 r_reg_get_value_by_role(RReg *reg, RRegisterId role) {
 	// TODO use mapping from RRegisterId to RRegItem (via RRegSet)
 	return r_reg_get_value (reg, r_reg_get (reg, r_reg_get_name (reg, role), -1));
 }
 
 R_API bool r_reg_set_value(RReg *reg, RRegItem *item, ut64 value) {
+	r_return_val_if_fail (reg && item, false);
+
 	ut8 bytes[12];
 	ut8 *src = bytes;
-	r_return_val_if_fail (reg && item, false);
 
 	if (r_reg_is_readonly (reg, item)) {
 		return true;
 	}
 	if (item->offset < 0) {

Vulnerable code: 	RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
	if (!r) {
		free (buf);
		return;
	}
	RRegItem *r;
				r_reg_set_value (core->dbg->reg, r,
						r_num_math (core->num, arg + 1));
	r_return_val_if_fail (reg && item, false);
Fixed code: 		RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
		if (!r) {
			free (buf);
			return;
		}
				RRegItem *r = r_reg_get (core->dbg->reg, pc, -1);
				if (!r) {
					free (buf);
					return;
				}
	RRegItem *r = NULL;
			ut64 n = r_num_math (core->num, arg + 1);
				r_reg_set_value (core->dbg->reg, r, n); 
	r_return_val_if_fail (reg && item, false);