Fix invalid pointer read issue in dwarf parser ##crash (#19459)

* Exploited by tests_65179, tests_65180 and tests_64901
* Fix out of bounds issue causing memory corruption in unit test
This commit is contained in:
pancake 2021-12-02 12:20:30 +01:00 committed by GitHub
parent e1efe7370f
commit dafa685c24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 32 deletions

View File

@ -164,18 +164,15 @@ static inline char *create_type_name_from_offset(ut64 offset) {
* @return char* DIEs name or NULL if error
*/
static char *get_die_name(const RBinDwarfDie *die) {
char *name = NULL;
st32 name_attr_idx = find_attr_idx (die, DW_AT_name);
if (name_attr_idx < 0 || name_attr_idx >= die->count) {
return NULL;
}
RBinDwarfAttrValue *av = &die->attr_values[name_attr_idx];
if (av->kind == DW_AT_KIND_STRING && name_attr_idx != -1 && av->string.content) {
name = strdup (av->string.content);
} else {
name = create_type_name_from_offset (die->offset);
return strdup (av->string.content);
}
return name;
return create_type_name_from_offset (die->offset);
}
/**
@ -208,7 +205,11 @@ static ut64 get_die_size(const RBinDwarfDie *die) {
* @param strbuf strbuf to store the type into
* @return st32 -1 if error else 0
*/
static st32 parse_array_type(Context *ctx, ut64 idx, RStrBuf *strbuf) {
static void parse_array_type(Context *ctx, int idx, RStrBuf *strbuf) {
if (idx < 0 || idx >= ctx->count) {
// eprintf ("die out of bounds\n");
return;
}
const RBinDwarfDie *die = &ctx->all_dies[idx++];
if (die->has_children) {
@ -242,7 +243,6 @@ static st32 parse_array_type(Context *ctx, ut64 idx, RStrBuf *strbuf) {
}
}
}
return 0;
}
/**
@ -391,7 +391,7 @@ static st32 parse_type(Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 *s
* @param result ptr to result member to fill up
* @return RAnalStructMember* ptr to parsed Member
*/
static RAnalStructMember *parse_struct_member (Context *ctx, ut64 idx, RAnalStructMember *result) {
static RAnalStructMember *parse_struct_member(Context *ctx, ut64 idx, RAnalStructMember *result) {
r_return_val_if_fail (result, NULL);
const RBinDwarfDie *die = &ctx->all_dies[idx];
@ -1190,15 +1190,16 @@ static st32 parse_function_args_and_vars(Context *ctx, ut64 idx, RStrBuf *args,
bool get_linkage_name = prefer_linkage_name (ctx->lang);
bool has_linkage_name = false;
int argNumber = 1;
const char *name = NULL;
size_t j;
for (j = idx; child_depth > 0 && j < ctx->count; j++) {
const RBinDwarfDie *child_die = &ctx->all_dies[j];
RStrBuf type;
r_strbuf_init (&type);
const char *name = NULL;
if (child_die->tag == DW_TAG_formal_parameter || child_die->tag == DW_TAG_variable) {
Variable *var = R_NEW0 (Variable);
size_t i;
name = NULL;
for (i = 0; i < child_die->count; i++) {
const RBinDwarfAttrValue *val = &child_die->attr_values[i];
switch (val->attr_name) {
@ -1229,10 +1230,10 @@ static st32 parse_function_args_and_vars(Context *ctx, ut64 idx, RStrBuf *args,
if (child_die->tag == DW_TAG_formal_parameter && child_depth == 1) {
/* arguments sometimes have only type, create generic argX */
if (type.len) {
if (!name) {
var->name = r_str_newf ("arg%d", argNumber);
} else {
if (name) {
var->name = strdup (name);
} else {
var->name = r_str_newf ("arg%d", argNumber);
}
r_strbuf_appendf (args, "%s %s,", r_strbuf_get (&type), var->name);
var->type = strdup (r_strbuf_get (&type));
@ -1434,6 +1435,7 @@ static void parse_function(Context *ctx, ut64 idx) {
break;
}
}
if (!fcn.name || !fcn.addr) { /* we need a name, faddr */
goto cleanup;
}

View File

@ -1327,7 +1327,7 @@ static void print_abbrev_section(RBinDwarfDebugAbbrev *da, PrintfCallback print)
for (i = 0; i < da->count; i++) {
int declstag = da->decls[i].tag;
print (" %-4"PFMT64d" ", da->decls[i].code);
if (declstag>=0 && declstag < DW_TAG_LAST) {
if (declstag >= 0 && declstag < DW_TAG_LAST) {
print (" %-25s ", dwarf_tag_name_encodings[declstag]);
}
print ("[%s]", da->decls[i].has_children ?
@ -1416,7 +1416,7 @@ R_API void r_bin_dwarf_free_debug_info(RBinDwarfDebugInfo *inf) {
}
ht_up_free (inf->lookup_table);
free (inf->comp_units);
free(inf);
free (inf);
}
static void print_attr_value(const RBinDwarfAttrValue *val, PrintfCallback print) {
@ -1514,7 +1514,7 @@ static void print_debug_info(const RBinDwarfDebugInfo *inf, PrintfCallback print
RBinDwarfDie *dies;
RBinDwarfAttrValue *values;
r_return_if_fail(inf);
r_return_if_fail (inf);
for (i = 0; i < inf->count; i++) {
print ("\n");
@ -1596,6 +1596,13 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len,
const ut8 *debug_str, size_t debug_str_len) {
r_return_val_if_fail (def && value && hdr && obuf, NULL);
value->attr_form = def->attr_form;
value->attr_name = def->attr_name;
value->block.data = NULL;
value->string.content = NULL;
value->string.offset = 0;
const ut8 *buf = obuf;
const ut8 *buf_end = obuf + obuf_len;
size_t j;
@ -1604,12 +1611,6 @@ static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len,
return NULL;
}
value->attr_form = def->attr_form;
value->attr_name = def->attr_name;
value->block.data = NULL;
value->string.content = NULL;
value->string.offset = 0;
// http://www.dwarfstd.org/doc/DWARF4.pdf#page=161&zoom=100,0,560
switch (def->attr_form) {
case DW_FORM_addr:

View File

@ -61,7 +61,7 @@ extern "C" {
#define DW_TAG_member 0x0d
#define DW_TAG_pointer_type 0x0f
#define DW_TAG_reference_type 0x10
#define DW_TAG_compile_unit 0x11 //
#define DW_TAG_compile_unit 0x11
#define DW_TAG_string_type 0x12
#define DW_TAG_structure_type 0x13
#define DW_TAG_subroutine_type 0x15
@ -202,8 +202,8 @@ extern "C" {
#define DW_AT_description 0x5a
#define DW_AT_binary_scale 0x5b
#define DW_AT_decimal_scale 0x5c
#define DW_AT_small 0x5d
#define DW_AT_decimal_sign 0x5e
#define DW_AT_small 0x5d
#define DW_AT_decimal_sign 0x5e
#define DW_AT_digit_count 0x5f
#define DW_AT_picture_string 0x60
#define DW_AT_mutable 0x61
@ -708,19 +708,19 @@ typedef struct dwarf_attr_kind {
ut64 attr_name;
ut64 attr_form;
RBinDwarfAttrKind kind;
/* This is subideal, as dw_form_data can be anything
we could lose information example: encoding signed
/* This is subideal, as dw_form_data can be anything
we could lose information example: encoding signed
2 byte int into ut64 and then interpreting it as st64 TODO*/
union {
union {
ut64 address;
RBinDwarfBlock block;
ut64 uconstant;
st64 sconstant;
ut8 flag;
ut64 reference;
RBinDwarfBlock block;
struct {
const char *content;
ut64 offset;
const char *content;
} string;
};
} RBinDwarfAttrValue;

View File

@ -3,7 +3,7 @@ BINS=$(patsubst %.c,$(BINDIR)/%,$(wildcard *.c))
LDFLAGS+=$(shell pkg-config --libs r_core)
CFLAGS+=-I../../libr/include
CFLAGS+=-I../../shlr/sdb/src
# $(shell pkg-config --cflags r_core) -g
CFLAGS+=-g
ifeq ($(ASAN),1)
ASAN_LD_PRELOAD=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5
else

View File

@ -45,8 +45,8 @@ bool test_r_reg_get_value_gpr(void) {
reg = r_reg_new ();
mu_assert_notnull (reg, "r_reg_new () failed");
r_reg_set_profile_string (reg,
"gpr eax .32 0 0\n\
r_reg_set_profile_string (reg, "=A0 eax\n\
gpr eax .32 0 0\n\
gpr ax .16 0 0\n\
gpr ah .8 1 0\n\
gpr al .8 0 0\n\