CVE-2017-16805: Out-of-bounds Read (CWE-125)
value: In radare2 2.0.1, libr/bin/dwarf.c allows remote attackers to cause a denial of service (invalid read and application crash) via a crafted ELF file, related to r_bin_dwarf_parse_comp_unit in dwarf.c and sdb_set_internal in shlr/sdb/src/sdb.c.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 5.5
Published: 2017-11-13T21:29Z
Repository: https://github.com/radare/radare2
Language: C
Files changed: libr/bin/dwarf.c, libr/include/r_bin_dwarf.h
Commit date: 2017-11-14 04:15:54 +0900
Commit message: Fix #8813 - segfault in dwarf parser

Diff: diff --git a/libr/bin/dwarf.c b/libr/bin/dwarf.c
index 808d3505207..ebbf5720bf4 100644
--- a/libr/bin/dwarf.c
+++ b/libr/bin/dwarf.c
@@ -1,6 +1,6 @@
-/* radare - LGPL - Copyright 2012-2016 - pancake, Fedor Sakharov */
+/* radare - LGPL - Copyright 2012-2017 - pancake, Fedor Sakharov */
 
 #define D0 if(1)
 #define D1 if(1)
 
 #include <errno.h>
@@ -1142,12 +1142,13 @@ static void r_bin_dwarf_dump_debug_info(FILE *f, const RBinDwarfDebugInfo *inf)
 				continue;
 			}
 			values = dies[j].attr_values;
 
 			for (k = 0; k < dies[j].length; k++) {
-				if (!values[k].name)
+				if (!values[k].name) {
 					continue;
+				}
 
 				if (values[k].name < DW_AT_vtable_elem_location &&
 						dwarf_attr_encodings[values[k].name]) {
 					fprintf (f, "     %-18s : ", dwarf_attr_encodings[values[k].name]);
 				} else {
@@ -1166,11 +1167,11 @@ static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len,
 		const ut8 *debug_str, size_t debug_str_len) {
 	const ut8 *buf = obuf;
 	const ut8 *buf_end = obuf + obuf_len;
 	size_t j;
 
-	if (!spec || !value || !hdr || !obuf || obuf_len < 0) {
+	if (!spec || !value || !hdr || !obuf || obuf_len < 1) {
 		return NULL;
 	}
 
 	value->form = spec->attr_form;
 	value->name = spec->attr_name;
@@ -1192,11 +1193,11 @@ static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len,
 			break;
 		case 8:
 			value->encoding.address = READ (buf, ut64);
 			break;
 		default:
-			eprintf("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size);
+			eprintf ("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size);
 			return NULL;
 		}
 		break;
 	case DW_FORM_block2:
 		value->encoding.block.length = READ (buf, ut16);
@@ -1217,38 +1218,45 @@ static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len,
 				}
 			}
 			value->encoding.block.data = data;
 		}
 		break;
+#if 0
+// This causes segfaults to happen
 	case DW_FORM_data2:
 		value->encoding.data = READ (buf, ut16);
 		break;
 	case DW_FORM_data4:
 		value->encoding.data = READ (buf, ut32);
 		break;
 	case DW_FORM_data8:
 		value->encoding.data = READ (buf, ut64);
 		break;
+#endif
 	case DW_FORM_string:
 		value->encoding.str_struct.string = *buf? strdup ((const char*)buf) : NULL;
 		buf += (strlen ((const char*)buf) + 1);
 		break;
 	case DW_FORM_block:
 		buf = r_uleb128 (buf, buf_end - buf, &value->encoding.block.length);
 		if (!buf) {
 			return NULL;
 		}
-		value->encoding.block.data = calloc (sizeof(ut8), value->encoding.block.length);
-		for (j = 0; j < value->encoding.block.length; j++) {
-			value->encoding.block.data[j] = READ (buf, ut8);
+		value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length);
+		if (value->encoding.block.data) {
+			for (j = 0; j < value->encoding.block.length; j++) {
+				value->encoding.block.data[j] = READ (buf, ut8);
+			}
 		}
 		break;
 	case DW_FORM_block1:
 		value->encoding.block.length = READ (buf, ut8);
 		value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length + 1);
