Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5acf069a authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Be permissive about badly formed elf files.

Here is the allowable issues with an elf file that will not result in an error:
- The program headers/section headers offset points to unreadable memory.
- Allow missing program header and/or section headers.
- Allow a symbol table section header to point to invalid symbol table values.

There is no real reason to require the elf file be perfect. Everything in
the code has sane defaults, so any missing information won't cause any
problems.

This gets rid of the warning that occurs any time an elf is loaded
from memory. In memory elf files never contain all of the section headers,
and do not contain the symbol table data.

Update tests to test these new cases.

Test: Builds and unit tests all pass.
Change-Id: Iaefe2cd6b6c965a01ed425a112d6afae339f3b78
parent d560f39f
Loading
Loading
Loading
Loading
+17 −30
Original line number Diff line number Diff line
@@ -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;
}

@@ -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) {
@@ -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;
@@ -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<uint64_t>(shdr.sh_offset)));
    }
  }
  return true;
}

template <typename DynType>
@@ -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*);
+2 −2
Original line number Diff line number Diff line
@@ -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);
+105 −2
Original line number Diff line number Diff line
@@ -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);

@@ -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_));
@@ -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_));
@@ -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));
+3 −3
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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];