summaryrefslogtreecommitdiffstats
path: root/courgette
diff options
context:
space:
mode:
authorhalyavin <halyavin@chromium.org>2015-03-24 08:40:12 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-24 15:40:59 +0000
commitc9de6f7ae8bf4b43b239812bb203b2b0e40b86dc (patch)
treef6334182d99bb5c3431dfe9bc5f064ca445ebae0 /courgette
parent34b2b43ff2d225fdf5bb7436d8ea497a092c00a9 (diff)
downloadchromium_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.cc5
-rw-r--r--courgette/disassembler.h5
-rw-r--r--courgette/disassembler_elf_32.cc54
-rw-r--r--courgette/disassembler_elf_32.h2
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