Skip to content

Commit

Permalink
Merge "Be permissive about badly formed elf files."
Browse files Browse the repository at this point in the history
  • Loading branch information
cferris1000 authored and Gerrit Code Review committed Aug 4, 2018
2 parents e0f6dc4 + 5acf069 commit c7815d6
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 37 deletions.
47 changes: 17 additions & 30 deletions libunwindstack/ElfInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,10 @@ bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
return false;
}

if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
return false;
}

// We could still potentially unwind without the section header
// information, so ignore any errors.
if (!ReadSectionHeaders<EhdrType, ShdrType>(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<EhdrType, PhdrType>(ehdr, load_bias);
ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
return true;
}

Expand All @@ -200,14 +195,12 @@ uint64_t ElfInterface::GetLoadBias(Memory* memory) {
}

template <typename EhdrType, typename PhdrType>
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) {
Expand Down Expand Up @@ -242,11 +235,10 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias)
break;
}
}
return true;
}

template <typename EhdrType, typename ShdrType>
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;
Expand All @@ -267,28 +259,22 @@ 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) {
// Need to go get the information about the section that contains
// 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));
Expand Down Expand Up @@ -324,7 +310,6 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
static_cast<uint64_t>(shdr.sh_offset)));
}
}
return true;
}

template <typename DynType>
Expand Down Expand Up @@ -499,11 +484,13 @@ template void ElfInterface::InitHeadersWithTemplate<uint64_t>(uint64_t);
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);

template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&,
uint64_t*);
template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&,
uint64_t*);

template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);

template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
Expand Down
4 changes: 2 additions & 2 deletions libunwindstack/include/unwindstack/ElfInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ class ElfInterface {
bool ReadAllHeaders(uint64_t* load_bias);

template <typename EhdrType, typename PhdrType>
bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);

template <typename EhdrType, typename ShdrType>
bool ReadSectionHeaders(const EhdrType& ehdr);
void ReadSectionHeaders(const EhdrType& ehdr);

template <typename DynType>
bool GetSonameWithTemplate(std::string* soname);
Expand Down
107 changes: 105 additions & 2 deletions libunwindstack/tests/ElfInterfaceTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,15 @@ class ElfInterfaceTest : public ::testing::Test {
template <typename ElfType>
void InitHeadersDebugFrameFail();

template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
void InitProgramHeadersMalformed();

template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void InitSectionHeadersMalformed();

template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void InitSectionHeadersMalformedSymData();

template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void InitSectionHeaders(uint64_t entry_size);

Expand Down Expand Up @@ -677,6 +683,29 @@ TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
InitHeadersDebugFrame<ElfInterface64Fake>();
}

template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitProgramHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> 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<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
}

TEST_F(ElfInterfaceTest, init_program_headers_malformed64) {
InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
}

template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
Expand All @@ -700,6 +729,80 @@ TEST_F(ElfInterfaceTest, init_section_headers_malformed64) {
InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}

template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformedSymData() {
std::unique_ptr<ElfInterfaceType> 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<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
}

TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) {
InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}

template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
Expand All @@ -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));

Expand Down Expand Up @@ -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));
Expand Down
6 changes: 3 additions & 3 deletions libunwindstack/tests/MapInfoGetElfTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
TestInitEhdr<Elf64_Ehdr>(&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);
Expand All @@ -341,7 +341,7 @@ TEST_F(MapInfoGetElfTest, check_device_maps) {
TestInitEhdr<Elf64_Ehdr>(&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);
Expand All @@ -368,7 +368,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
TestInitEhdr<Elf64_Ehdr>(&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];
Expand Down

0 comments on commit c7815d6

Please sign in to comment.