CVE-2023-27590 (published 2023-03-14T21:15Z)

Rizin is a UNIX-like reverse engineering framework and command-line toolset. In version 0.5.1 and prior, converting a GDB registers profile file into a Rizin register profile can result in a stack-based buffer overflow when the `name`, `type`, or `groups` fields have longer values than expected. Users opening untrusted GDB registers files (e.g. with the `drpg` or `arpg` commands) are affected by this flaw. Commit d6196703d89c84467b600ba2692534579dc25ed4 contains a patch for this issue. As a workaround, review the GDB register profiles before loading them with `drpg`/`arpg` commands.

CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-120
cwe_name: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
extended_description: A buffer overflow condition exists when a product attempts to put more data in a buffer than it can hold, or when it attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the product copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
         
cwe_id: CWE-121
cwe_name: Stack-based Buffer Overflow
description: A stack-based buffer overflow condition is a condition where the buffer being overwritten is allocated on the stack (i.e., is a local variable or, rarely, a parameter to a function).
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/rizinorg/rizin
commit_details: repo_url: https://github.com/rizinorg/rizin
author: Riccardo Schirone
author_date: 2023-03-13 18:53:58+01:00
msg: Fix conversion from GDB register profile to rizin profile
repository: repo_url: https://github.com/rizinorg/rizin
repo_name: rizinorg/rizin
description: UNIX-like reverse engineering framework and command-line toolset.
repo_language: C
owner: rizinorg
file_changes: filename: debug_gdb.c
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,13 @@ typedef struct {
 #define UNSUPPORTED 0
 #define SUPPORTED   1
 
+#define PROC_NAME_SZ   1024
+#define PROC_REGION_SZ 100
+// PROC_REGION_SZ - 2 (used for `0x`). Due to how RZ_STR_DEF works this can't be
+// computed.
+#define PROC_REGION_LEFT_SZ 98
+#define PROC_PERM_SZ        5
+
 typedef struct rz_debug_gdb_ctx_t {
 	RzIOGdb **origrziogdb;
 	libgdbr_t *desc;
@@ -189,7 +196,7 @@ static RzList /*<RzDebugMap *>*/ *rz_debug_gdb_map_get(RzDebug *dbg) { // TODO
 	int unk = 0, perm, i;
 	char *ptr, *pos_1;
 	size_t line_len;
-	char name[1024], region1[100], region2[100], perms[5];
+	char name[PROC_NAME_SZ + 1], region1[PROC_REGION_SZ + 1], region2[PROC_REGION_SZ + 1], perms[PROC_PERM_SZ + 1];
 	RzDebugMap *map = NULL;
 	region1[0] = region2[0] = '0';
 	region1[1] = region2[1] = 'x';
@@ -213,8 +220,8 @@ static RzList /*<RzDebugMap *>*/ *rz_debug_gdb_map_get(RzDebug *dbg) { // TODO
 		}
 		// We assume Linux target, for now, so -
 		// 7ffff7dda000-7ffff7dfd000 r-xp 00000000 08:05 265428 /usr/lib/ld-2.25.so
-		ret = sscanf(ptr, "%s %s %" PFMT64x " %*s %*s %[^\n]", &region1[2],
-			perms, &offset, name);
+		ret = sscanf(ptr, "%" RZ_STR_DEF(PROC_REGION_LEFT_SZ) "s %" RZ_STR_DEF(PROC_PERM_SZ) "s %" PFMT64x " %*s %*s %" RZ_STR_DEF(PROC_NAME_SZ) "[^\n]",
+			&region1[2], perms, &offset, name);
 		if (ret == 3) {
 			name[0] = '\0';
 		} else if (ret != 4) {

programming_language: C
filename: debug_io.c
change_type: ModificationType.MODIFY
diff: @@ -4,6 +4,9 @@
 #include <rz_io.h>
 #include <rz_debug.h>
 
+#define IO_MAPS_PERM_SZ 32
+#define IO_MAPS_NAME_SZ 512
+
 static int __io_step(RzDebug *dbg) {
 	free(dbg->iob.system(dbg->iob.io, "ds"));
 	return true;
@@ -23,8 +26,8 @@ static RzList /*<RzDebugMap *>*/ *__io_maps(RzDebug *dbg) {
 	}
 	char *ostr = str;
 	ut64 map_start, map_end;
-	char perm[32];
-	char name[512];
+	char perm[IO_MAPS_PERM_SZ + 1];
+	char name[IO_MAPS_NAME_SZ + 1];
 	for (;;) {
 		char *nl = strchr(str, '\n');
 		if (nl) {
@@ -48,7 +51,7 @@ static RzList /*<RzDebugMap *>*/ *__io_maps(RzDebug *dbg) {
 			if (_s_) {
 				memmove(_s_, _s_ + 2, strlen(_s_));
 			}
-			sscanf(str, "0x%" PFMT64x " - 0x%" PFMT64x " %s %s",
+			sscanf(str, "0x%" PFMT64x " - 0x%" PFMT64x " %" RZ_STR_DEF(IO_MAPS_PERM_SZ) "s %" RZ_STR_DEF(IO_MAPS_NAME_SZ) "s",
 				&map_start, &map_end, perm, name);
 			if (map_end != 0LL) {
 				RzDebugMap *map = rz_debug_map_new(name, map_start, map_end, rz_str_rwx(perm), 0);

programming_language: C
filename: rz_types_base.h
change_type: ModificationType.MODIFY
diff: @@ -214,4 +214,7 @@ typedef struct _utX {
 		return m ? *m = n, m : m; \
 	}
 
+#define RZ_STR_DEF(s) RZ_STR(s)
+#define RZ_STR(s)     #s
+
 #endif // RZ_TYPES_BASE_H

programming_language: C
filename: profile.c
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,10 @@
 #include <rz_lib.h>
 #include <string.h>
 
+#define GDB_NAME_SZ   16
+#define GDB_TYPE_SZ   16
+#define GDB_GROUPS_SZ 128
+
 static void rz_reg_profile_def_free(RzRegProfileDef *def) {
 	if (!def) {
 		return;
@@ -511,7 +515,7 @@ static char *gdb_to_rz_profile(const char *gdb) {
 		return NULL;
 	}
 	char *ptr1, *gptr, *gptr1;
-	char name[16], groups[128], type[16];
+	char name[GDB_NAME_SZ + 1], groups[GDB_GROUPS_SZ + 1], type[GDB_TYPE_SZ + 1];
 	const int all = 1, gpr = 2, save = 4, restore = 8, float_ = 16,
 		  sse = 32, vector = 64, system = 128, mmx = 256;
 	int number, rel, offset, size, type_bits, ret;
@@ -542,8 +546,8 @@ static char *gdb_to_rz_profile(const char *gdb) {
 			rz_strbuf_free(sb);
 			return false;
 		}
-		ret = sscanf(ptr, " %s %d %d %d %d %s %s", name, &number, &rel,
-			&offset, &size, type, groups);
+		ret = sscanf(ptr, " %" RZ_STR_DEF(GDB_NAME_SZ) "s %d %d %d %d %" RZ_STR_DEF(GDB_TYPE_SZ) "s %" RZ_STR_DEF(GDB_GROUPS_SZ) "s",
+			name, &number, &rel, &offset, &size, type, groups);
 		// Groups is optional, others not
 		if (ret < 6) {
 			if (*ptr != '*') {

programming_language: C