-		for (j = 0; j < value->encoding.block.length; j++) {
-			value->encoding.block.data[j] = READ (buf, ut8);
+		if (value->encoding.block.data) {
+			for (j = 0; j < value->encoding.block.length; j++) {
+				value->encoding.block.data[j] = READ (buf, ut8);
+			}
 		}
 		break;
 	case DW_FORM_flag:
 		value->encoding.flag = READ (buf, ut8);
 		break;
@@ -1342,12 +1350,11 @@ static const ut8 *r_bin_dwarf_parse_comp_unit(Sdb *s, const ut8 *obuf,
 			}
 			if (i >= cu->dies[cu->length].capacity || i >= da->decls[abbr_code - 1].capacity) {
 				eprintf ("Warning: malformed dwarf attribute capacity doesn't match length\n");
 				break;
 			}
-			memset (&cu->dies[cu->length].attr_values[i], 0, sizeof
-					(cu->dies[cu->length].attr_values[i]));
+			memset (&cu->dies[cu->length].attr_values[i], 0, sizeof (cu->dies[cu->length].attr_values[i]));
 			buf = r_bin_dwarf_parse_attr_value (buf, buf_end - buf,
 					&da->decls[abbr_code - 1].specs[i],
 					&cu->dies[cu->length].attr_values[i],
 					&cu->hdr, debug_str, debug_str_len);
 			if (cu->dies[cu->length].attr_values[i].name == DW_AT_comp_dir) {
diff --git a/libr/include/r_bin_dwarf.h b/libr/include/r_bin_dwarf.h
index 866bcbb445f..857d9cca345 100644
--- a/libr/include/r_bin_dwarf.h
+++ b/libr/include/r_bin_dwarf.h
@@ -620,11 +620,11 @@ typedef union {
 	ut64	constant;
 	ut8	flag;
 	ut64	data;
 	st64	sdata;
 	ut64	reference;
-	struct str_structt {
+	struct {
 		char	*string;
 		ut64	offset;
 	} str_struct;
 } RBinDwarfAttrEnc;
 

Vulnerable code: /* radare - LGPL - Copyright 2012-2016 - pancake, Fedor Sakharov */
				if (!values[k].name)
	if (!spec || !value || !hdr || !obuf || obuf_len < 0) {
			eprintf("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size);
		value->encoding.block.data = calloc (sizeof(ut8), value->encoding.block.length);
		for (j = 0; j < value->encoding.block.length; j++) {
			value->encoding.block.data[j] = READ (buf, ut8);
		for (j = 0; j < value->encoding.block.length; j++) {
			value->encoding.block.data[j] = READ (buf, ut8);
			memset (&cu->dies[cu->length].attr_values[i], 0, sizeof
					(cu->dies[cu->length].attr_values[i]));
	struct str_structt {
Fixed code: /* radare - LGPL - Copyright 2012-2017 - pancake, Fedor Sakharov */
				if (!values[k].name) {
				}
	if (!spec || !value || !hdr || !obuf || obuf_len < 1) {
			eprintf ("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size);
#if 0
// This causes segfaults to happen
#endif
		value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length);
		if (value->encoding.block.data) {
			for (j = 0; j < value->encoding.block.length; j++) {
				value->encoding.block.data[j] = READ (buf, ut8);
			}
		if (value->encoding.block.data) {
			for (j = 0; j < value->encoding.block.length; j++) {
				value->encoding.block.data[j] = READ (buf, ut8);
			}
			memset (&cu->dies[cu->length].attr_values[i], 0, sizeof (cu->dies[cu->length].attr_values[i]));
	struct {