Bug 24431 Read 32bit values when testing for the v4.19 symbol table format

Reading into uint64_t when reading the symbol table values drops the
sign and subsequently offset calculations will only be correct if either
the offset is positive or if the calculation overflows.

Read the relative value as signed int32_t (indepently of the target's
bitness) to allow negative offsets.  That also allows to drop the code
that formerly handled the overflow.

That change fixes an assertion raised when dealing with aarch64 kernel
binaries that have a __ksymtab with 32bit relocations. i.e. Bug #24431

	* src/abg-dwarf-reader.cc
	(try_reading_first_ksymtab_entry_using_v4_19_format): attempt to
	read first __ksymtab entry into int32_t to preserve sign

Signed-off-by: Matthias Maennich <maennich@google.com>
This commit is contained in:
maennich@google.com 2019-05-10 02:00:40 +01:00 committed by Dodji Seketeli
parent 2af6990560
commit a8bec92de2

View File

@ -7234,29 +7234,17 @@ public:
uint8_t *bytes = reinterpret_cast<uint8_t*>(elf_data->d_buf); uint8_t *bytes = reinterpret_cast<uint8_t*>(elf_data->d_buf);
bool is_big_endian = elf_architecture_is_big_endian(); bool is_big_endian = elf_architecture_is_big_endian();
elf_symbol_sptr symbol; elf_symbol_sptr symbol;
unsigned char symbol_value_size = 4;
unsigned char arch_word_size = architecture_word_size();
int32_t offset = 0;
const unsigned char symbol_value_size = sizeof(offset);
GElf_Addr symbol_address = 0, adjusted_symbol_address = 0; GElf_Addr symbol_address = 0, adjusted_symbol_address = 0;
ABG_ASSERT(read_int_from_array_of_bytes(bytes, ABG_ASSERT(read_int_from_array_of_bytes(bytes,
symbol_value_size, symbol_value_size,
is_big_endian, is_big_endian,
symbol_address)); offset));
GElf_Shdr mem; GElf_Shdr mem;
GElf_Shdr *section_header = gelf_getshdr(section, &mem); GElf_Shdr *section_header = gelf_getshdr(section, &mem);
if (arch_word_size == 4) symbol_address = offset + section_header->sh_addr;
symbol_address = (uint32_t)(symbol_address + section_header->sh_addr);
else if (arch_word_size == 8)
{
symbol_address = symbol_address + section_header->sh_addr;
if (symbol_address < ((uint64_t)1 << 32))
// The symbol address is expressed in 32 bits. So let's
// convert it to a 64 bits address with the 4 most
// significant bytes set to ff each.
symbol_address = ((uint64_t)0xffffffff << 32) | symbol_address;
}
else
ABG_ASSERT_NOT_REACHED;
adjusted_symbol_address = maybe_adjust_fn_sym_address(symbol_address); adjusted_symbol_address = maybe_adjust_fn_sym_address(symbol_address);
symbol = lookup_elf_symbol_from_address(adjusted_symbol_address); symbol = lookup_elf_symbol_from_address(adjusted_symbol_address);