diff options
author | halyavin <halyavin@chromium.org> | 2015-03-24 08:40:12 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-24 15:40:59 +0000 |
commit | c9de6f7ae8bf4b43b239812bb203b2b0e40b86dc (patch) | |
tree | f6334182d99bb5c3431dfe9bc5f064ca445ebae0 /courgette | |
parent | 34b2b43ff2d225fdf5bb7436d8ea497a092c00a9 (diff) | |
download | chromium_src-c9de6f7ae8bf4b43b239812bb203b2b0e40b86dc.zip chromium_src-c9de6f7ae8bf4b43b239812bb203b2b0e40b86dc.tar.gz chromium_src-c9de6f7ae8bf4b43b239812bb203b2b0e40b86dc.tar.bz2 |
Robust ELF header parsing.
Check all out-of-bounds errors in ELF header parsing.
BUG= none
TEST= courgette_unittests
Review URL: https://codereview.chromium.org/1031513002
Cr-Commit-Position: refs/heads/master@{#322003}
Diffstat (limited to 'courgette')
-rw-r--r-- | courgette/disassembler.cc | 5 | ||||
-rw-r--r-- | courgette/disassembler.h | 5 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.cc | 54 | ||||
-rw-r--r-- | courgette/disassembler_elf_32.h | 2 |
4 files changed, 36 insertions, 30 deletions
diff --git a/courgette/disassembler.cc b/courgette/disassembler.cc index 1b7b16e..f146b4e 100644 --- a/courgette/disassembler.cc +++ b/courgette/disassembler.cc @@ -125,8 +125,9 @@ bool Disassembler::Bad(const char* reason) { } void Disassembler::ReduceLength(size_t reduced_length) { - if (reduced_length < length_) - length_ = reduced_length; + CHECK_LE(reduced_length, length_); + length_ = reduced_length; + end_ = start_ + length_; } } // namespace courgette diff --git a/courgette/disassembler.h b/courgette/disassembler.h index 77abd41..0154ec4 100644 --- a/courgette/disassembler.h +++ b/courgette/disassembler.h @@ -54,6 +54,11 @@ class Disassembler { bool Good(); bool Bad(const char *reason); + // Returns true if the array lies within our memory region. + bool IsArrayInBounds(size_t offset, size_t elements, size_t element_size) { + return offset <= length() && elements <= (length() - offset) / element_size; + } + // These helper functions avoid the need for casts in the main code. uint16 ReadU16(const uint8* address, size_t offset) { return *reinterpret_cast<const uint16*>(address + offset); diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc index 02a31eb..be420d4 100644 --- a/courgette/disassembler_elf_32.cc +++ b/courgette/disassembler_elf_32.cc @@ -54,27 +54,26 @@ bool DisassemblerElf32::ParseHeader() { if (header_->e_shentsize != sizeof(Elf32_Shdr)) return Bad("Unexpected section header size"); - if (header_->e_shoff >= length()) - return Bad("Out of bounds section header table offset"); + if (!IsArrayInBounds(header_->e_shoff, header_->e_shnum, sizeof(Elf32_Shdr))) + return Bad("Out of bounds section header table"); section_header_table_ = (Elf32_Shdr *)OffsetToPointer(header_->e_shoff); section_header_table_size_ = header_->e_shnum; - if ((header_->e_shoff + header_->e_shnum ) >= length()) - return Bad("Out of bounds section header table"); - - if (header_->e_phoff >= length()) - return Bad("Out of bounds program header table offset"); + if (!IsArrayInBounds(header_->e_phoff, header_->e_phnum, sizeof(Elf32_Phdr))) + return Bad("Out of bounds program header table"); program_header_table_ = (Elf32_Phdr *)OffsetToPointer(header_->e_phoff); program_header_table_size_ = header_->e_phnum; - if ((header_->e_phoff + header_->e_phnum) >= length()) - return Bad("Out of bounds program header table"); + if (header_->e_shstrndx >= header_->e_shnum) + return Bad("Out of bounds string section index"); default_string_section_ = (const char *)SectionBody((int)header_->e_shstrndx); - ReduceLength(DiscoverLength()); + if (!UpdateLength()) { + return Bad("Out of bounds section or segment"); + } return Good(); } @@ -100,8 +99,8 @@ bool DisassemblerElf32::Disassemble(AssemblyProgram* target) { return true; } -uint32 DisassemblerElf32::DiscoverLength() { - uint32 result = 0; +bool DisassemblerElf32::UpdateLength() { + Elf32_Off result = 0; // Find the end of the last section for (int section_id = 0; section_id < SectionHeaderCount(); section_id++) { @@ -110,33 +109,34 @@ uint32 DisassemblerElf32::DiscoverLength() { if (section_header->sh_type == SHT_NOBITS) continue; - uint32 section_end = section_header->sh_offset + section_header->sh_size; + if (!IsArrayInBounds(section_header->sh_offset, section_header->sh_size, 1)) + return false; - if (section_end > result) - result = section_end; + Elf32_Off section_end = section_header->sh_offset + section_header->sh_size; + result = std::max(result, section_end); } // Find the end of the last segment for (int i = 0; i < ProgramSegmentHeaderCount(); i++) { const Elf32_Phdr *segment_header = ProgramSegmentHeader(i); - uint32 segment_end = segment_header->p_offset + segment_header->p_filesz; + if (!IsArrayInBounds(segment_header->p_offset, segment_header->p_filesz, 1)) + return false; - if (segment_end > result) - result = segment_end; + Elf32_Off segment_end = segment_header->p_offset + segment_header->p_filesz; + result = std::max(result, segment_end); } - uint32 section_table_end = header_->e_shoff + - (header_->e_shnum * sizeof(Elf32_Shdr)); - if (section_table_end > result) - result = section_table_end; + Elf32_Off section_table_end = header_->e_shoff + + (header_->e_shnum * sizeof(Elf32_Shdr)); + result = std::max(result, section_table_end); - uint32 segment_table_end = header_->e_phoff + - (header_->e_phnum * sizeof(Elf32_Phdr)); - if (segment_table_end > result) - result = segment_table_end; + Elf32_Off segment_table_end = header_->e_phoff + + (header_->e_phnum * sizeof(Elf32_Phdr)); + result = std::max(result, segment_table_end); - return result; + ReduceLength(result); + return true; } CheckBool DisassemblerElf32::IsValidRVA(RVA rva) const { diff --git a/courgette/disassembler_elf_32.h b/courgette/disassembler_elf_32.h index 58e2eba..608c73a 100644 --- a/courgette/disassembler_elf_32.h +++ b/courgette/disassembler_elf_32.h @@ -96,7 +96,7 @@ class DisassemblerElf32 : public Disassembler { protected: - uint32 DiscoverLength(); + bool UpdateLength(); // Misc Section Helpers |