Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Unified Diff: src/processor/exploitability_linux.cc

Issue 1233973002: Add ELF header analysis when checking for instruction pointer in code. (Closed) Base URL: http://google-breakpad.googlecode.com/svn/trunk/
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/processor/exploitability_linux.h ('k') | src/processor/exploitability_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/processor/exploitability_linux.cc
===================================================================
--- src/processor/exploitability_linux.cc (revision 1471)
+++ src/processor/exploitability_linux.cc (working copy)
@@ -36,6 +36,8 @@
#include "processor/exploitability_linux.h"
+#include <elf.h>
+
#include "google_breakpad/common/minidump_exception_linux.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/process_state.h"
@@ -109,8 +111,13 @@
return EXPLOITABILITY_ERR_PROCESSING;
}
+ if (this->ArchitectureType() == UNSUPPORTED_ARCHITECTURE) {
+ BPLOG(INFO) << "Unsupported architecture.";
+ return EXPLOITABILITY_ERR_PROCESSING;
+ }
// Getting the instruction pointer.
if (!context->GetInstructionPointer(&instruction_ptr)) {
+ BPLOG(INFO) << "Failed to retrieve instruction pointer.";
return EXPLOITABILITY_ERR_PROCESSING;
}
@@ -119,35 +126,161 @@
return EXPLOITABILITY_HIGH;
}
+ // There was no strong evidence suggesting exploitability, but the minidump
+ // does not appear totally benign either.
return EXPLOITABILITY_INTERESTING;
}
+LinuxArchitectureType ExploitabilityLinux::ArchitectureType() {
+ // GetContextCPU() should have already been successfully called before
+ // calling this method. Thus there should be a raw exception stream for
+ // the minidump.
+ MinidumpException *exception = dump_->GetException();
+ const DumpContext *dump_context =
+ exception ?
+ exception->GetContext() : NULL;
+ if (dump_context == NULL) {
+ BPLOG(INFO) << "No raw dump context.";
+ return UNSUPPORTED_ARCHITECTURE;
+ }
+
+ // Check the architecture type.
+ switch (dump_context->GetContextCPU()) {
+ case MD_CONTEXT_ARM:
+ case MD_CONTEXT_X86:
+ return LINUX_32_BIT;
+ case MD_CONTEXT_ARM64:
+ case MD_CONTEXT_AMD64:
+ return LINUX_64_BIT;
+ default:
+ // This should not happen. The four architectures above should be
+ // the only Linux architectures.
+ BPLOG(INFO) << "Unsupported architecture.";
+ return UNSUPPORTED_ARCHITECTURE;
+ }
+}
+
bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
- // Here we get memory mapping. Most minidumps will not contain a memory
- // mapping, so we will commonly resort to checking modules.
+ // Get memory mapping. Most minidumps will not contain a memory
+ // mapping, so processing will commonly resort to checking modules.
MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList();
const MinidumpMemoryInfo *mem_info =
mem_info_list ?
mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL;
- // Checking if the memory mapping at the instruction pointer is executable.
- // If there is no memory mapping, we will use the modules as reference.
+ // Check if the memory mapping at the instruction pointer is executable.
+ // If there is no memory mapping, processing will use modules as reference.
if (mem_info != NULL) {
return mem_info->IsExecutable();
}
- // If the memory mapping retrieval fails, we will check the modules
+ // If the memory mapping retrieval fails, check the modules
// to see if the instruction pointer is inside a module.
- // TODO(liuandrew): Check if the instruction pointer lies in an executable
- // region within the module.
MinidumpModuleList *minidump_module_list = dump_->GetModuleList();
- return !minidump_module_list ||
- minidump_module_list->GetModuleForAddress(instruction_ptr);
+ const MinidumpModule *minidump_module =
+ minidump_module_list ?
+ minidump_module_list->GetModuleForAddress(instruction_ptr) : NULL;
+
+ // If the instruction pointer isn't in a module, return false.
+ if (minidump_module == NULL) {
+ return false;
+ }
+
+ // Get ELF header data from the instruction pointer's module.
+ const uint64_t base_address = minidump_module->base_address();
+ MinidumpMemoryList *memory_list = dump_->GetMemoryList();
+ MinidumpMemoryRegion *memory_region =
+ memory_list ?
+ memory_list->GetMemoryRegionForAddress(base_address) : NULL;
+
+ // The minidump does not have the correct memory region.
+ // This returns true because even though there is no memory data available,
+ // the evidence so far suggests that the instruction pointer is not at a
+ // bad location.
+ if (memory_region == NULL) {
+ return true;
+ }
+
+ // Examine ELF headers. Depending on the architecture, the size of the
+ // ELF headers can differ.
+ LinuxArchitectureType architecture = this->ArchitectureType();
+ if (architecture == LINUX_32_BIT) {
+ // Check if the ELF header is within the memory region and if the
+ // instruction pointer lies within the ELF header.
+ if (memory_region->GetSize() < sizeof(Elf32_Ehdr) ||
+ instruction_ptr < base_address + sizeof(Elf32_Ehdr)) {
+ return false;
+ }
+ // Load 32-bit ELF header.
+ Elf32_Ehdr header;
+ this->LoadElfHeader(memory_region, base_address, &header);
+ // Check if the program header table is within the memory region, and
+ // validate that the program header entry size is correct.
+ if (header.e_phentsize != sizeof(Elf32_Phdr) ||
+ memory_region->GetSize() <
+ header.e_phoff +
+ ((uint64_t) header.e_phentsize * (uint64_t) header.e_phnum)) {
+ return false;
+ }
+ // Load 32-bit Program Header Table.
+ scoped_array<Elf32_Phdr> program_headers(new Elf32_Phdr[header.e_phnum]);
+ this->LoadElfHeaderTable(memory_region,
+ base_address + header.e_phoff,
+ header.e_phnum,
+ program_headers.get());
+ // Find correct program header that corresponds to the instruction pointer.
+ for (int i = 0; i < header.e_phnum; i++) {
+ const Elf32_Phdr& program_header = program_headers[i];
+ // Check if instruction pointer lies within this program header's region.
+ if (instruction_ptr >= program_header.p_vaddr &&
+ instruction_ptr < program_header.p_vaddr + program_header.p_memsz) {
+ // Return whether this program header region is executable.
+ return program_header.p_flags & PF_X;
+ }
+ }
+ } else if (architecture == LINUX_64_BIT) {
+ // Check if the ELF header is within the memory region and if the
+ // instruction pointer lies within the ELF header.
+ if (memory_region->GetSize() < sizeof(Elf64_Ehdr) ||
+ instruction_ptr < base_address + sizeof(Elf64_Ehdr)) {
+ return false;
+ }
+ // Load 64-bit ELF header.
+ Elf64_Ehdr header;
+ this->LoadElfHeader(memory_region, base_address, &header);
+ // Check if the program header table is within the memory region, and
+ // validate that the program header entry size is correct.
+ if (header.e_phentsize != sizeof(Elf64_Phdr) ||
+ memory_region->GetSize() <
+ header.e_phoff +
+ ((uint64_t) header.e_phentsize * (uint64_t) header.e_phnum)) {
+ return false;
+ }
+ // Load 64-bit Program Header Table.
+ scoped_array<Elf64_Phdr> program_headers(new Elf64_Phdr[header.e_phnum]);
+ this->LoadElfHeaderTable(memory_region,
+ base_address + header.e_phoff,
+ header.e_phnum,
+ program_headers.get());
+ // Find correct program header that corresponds to the instruction pointer.
+ for (int i = 0; i < header.e_phnum; i++) {
+ const Elf64_Phdr& program_header = program_headers[i];
+ // Check if instruction pointer lies within this program header's region.
+ if (instruction_ptr >= program_header.p_vaddr &&
+ instruction_ptr < program_header.p_vaddr + program_header.p_memsz) {
+ // Return whether this program header region is executable.
+ return program_header.p_flags & PF_X;
+ }
+ }
+ }
+
+ // The instruction pointer was not in an area identified by the ELF headers.
+ return false;
}
bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
*raw_exception_stream) {
- // Here we check the cause of crash.
+ // Check the cause of crash.
// If the exception of the crash is a benign exception,
// it is probably not exploitable.
switch (raw_exception_stream->exception_record.exception_code) {
« no previous file with comments | « src/processor/exploitability_linux.h ('k') | src/processor/exploitability_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698