CVE-2022-1296: Out-of-bounds Read (CWE-125)
value: Out-of-bounds read in `r_bin_ne_get_relocs` function in GitHub repository radareorg/radare2 prior to 5.6.8. This vulnerability may allow attackers to read sensitive information or cause a crash.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.1
Published: 2022-04-11T12:15Z
Repository: https://github.com/radareorg/radare2
Language: Other
Files changed: libr/bin/format/ne/ne.c, test/db/formats/ne
Commit date: 2022-04-08 20:29:01 +0200
Commit message: Fix oobread in NE parser ##crash

* Reported by @hmsec via huntr.dev
* Reproducer: necrash
* BountyID: 52b57274-0e1a-4d61-ab29-1373b555fea0/

Diff: diff --git a/libr/bin/format/ne/ne.c b/libr/bin/format/ne/ne.c
index ee2df871ac87..b907d56e93b1 100644
--- a/libr/bin/format/ne/ne.c
+++ b/libr/bin/format/ne/ne.c
@@ -1,9 +1,8 @@
 /* radare - LGPL - Copyright 2019-2022 - GustavoLCR */
 
 #include "ne.h"
-#define NE_BUG 0
 
 static char *__get_target_os(r_bin_ne_obj_t *bin) {
 	switch (bin->ne_header->targOS) {
 	case 1:
 		return "OS/2";
@@ -503,29 +502,22 @@ RList *r_bin_ne_get_relocs(r_bin_ne_obj_t *bin) {
 				RBinImport *imp = R_NEW0 (RBinImport);
 				if (!imp) {
 					free (reloc);
 					break;
 				}
-				char *name;
-#if NE_BUG
-				if (rel.index > 0 && rel.index < bin->ne_header->ModRefs) {
-					offset = modref[rel.index - 1] + bin->header_offset + bin->ne_header->ImportNameTable;
-					name = __read_nonnull_str_at (bin->buf, offset);
-				} else {
-					name = r_str_newf ("UnknownModule%d_%x", rel.index, off); // ????
-				}
-#else
+				char *name = NULL;
 				if (rel.index > bin->ne_header->ModRefs) {
 					name = r_str_newf ("UnknownModule%d_%x", rel.index, off); // ????
-				} else {
+				} else if (rel.index > 0) {
 					offset = modref[rel.index - 1] + bin->header_offset + bin->ne_header->ImportNameTable;
 					name = __read_nonnull_str_at (bin->buf, offset);
 				}
-#endif
 				if (rel.flags & IMPORTED_ORD) {
 					imp->ordinal = rel.func_ord;
-					imp->name = r_str_newf ("%s.%s", name, __func_name_from_ord(name, rel.func_ord));
+					char *fname = __func_name_from_ord (name, rel.func_ord);
+					imp->name = r_str_newf ("%s.%s", name, fname);
+					free (fname);
 				} else {
 					offset = bin->header_offset + bin->ne_header->ImportNameTable + rel.name_off;
 					char *func = __read_nonnull_str_at (bin->buf, offset);
 					imp->name = r_str_newf ("%s.%s", name, func);
 					free (func);
@@ -564,10 +556,11 @@ RList *r_bin_ne_get_relocs(r_bin_ne_obj_t *bin) {
 			if (rel.flags & ADDITIVE) {
 				reloc->additive = 1;
 				r_list_append (relocs, reloc);
 			} else {
 				do {
+#define NE_BUG 0
 #if NE_BUG
 					if (reloc->paddr + 4 < r_buf_size (bin->buf)) {
 						break;
 					}
 #endif
diff --git a/test/db/formats/ne b/test/db/formats/ne
index 7b68344414dc..b71f29469b5d 100644
--- a/test/db/formats/ne
+++ b/test/db/formats/ne
@@ -1,5 +1,19 @@
+NAME=NE crash
+FILE=bins/ne/necrash
+CMDS=<<EOF
+aaa
+i~format
+i~csum
+aflc
+EOF
+EXPECT=<<EOF
+format   ne
+hdr.csum c258016a
+0
+EOF
+RUN
 NAME=NE Symbols
 FILE=bins/ne/anim8.exe
 CMDS=is
 EXPECT=<<EOF
 [Symbols]

Vulnerable code: #define NE_BUG 0
				char *name;
#if NE_BUG
				if (rel.index > 0 && rel.index < bin->ne_header->ModRefs) {
					offset = modref[rel.index - 1] + bin->header_offset + bin->ne_header->ImportNameTable;
					name = __read_nonnull_str_at (bin->buf, offset);
				} else {
					name = r_str_newf ("UnknownModule%d_%x", rel.index, off); // ????
				}
#else
				} else {
#endif
					imp->name = r_str_newf ("%s.%s", name, __func_name_from_ord(name, rel.func_ord));
Fixed code: 				char *name = NULL;
				} else if (rel.index > 0) {
					char *fname = __func_name_from_ord (name, rel.func_ord);
					imp->name = r_str_newf ("%s.%s", name, fname);
					free (fname);
#define NE_BUG 0
NAME=NE crash
FILE=bins/ne/necrash
CMDS=<<EOF
aaa
i~format
i~csum
aflc
EOF
EXPECT=<<EOF
format   ne
hdr.csum c258016a
0
EOF
RUN