diff options
author | Mark Wielaard <mjw@redhat.com> | 2014-12-14 21:48:23 +0100 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2014-12-17 16:35:56 +0100 |
commit | 7a053473c7bedd22e3db39c444a4cd8f97eace25 (patch) | |
tree | f98e9e7def17ec051170aaf663419628d84fae78 /libdw/dwarf_getlocation.c | |
parent | 9202665816763fad8524dd78a664dbcaa157b8d4 (diff) |
libdw: Add get_uleb128 and get_sleb128 bounds checking.
Both get_uleb128 and get_sleb128 now take an end pointer to prevent
reading too much data. Adjust all callers to provide the end pointer.
There are still two exceptions. "Raw" dwarf_getabbrevattr and
read_encoded_valued don't have a end pointer associated yet.
They will have to be provided in the future.
Signed-off-by: Mark Wielaard <mjw@redhat.com>
Diffstat (limited to 'libdw/dwarf_getlocation.c')
-rw-r--r-- | libdw/dwarf_getlocation.c | 39 |
1 files changed, 19 insertions, 20 deletions
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 38e93e68..068f3853 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -104,7 +104,8 @@ store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op) struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, sizeof (struct loc_block_s), 1); const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2; - (void) __libdw_get_uleb128 (&data); // Ignored, equal to op->number. + // Ignored, equal to op->number. And data length already checked. + (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word)); block->addr = op; block->data = (unsigned char *) data; block->length = op->number; @@ -394,28 +395,28 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, case DW_OP_piece: case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: - /* XXX Check size. */ - get_uleb128 (newloc->number, data); + get_uleb128 (newloc->number, data, end_data); break; case DW_OP_consts: case DW_OP_breg0 ... DW_OP_breg31: case DW_OP_fbreg: - /* XXX Check size. */ - get_sleb128 (newloc->number, data); + get_sleb128 (newloc->number, data, end_data); break; case DW_OP_bregx: - /* XXX Check size. */ - get_uleb128 (newloc->number, data); - get_sleb128 (newloc->number2, data); + get_uleb128 (newloc->number, data, end_data); + if (unlikely (data >= end_data)) + goto invalid; + get_sleb128 (newloc->number2, data, end_data); break; case DW_OP_bit_piece: case DW_OP_GNU_regval_type: - /* XXX Check size. */ - get_uleb128 (newloc->number, data); - get_uleb128 (newloc->number2, data); + get_uleb128 (newloc->number, data, end_data); + if (unlikely (data >= end_data)) + goto invalid; + get_uleb128 (newloc->number2, data, end_data); break; case DW_OP_implicit_value: @@ -426,8 +427,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, /* start of block inc. len. */ newloc->number2 = (Dwarf_Word) (uintptr_t) data; - /* XXX Check size. */ - get_uleb128 (newloc->number, data); /* Block length. */ + get_uleb128 (newloc->number, data, end_data); /* Block length. */ if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) goto invalid; data += newloc->number; /* Skip the block. */ @@ -438,23 +438,22 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, &newloc->number, IDX_debug_info, 0)) return -1; - /* XXX Check size. */ - get_uleb128 (newloc->number2, data); /* Byte offset. */ + if (unlikely (data >= end_data)) + goto invalid; + get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */ break; case DW_OP_GNU_deref_type: - if (unlikely (data >= end_data)) + if (unlikely (data + 1 >= end_data)) goto invalid; newloc->number = *data++; - get_uleb128 (newloc->number2, data); + get_uleb128 (newloc->number2, data, end_data); break; case DW_OP_GNU_const_type: { size_t size; - - /* XXX Check size. */ - get_uleb128 (newloc->number, data); + get_uleb128 (newloc->number, data, end_data); if (unlikely (data >= end_data)) goto invalid; |