diff options
author | Alan Modra <amodra@gmail.com> | 2022-06-14 12:46:42 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2022-06-15 10:24:33 +0930 |
commit | 31d6c13defeba7716ebc9d5c8f81f2f35fe39980 (patch) | |
tree | 33e4cf384691d48e0bcc87cfb21c5c2d0e0bf3ae | |
parent | dac0515d825e788dec188fff4d5b9d4ac7383f33 (diff) | |
download | gdb-31d6c13defeba7716ebc9d5c8f81f2f35fe39980.zip gdb-31d6c13defeba7716ebc9d5c8f81f2f35fe39980.tar.gz gdb-31d6c13defeba7716ebc9d5c8f81f2f35fe39980.tar.bz2 |
PR29230, segv in lookup_symbol_in_variable_table
The PR23230 testcase uses indexed strings without specifying
SW_AT_str_offsets_base. In this case we left u.str with garbage (from
u.val) which then led to a segfault when attempting to access the
string. Fix that by clearing u.str. The patch also adds missing
sanity checks in the recently committed read_indexed_address and
read_indexed_string functions.
PR 29230
* dwarf2.c (read_indexed_address): Return uint64_t. Sanity check idx.
(read_indexed_string): Use uint64_t for str_offset. Sanity check idx.
(read_attribute_value): Clear u.str for indexed string forms when
DW_AT_str_offsets_base is not yet read or missing.
-rw-r--r-- | bfd/dwarf2.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 51018e1..aaa2d84 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -1353,13 +1353,13 @@ is_addrx_form (enum dwarf_form form) /* Returns the address in .debug_addr section using DW_AT_addr_base. Used to implement DW_FORM_addrx*. */ -static bfd_vma +static uint64_t read_indexed_address (uint64_t idx, struct comp_unit *unit) { struct dwarf2_debug *stash = unit->stash; struct dwarf2_debug_file *file = unit->file; - size_t addr_base = unit->dwarf_addr_offset; bfd_byte *info_ptr; + size_t offset; if (stash == NULL) return 0; @@ -1369,12 +1369,23 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit) &file->dwarf_addr_buffer, &file->dwarf_addr_size)) return 0; - info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size; + if (_bfd_mul_overflow (idx, unit->offset_size, &offset)) + return 0; + + offset += unit->dwarf_addr_offset; + if (offset < unit->dwarf_addr_offset + || offset > file->dwarf_addr_size + || file->dwarf_addr_size - offset < unit->offset_size) + return 0; + + info_ptr = file->dwarf_addr_buffer + offset; if (unit->offset_size == 4) return bfd_get_32 (unit->abfd, info_ptr); - else + else if (unit->offset_size == 8) return bfd_get_64 (unit->abfd, info_ptr); + else + return 0; } /* Returns the string using DW_AT_str_offsets_base. @@ -1385,7 +1396,8 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit) struct dwarf2_debug *stash = unit->stash; struct dwarf2_debug_file *file = unit->file; bfd_byte *info_ptr; - unsigned long str_offset; + uint64_t str_offset; + size_t offset; if (stash == NULL) return NULL; @@ -1401,15 +1413,26 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit) &file->dwarf_str_offsets_size)) return NULL; - info_ptr = (file->dwarf_str_offsets_buffer - + unit->dwarf_str_offset - + idx * unit->offset_size); + if (_bfd_mul_overflow (idx, unit->offset_size, &offset)) + return NULL; + + offset += unit->dwarf_str_offset; + if (offset < unit->dwarf_str_offset + || offset > file->dwarf_str_offsets_size + || file->dwarf_str_offsets_size - offset < unit->offset_size) + return NULL; + + info_ptr = file->dwarf_str_offsets_buffer + offset; if (unit->offset_size == 4) str_offset = bfd_get_32 (unit->abfd, info_ptr); - else + else if (unit->offset_size == 8) str_offset = bfd_get_64 (unit->abfd, info_ptr); + else + return NULL; + if (str_offset >= file->dwarf_str_size) + return NULL; return (const char *) file->dwarf_str_buffer + str_offset; } @@ -1534,27 +1557,37 @@ read_attribute_value (struct attribute * attr, is not yet read. */ if (unit->dwarf_str_offset != 0) attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + else + attr->u.str = NULL; break; case DW_FORM_strx2: attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end); if (unit->dwarf_str_offset != 0) attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + else + attr->u.str = NULL; break; case DW_FORM_strx3: attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end); if (unit->dwarf_str_offset != 0) attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + else + attr->u.str = NULL; break; case DW_FORM_strx4: attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end); if (unit->dwarf_str_offset != 0) attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + else + attr->u.str = NULL; break; case DW_FORM_strx: attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr, false, info_ptr_end); if (unit->dwarf_str_offset != 0) attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + else + attr->u.str = NULL; break; case DW_FORM_exprloc: case DW_FORM_block: |