CVE-2018-11380: Out-of-bounds Read (CWE-125)
value: The parse_import_ptr() function in radare2 2.5.0 allows remote attackers to cause a denial of service (heap-based out-of-bounds read and application crash) via a crafted Mach-O file.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 5.5
Published: 2018-05-22T19:29Z
Repository: https://github.com/radare/radare2
Language: C
Files changed: libr/bin/format/mach0/mach0.c
Commit date: 2018-05-06 15:59:08 +0200
Commit message: Fix #9970 - heap oobread in mach0 parser (#10026)


Diff: diff --git a/libr/bin/format/mach0/mach0.c b/libr/bin/format/mach0/mach0.c
index b7d866284f6..35b207c87a5 100644
--- a/libr/bin/format/mach0/mach0.c
+++ b/libr/bin/format/mach0/mach0.c
@@ -1584,12 +1584,13 @@ struct symbol_t* MACH0_(get_symbols)(struct MACH0_(obj_t)* bin) {
 	for (i = bin->dysymtab.iundefsym; i < to; i++) {
 		if (j > symbols_count) {
 			bprintf ("mach0-get-symbols: error\n");
 			break;
 		}
-		if (parse_import_stub(bin, &symbols[j], i))
+		if (parse_import_stub(bin, &symbols[j], i)) {
 			symbols[j++].last = 0;
+		}
 	}
 
 #if 1
 // symtab is wrongly parsed and produces dupped syms with incorrect vaddr */
 	for (i = 0; i < bin->nsymtab; i++) {
@@ -1660,16 +1661,20 @@ static int parse_import_ptr(struct MACH0_(obj_t)* bin, struct reloc_t *reloc, in
 	}
 #undef CASE
 
 	for (i = 0; i < bin->nsects; i++) {
 		if ((bin->sects[i].flags & SECTION_TYPE) == stype) {
-			for (j=0, sym=-1; bin->sects[i].reserved1+j < bin->nindirectsyms; j++)
-				if (idx == bin->indirectsyms[bin->sects[i].reserved1 + j]) {
+			for (j = 0, sym = -1; bin->sects[i].reserved1 + j < bin->nindirectsyms; j++) {
+				int indidx = bin->sects[i].reserved1 + j;
+				if (indidx < 0 || indidx >= bin->nindirectsyms) {
+					break;
+				}
+				if (idx == bin->indirectsyms[indidx]) {
 					sym = j;
 					break;
 				}
-
+			}
 			reloc->offset = sym == -1 ? 0 : bin->sects[i].offset + sym * wordsize;
 			reloc->addr = sym == -1 ? 0 : bin->sects[i].addr + sym * wordsize;
 			return true;
 		}
 	}
@@ -1679,12 +1684,13 @@ static int parse_import_ptr(struct MACH0_(obj_t)* bin, struct reloc_t *reloc, in
 struct import_t* MACH0_(get_imports)(struct MACH0_(obj_t)* bin) {
 	struct import_t *imports;
 	int i, j, idx, stridx;
 	const char *symstr;
 
-	if (!bin->symtab || !bin->symstr || !bin->sects || !bin->indirectsyms)
+	if (!bin->symtab || !bin->symstr || !bin->sects || !bin->indirectsyms) {
 		return NULL;
+	}
 	if (bin->dysymtab.nundefsym < 1 || bin->dysymtab.nundefsym > 0xfffff) {
 		return NULL;
 	}
 	if (!(imports = malloc ((bin->dysymtab.nundefsym + 1) * sizeof (struct import_t)))) {
 		return NULL;

Vulnerable code: 		if (parse_import_stub(bin, &symbols[j], i))
			for (j=0, sym=-1; bin->sects[i].reserved1+j < bin->nindirectsyms; j++)
				if (idx == bin->indirectsyms[bin->sects[i].reserved1 + j]) {

	if (!bin->symtab || !bin->symstr || !bin->sects || !bin->indirectsyms)
Fixed code: 		if (parse_import_stub(bin, &symbols[j], i)) {
		}
			for (j = 0, sym = -1; bin->sects[i].reserved1 + j < bin->nindirectsyms; j++) {
				int indidx = bin->sects[i].reserved1 + j;
				if (indidx < 0 || indidx >= bin->nindirectsyms) {
					break;
				}
				if (idx == bin->indirectsyms[indidx]) {
			}
	if (!bin->symtab || !bin->symstr || !bin->sects || !bin->indirectsyms) {
	}