From aa6917772d2f32e5a7daab25a46c72df0b5ea406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=A4rkl?= <info@florianmaerkl.de>
Date: Fri, 10 Dec 2021 15:43:12 +0100
Subject: [PATCH] Fix oob write for dwarf with abbrev with count 0 (Fix #2083)
 (#2086)

---
 librz/bin/dwarf.c         | 40 ++++++++++++++++++++++-----------------
 test/db/formats/elf/crash |  8 ++++++++
 2 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/librz/bin/dwarf.c b/librz/bin/dwarf.c
index 1ed1d3517c2..23dd1f9f0b1 100644
--- a/librz/bin/dwarf.c
+++ b/librz/bin/dwarf.c
@@ -1220,9 +1220,13 @@ static int init_die(RzBinDwarfDie *die, ut64 abbr_code, ut64 attr_count) {
 	if (!die) {
 		return -1;
 	}
-	die->attr_values = calloc(sizeof(RzBinDwarfAttrValue), attr_count);
-	if (!die->attr_values) {
-		return -1;
+	if (attr_count) {
+		die->attr_values = calloc(sizeof(RzBinDwarfAttrValue), attr_count);
+		if (!die->attr_values) {
+			return -1;
+		}
+	} else {
+		die->attr_values = NULL;
 	}
 	die->abbrev_code = abbr_code;
 	die->capacity = attr_count;
@@ -1726,25 +1730,27 @@ static const ut8 *parse_die(const ut8 *buf, const ut8 *buf_end, RzBinDwarfDebugI
 	size_t i;
 	const char *comp_dir = NULL;
 	ut64 line_info_offset = UT64_MAX;
-	for (i = 0; i < abbrev->count - 1; i++) {
-		memset(&die->attr_values[i], 0, sizeof(die->attr_values[i]));
+	if (abbrev->count) {
+		for (i = 0; i < abbrev->count - 1; i++) {
+			memset(&die->attr_values[i], 0, sizeof(die->attr_values[i]));
 
-		buf = parse_attr_value(buf, buf_end - buf, &abbrev->defs[i],
-			&die->attr_values[i], hdr, debug_str, debug_str_len, big_endian);
+			buf = parse_attr_value(buf, buf_end - buf, &abbrev->defs[i],
+				&die->attr_values[i], hdr, debug_str, debug_str_len, big_endian);
 
-		RzBinDwarfAttrValue *attribute = &die->attr_values[i];
+			RzBinDwarfAttrValue *attribute = &die->attr_values[i];
 
-		if (attribute->attr_name == DW_AT_comp_dir && (attribute->attr_form == DW_FORM_strp || attribute->attr_form == DW_FORM_string) && attribute->string.content) {
-			comp_dir = attribute->string.content;
-		}
-		if (attribute->attr_name == DW_AT_stmt_list) {
-			if (attribute->kind == DW_AT_KIND_CONSTANT) {
-				line_info_offset = attribute->uconstant;
-			} else if (attribute->kind == DW_AT_KIND_REFERENCE) {
-				line_info_offset = attribute->reference;
+			if (attribute->attr_name == DW_AT_comp_dir && (attribute->attr_form == DW_FORM_strp || attribute->attr_form == DW_FORM_string) && attribute->string.content) {
+				comp_dir = attribute->string.content;
+			}
+			if (attribute->attr_name == DW_AT_stmt_list) {
+				if (attribute->kind == DW_AT_KIND_CONSTANT) {
+					line_info_offset = attribute->uconstant;
+				} else if (attribute->kind == DW_AT_KIND_REFERENCE) {
+					line_info_offset = attribute->reference;
+				}
 			}
+			die->count++;
 		}
-		die->count++;
 	}
 
 	// If this is a compilation unit dir attribute, we want to cache it so the line info parsing
diff --git a/test/db/formats/elf/crash b/test/db/formats/elf/crash
index ea6c2c214bb..fb8a572bd56 100644
--- a/test/db/formats/elf/crash
+++ b/test/db/formats/elf/crash
@@ -25,3 +25,11 @@ nth vaddr bind type lib name
 []
 EOF
 RUN
+
+NAME=ELF/Dwarf: abbrev empty
+FILE=bins/elf/dwarf_fuzzed_abbrev_empty
+CMDS=<<EOF
+aaa
+EOF
+EXPECT=
+RUN
