diff --git a/src/processor/exploitability_linux.cc b/src/processor/exploitability_linux.cc index 13ebad12..c11aed4c 100644 --- a/src/processor/exploitability_linux.cc +++ b/src/processor/exploitability_linux.cc @@ -39,6 +39,7 @@ #include "google_breakpad/processor/process_state.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/stack_frame.h" +#include "processor/logging.h" namespace { @@ -80,7 +81,65 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { } } + // Check if the instruction pointer is in a valid instruction region + // by finding if it maps to an executable part of memory. + uint64_t instruction_ptr = 0; + + // Getting exception data. (It should exist for all minidumps.) + MinidumpException *exception = dump_->GetException(); + if (exception == NULL) { + BPLOG(INFO) << "No exception record."; + return EXPLOITABILITY_ERR_PROCESSING; + } + const MinidumpContext *context = exception->GetContext(); + if (context == NULL) { + BPLOG(INFO) << "No exception context."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Getting instruction pointer based off architecture. + uint32_t architecture = context->GetContextCPU(); + switch (architecture) { + case MD_CONTEXT_X86: + instruction_ptr = context->GetContextX86()->eip; + break; + case MD_CONTEXT_AMD64: + instruction_ptr = context->GetContextAMD64()->rip; + break; + default: + // TODO(liuandrew): Add support ARM and arm64 architectures. + BPLOG(INFO) << "Unsupported architecture."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + if (!this->InstructionPointerInCode(instruction_ptr)) { + return EXPLOITABILITY_HIGH; + } + return EXPLOITABILITY_NONE; } +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. + 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. + if (mem_info != NULL) { + return mem_info->IsExecutable(); + } + + // If the memory mapping retrieval fails, we will 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); +} + } // namespace google_breakpad diff --git a/src/processor/exploitability_linux.h b/src/processor/exploitability_linux.h index c63c0457..95607602 100644 --- a/src/processor/exploitability_linux.h +++ b/src/processor/exploitability_linux.h @@ -48,6 +48,11 @@ class ExploitabilityLinux : public Exploitability { ProcessState *process_state); virtual ExploitabilityRating CheckPlatformExploitability(); + + private: + // This method takes the address of the instruction pointer and returns + // whether the instruction pointer lies in a valid instruction region. + bool InstructionPointerInCode(uint64_t instruction_ptr); }; } // namespace google_breakpad diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc index 72994d5a..509ae230 100644 --- a/src/processor/exploitability_unittest.cc +++ b/src/processor/exploitability_unittest.cc @@ -113,5 +113,12 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ExploitabilityFor("linux_overflow.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_stacksmash.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("linux_divide_by_zero.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("linux_null_dereference.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_jmp_to_0.dmp")); + } } diff --git a/src/processor/testdata/linux_divide_by_zero.dmp b/src/processor/testdata/linux_divide_by_zero.dmp new file mode 100644 index 00000000..e7b37cf2 Binary files /dev/null and b/src/processor/testdata/linux_divide_by_zero.dmp differ diff --git a/src/processor/testdata/linux_jmp_to_0.dmp b/src/processor/testdata/linux_jmp_to_0.dmp new file mode 100644 index 00000000..40e4b15f Binary files /dev/null and b/src/processor/testdata/linux_jmp_to_0.dmp differ diff --git a/src/processor/testdata/linux_null_dereference.dmp b/src/processor/testdata/linux_null_dereference.dmp new file mode 100644 index 00000000..d216a802 Binary files /dev/null and b/src/processor/testdata/linux_null_dereference.dmp differ