Commit message: None
CVE: CVE-2018-14015
CWE: CWE-119
Vulnerability description: The sdb_set_internal function in sdb.c in radare2 2.7.0 allows remote attackers to cause a denial of service (invalid read and application crash) via a crafted ELF file because of missing input validation in r_bin_dwarf_parse_comp_unit in libr/bin/dwarf.c.

Project: radare2
File: dwarf.c

static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) {
	size_t i, j;
	ut64 attr_name, attr_form;

	if (!f || !da) {
		return;
	}
	for (i = 0; i < da->length; i++) {
		int declstag = da->decls[i].tag;
		fprintf (f, "Abbreviation Code %"PFMT64d" ", da->decls[i].code);
		if (declstag>=0 && declstag < DW_TAG_LAST) {
			fprintf (f, "Tag %s ", dwarf_tag_name_encodings[declstag]);
		}
		fprintf (f, "[%s]\n", da->decls[i].has_children ?
				"has children" : "no children");
		fprintf (f, "Offset 0x%"PFMT64x"\n", da->decls[i].offset);

		if (da->decls[i].specs) {
			for (j = 0; j < da->decls[i].length; j++) {
				attr_name = da->decls[i].specs[j].attr_name;
				attr_form = da->decls[i].specs[j].attr_form;
				if (attr_name && attr_form &&
					attr_name <= DW_AT_vtable_elem_location &&
					attr_form <= DW_FORM_indirect) {
					fprintf (f, "    %s %s\n",
							dwarf_attr_encodings[attr_name],
							dwarf_attr_form_encodings[attr_form]);
				}
			}
		}
	}
}

Project: radare2
File: dwarf.c

static void r_bin_dwarf_dump_debug_info(FILE *f, const RBinDwarfDebugInfo *inf) {
	size_t i, j, k;
	RBinDwarfDIE *dies;
	RBinDwarfAttrValue *values;
	if (!inf || !f) {
		return;
	}

	for (i = 0; i < inf->length; i++) {
		fprintf (f, "  Compilation Unit @ offset 0x%"PFMT64x":\n", inf->comp_units [i].offset);
		fprintf (f, "   Length:        0x%x\n", inf->comp_units [i].hdr.length);
		fprintf (f, "   Version:       %d\n", inf->comp_units [i].hdr.version);
		fprintf (f, "   Abbrev Offset: 0x%x\n", inf->comp_units [i].hdr.abbrev_offset);
		fprintf (f, "   Pointer Size:  %d\n", inf->comp_units [i].hdr.pointer_size);

		dies = inf->comp_units[i].dies;

		for (j = 0; j < inf->comp_units[i].length; j++) {
			fprintf (f, "    Abbrev Number: %"PFMT64u" ", dies[j].abbrev_code);

			if (dies[j].tag && dies[j].tag <= DW_TAG_volatile_type &&
				       dwarf_tag_name_encodings[dies[j].tag]) {
				fprintf (f, "(%s)\n", dwarf_tag_name_encodings[dies[j].tag]);
			} else {
				fprintf (f, "(Unknown abbrev tag)\n");
			}

			if (!dies[j].abbrev_code) {
				continue;
			}
			values = dies[j].attr_values;

			for (k = 0; k < dies[j].length; k++) {
				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 {
					fprintf (f, "     TODO\t");
				}
				r_bin_dwarf_dump_attr_value (&values[k], f);
				fprintf (f, "\n");
			}
		}
	}
}

Project: radare2

static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len,
		RBinDwarfAttrSpec *spec, RBinDwarfAttrValue *value,
		const RBinDwarfCompUnitHdr *hdr,
		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 < 1) {
		return NULL;
	}

	value->form = spec->attr_form;
	value->name = spec->attr_name;
	value->encoding.block.data = NULL;
	value->encoding.str_struct.string = NULL;
	value->encoding.str_struct.offset = 0;

	switch (spec->attr_form) {
	case DW_FORM_addr:
		switch (hdr->pointer_size) {
		case 1:
			value->encoding.address = READ (buf, ut8);
			break;
		case 2:
			value->encoding.address = READ (buf, ut16);
			break;
		case 4:
			value->encoding.address = READ (buf, ut32);
			break;
		case 8:
			value->encoding.address = READ (buf, ut64);
			break;
		default:
			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);
		if (value->encoding.block.length > 0) {
			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);
			}
		}
		break;
	case DW_FORM_block4:
		value->encoding.block.length = READ (buf, ut32);
		if (value->encoding.block.length > 0) {
			ut8 *data = calloc (sizeof (ut8), value->encoding.block.length);
			if (data) {
				for (j = 0; j < value->encoding.block.length; j++) {
					data[j] = READ (buf, ut8);
				}
			}
			value->encoding.block.data = data;
		}
		break;
#if 0
	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);
		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);
		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;
	case DW_FORM_sdata:
		buf = r_leb128 (buf, &value->encoding.sdata);
		break;
	case DW_FORM_strp:
		value->encoding.str_struct.offset = READ (buf, ut32);
		if (debug_str && value->encoding.str_struct.offset < debug_str_len) {
			value->encoding.str_struct.string = strdup (
				(const char *)(debug_str +
					value->encoding.str_struct.offset));
		} else {
			value->encoding.str_struct.string = NULL;
		}
		break;
	case DW_FORM_udata:
		{
			ut64 ndata = 0;
			const ut8 *data = (const ut8*)&ndata;
			buf = r_uleb128 (buf, R_MIN (sizeof (data), (size_t)(buf_end - buf)), &ndata);
			memcpy (&value->encoding.data, data, sizeof (value->encoding.data));
			value->encoding.str_struct.string = NULL;
		}
		break;
	case DW_FORM_ref_addr:
		value->encoding.reference = READ (buf, ut64); // addr size of machine
		break;
	case DW_FORM_ref1:
		value->encoding.reference = READ (buf, ut8);
		break;
	case DW_FORM_ref2:
		value->encoding.reference = READ (buf, ut16);
		break;
	case DW_FORM_ref4:
		value->encoding.reference = READ (buf, ut32);
		break;
	case DW_FORM_ref8:
		value->encoding.reference = READ (buf, ut64);
		break;
	case DW_FORM_data1:
		value->encoding.data = READ (buf, ut8);
		break;
	default:
		eprintf ("Unknown DW_FORM 0x%02"PFMT64x"\n", spec->attr_form);
		value->encoding.data = 0;
		return NULL;
	}
	return buf;
}