From e3687f92c22db45e8fd7d2b83884edcbb3685d6e Mon Sep 17 00:00:00 2001 From: "Liu.andrew.x@gmail.com" Date: Sat, 15 Aug 2015 00:37:14 +0000 Subject: [PATCH] Add check for executable stack/heap when rating Linux exploitability. This CL also consequentially adds a public method to get the number of mappings in a Linux minidump. R=ivanpe@chromium.org Review URL: https://codereview.chromium.org/1291603002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1488 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/google_breakpad/processor/minidump.h | 3 +++ src/processor/exploitability_linux.cc | 21 +++++++++++++++++- src/processor/exploitability_linux.h | 8 +++++-- src/processor/exploitability_unittest.cc | 4 ++++ .../testdata/linux_executable_heap.dmp | Bin 0 -> 38761 bytes .../testdata/linux_executable_stack.dmp | Bin 0 -> 38794 bytes 6 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/processor/testdata/linux_executable_heap.dmp create mode 100644 src/processor/testdata/linux_executable_stack.dmp diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index ce1af851..2b5025e4 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -916,6 +916,9 @@ class MinidumpLinuxMapsList : public MinidumpStream { public: virtual ~MinidumpLinuxMapsList(); + // Get number of mappings. + unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } + // Get mapping at the given memory address. The caller owns the pointer. const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const; // Get mapping at the given index. The caller owns the pointer. diff --git a/src/processor/exploitability_linux.cc b/src/processor/exploitability_linux.cc index 0fae727c..46cad318 100644 --- a/src/processor/exploitability_linux.cc +++ b/src/processor/exploitability_linux.cc @@ -124,7 +124,8 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { // Checking for the instruction pointer in a valid instruction region. if (!this->InstructionPointerInCode(instruction_ptr) || - this->StackPointerOffStack(stack_ptr)) { + this->StackPointerOffStack(stack_ptr) || + this->ExecutableStackOrHeap()) { return EXPLOITABILITY_HIGH; } @@ -149,6 +150,24 @@ bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { linux_maps->GetPathname().compare("[stack]")); } +bool ExploitabilityLinux::ExecutableStackOrHeap() { + MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + if (linux_maps_list) { + for (size_t i = 0; i < linux_maps_list->get_maps_count(); i++) { + const MinidumpLinuxMaps *linux_maps = + linux_maps_list->GetLinuxMapsAtIndex(i); + // Check for executable stack or heap for each mapping. + if (linux_maps && + (!linux_maps->GetPathname().compare("[stack]") || + !linux_maps->GetPathname().compare("[heap]")) && + linux_maps->IsExecutable()) { + return true; + } + } + } + return false; +} + bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { // Get Linux memory mapping from /proc/self/maps. Checking whether the // region the instruction pointer is in has executable permission can tell diff --git a/src/processor/exploitability_linux.h b/src/processor/exploitability_linux.h index 9d9fa695..857185b4 100644 --- a/src/processor/exploitability_linux.h +++ b/src/processor/exploitability_linux.h @@ -51,17 +51,21 @@ class ExploitabilityLinux : public Exploitability { virtual ExploitabilityRating CheckPlatformExploitability(); private: - // This method takes the address of the instruction pointer and returns + // 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); - // This method checks the exception that triggered the creation of the + // Checks the exception that triggered the creation of the // minidump and reports whether the exception suggests no exploitability. bool BenignCrashTrigger(const MDRawExceptionStream *raw_exception_stream); // Checks if the stack pointer points to a memory mapping that is not // labelled as the stack. bool StackPointerOffStack(uint64_t stack_ptr); + + // Checks if the stack or heap are marked executable according + // to the memory mappings. + bool ExecutableStackOrHeap(); }; } // namespace google_breakpad diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc index db668d80..db7f1cb0 100644 --- a/src/processor/exploitability_unittest.cc +++ b/src/processor/exploitability_unittest.cc @@ -131,6 +131,10 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ExploitabilityFor("linux_stack_pointer_in_stack.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_stack_pointer_in_module.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_executable_stack.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_executable_heap.dmp")); } } diff --git a/src/processor/testdata/linux_executable_heap.dmp b/src/processor/testdata/linux_executable_heap.dmp new file mode 100644 index 0000000000000000000000000000000000000000..f8c807fac78c50145c59facac17e13ed5da1e9b9 GIT binary patch literal 38761 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 literal 0 HcmV?d00001 diff --git a/src/processor/testdata/linux_executable_stack.dmp b/src/processor/testdata/linux_executable_stack.dmp new file mode 100644 index 0000000000000000000000000000000000000000..c424cb20e43101b0673708f59ee89e169f150a7e GIT binary patch literal 38794 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