diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 2c0045691eec..f59a4722dc8a 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -167,15 +167,10 @@ bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) { return false; } - if (!ReadProgramHeaders(ehdr, load_bias)) { - return false; - } - - // We could still potentially unwind without the section header - // information, so ignore any errors. - if (!ReadSectionHeaders(ehdr)) { - log(0, "Malformed section header found, ignoring..."); - } + // If we have enough information that this is an elf file, then allow + // malformed program and section headers. + ReadProgramHeaders(ehdr, load_bias); + ReadSectionHeaders(ehdr); return true; } @@ -200,14 +195,12 @@ uint64_t ElfInterface::GetLoadBias(Memory* memory) { } template -bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) { +void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) { uint64_t offset = ehdr.e_phoff; for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) { PhdrType phdr; if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) { - last_error_.code = ERROR_MEMORY_INVALID; - last_error_.address = offset; - return false; + return; } switch (phdr.p_type) { @@ -242,11 +235,10 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) break; } } - return true; } template -bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { +void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { uint64_t offset = ehdr.e_shoff; uint64_t sec_offset = 0; uint64_t sec_size = 0; @@ -267,9 +259,7 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory_->Read(offset, &shdr, sizeof(shdr))) { - last_error_.code = ERROR_MEMORY_INVALID; - last_error_.address = offset; - return false; + return; } if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { @@ -277,18 +267,14 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { // the string terminated names. ShdrType str_shdr; if (shdr.sh_link >= ehdr.e_shnum) { - last_error_.code = ERROR_UNWIND_INFO; - return false; + continue; } uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize; if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) { - last_error_.code = ERROR_MEMORY_INVALID; - last_error_.address = str_offset; - return false; + continue; } if (str_shdr.sh_type != SHT_STRTAB) { - last_error_.code = ERROR_UNWIND_INFO; - return false; + continue; } symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, str_shdr.sh_offset, str_shdr.sh_size)); @@ -324,7 +310,6 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { static_cast(shdr.sh_offset))); } } - return true; } template @@ -499,11 +484,13 @@ template void ElfInterface::InitHeadersWithTemplate(uint64_t); template bool ElfInterface::ReadAllHeaders(uint64_t*); template bool ElfInterface::ReadAllHeaders(uint64_t*); -template bool ElfInterface::ReadProgramHeaders(const Elf32_Ehdr&, uint64_t*); -template bool ElfInterface::ReadProgramHeaders(const Elf64_Ehdr&, uint64_t*); +template void ElfInterface::ReadProgramHeaders(const Elf32_Ehdr&, + uint64_t*); +template void ElfInterface::ReadProgramHeaders(const Elf64_Ehdr&, + uint64_t*); -template bool ElfInterface::ReadSectionHeaders(const Elf32_Ehdr&); -template bool ElfInterface::ReadSectionHeaders(const Elf64_Ehdr&); +template void ElfInterface::ReadSectionHeaders(const Elf32_Ehdr&); +template void ElfInterface::ReadSectionHeaders(const Elf64_Ehdr&); template bool ElfInterface::GetSonameWithTemplate(std::string*); template bool ElfInterface::GetSonameWithTemplate(std::string*); diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 5c1210d68877..a45eba8a5a89 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -104,10 +104,10 @@ class ElfInterface { bool ReadAllHeaders(uint64_t* load_bias); template - bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias); + void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias); template - bool ReadSectionHeaders(const EhdrType& ehdr); + void ReadSectionHeaders(const EhdrType& ehdr); template bool GetSonameWithTemplate(std::string* soname); diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp index aa6df8412cc2..9326bff0fbff 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -97,9 +97,15 @@ class ElfInterfaceTest : public ::testing::Test { template void InitHeadersDebugFrameFail(); + template + void InitProgramHeadersMalformed(); + template void InitSectionHeadersMalformed(); + template + void InitSectionHeadersMalformedSymData(); + template void InitSectionHeaders(uint64_t entry_size); @@ -677,6 +683,29 @@ TEST_F(ElfInterfaceTest, init_headers_debug_frame64) { InitHeadersDebugFrame(); } +template +void ElfInterfaceTest::InitProgramHeadersMalformed() { + std::unique_ptr elf(new ElfInterfaceType(&memory_)); + + Ehdr ehdr = {}; + ehdr.e_phoff = 0x100; + ehdr.e_phnum = 3; + ehdr.e_phentsize = sizeof(Phdr); + memory_.SetMemory(0, &ehdr, sizeof(ehdr)); + + uint64_t load_bias = 0; + ASSERT_TRUE(elf->Init(&load_bias)); + EXPECT_EQ(0U, load_bias); +} + +TEST_F(ElfInterfaceTest, init_program_headers_malformed32) { + InitProgramHeadersMalformed(); +} + +TEST_F(ElfInterfaceTest, init_program_headers_malformed64) { + InitProgramHeadersMalformed(); +} + template void ElfInterfaceTest::InitSectionHeadersMalformed() { std::unique_ptr elf(new ElfInterfaceType(&memory_)); @@ -700,6 +729,80 @@ TEST_F(ElfInterfaceTest, init_section_headers_malformed64) { InitSectionHeadersMalformed(); } +template +void ElfInterfaceTest::InitSectionHeadersMalformedSymData() { + std::unique_ptr elf(new ElfInterfaceType(&memory_)); + + uint64_t offset = 0x1000; + + Ehdr ehdr = {}; + ehdr.e_shoff = offset; + ehdr.e_shnum = 5; + ehdr.e_shentsize = sizeof(Shdr); + memory_.SetMemory(0, &ehdr, sizeof(ehdr)); + + offset += ehdr.e_shentsize; + + Shdr shdr = {}; + shdr.sh_type = SHT_SYMTAB; + shdr.sh_link = 4; + shdr.sh_addr = 0x5000; + shdr.sh_offset = 0x5000; + shdr.sh_entsize = 0x100; + shdr.sh_size = shdr.sh_entsize * 10; + memory_.SetMemory(offset, &shdr, sizeof(shdr)); + offset += ehdr.e_shentsize; + + memset(&shdr, 0, sizeof(shdr)); + shdr.sh_type = SHT_DYNSYM; + shdr.sh_link = 10; + shdr.sh_addr = 0x6000; + shdr.sh_offset = 0x6000; + shdr.sh_entsize = 0x100; + shdr.sh_size = shdr.sh_entsize * 10; + memory_.SetMemory(offset, &shdr, sizeof(shdr)); + offset += ehdr.e_shentsize; + + memset(&shdr, 0, sizeof(shdr)); + shdr.sh_type = SHT_DYNSYM; + shdr.sh_link = 2; + shdr.sh_addr = 0x6000; + shdr.sh_offset = 0x6000; + shdr.sh_entsize = 0x100; + shdr.sh_size = shdr.sh_entsize * 10; + memory_.SetMemory(offset, &shdr, sizeof(shdr)); + offset += ehdr.e_shentsize; + + // The string data for the entries. + memset(&shdr, 0, sizeof(shdr)); + shdr.sh_type = SHT_STRTAB; + shdr.sh_name = 0x20000; + shdr.sh_offset = 0xf000; + shdr.sh_size = 0x1000; + memory_.SetMemory(offset, &shdr, sizeof(shdr)); + offset += ehdr.e_shentsize; + + uint64_t load_bias = 0; + ASSERT_TRUE(elf->Init(&load_bias)); + EXPECT_EQ(0U, load_bias); + EXPECT_EQ(0U, elf->debug_frame_offset()); + EXPECT_EQ(0U, elf->debug_frame_size()); + EXPECT_EQ(0U, elf->gnu_debugdata_offset()); + EXPECT_EQ(0U, elf->gnu_debugdata_size()); + + std::string name; + uint64_t name_offset; + ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset)); +} + +TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata32) { + InitSectionHeadersMalformedSymData(); +} + +TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) { + InitSectionHeadersMalformedSymData(); +} + template void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) { std::unique_ptr elf(new ElfInterfaceType(&memory_)); @@ -708,7 +811,7 @@ void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) { Ehdr ehdr = {}; ehdr.e_shoff = offset; - ehdr.e_shnum = 10; + ehdr.e_shnum = 5; ehdr.e_shentsize = entry_size; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); @@ -795,7 +898,7 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() { Ehdr ehdr = {}; ehdr.e_shoff = offset; - ehdr.e_shnum = 10; + ehdr.e_shnum = 6; ehdr.e_shentsize = sizeof(Shdr); ehdr.e_shstrndx = 2; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp index f5995037583a..861b82f07198 100644 --- a/libunwindstack/tests/MapInfoGetElfTest.cpp +++ b/libunwindstack/tests/MapInfoGetElfTest.cpp @@ -319,7 +319,7 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) { TestInitEhdr(&ehdr, ELFCLASS64, EM_AARCH64); ehdr.e_shoff = 0x2000; ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; - ehdr.e_shnum = 4; + ehdr.e_shnum = 0; memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr)); Elf* elf = info.GetElf(process_memory_, false); @@ -341,7 +341,7 @@ TEST_F(MapInfoGetElfTest, check_device_maps) { TestInitEhdr(&ehdr, ELFCLASS64, EM_X86_64); ehdr.e_shoff = 0x2000; ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; - ehdr.e_shnum = 4; + ehdr.e_shnum = 0; memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr)); Elf* elf = info.GetElf(process_memory_, false); @@ -368,7 +368,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) { TestInitEhdr(&ehdr, ELFCLASS64, EM_X86_64); ehdr.e_shoff = 0x2000; ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; - ehdr.e_shnum = 4; + ehdr.e_shnum = 0; memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr)); Elf* elf_in_threads[kNumConcurrentThreads];