Add check for Linux minidump ending on bad write for exploitability rating.

If a crash occurred as a result to a write to unwritable memory, it is reason
to suggest exploitability. The processor checks for a bad write by
disassembling the command that caused the crash by piping the raw bytes near
the instruction pointer through objdump. This allows the processor to see if
the instruction that caused the crash is a write to memory and where the
target of the address is located.

R=ivanpe@chromium.org

Review URL: https://codereview.chromium.org/1273823004

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1497 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
Liu.andrew.x@gmail.com
2015-08-21 16:22:19 +00:00
parent 7b1ec78407
commit f252ca8ed1
13 changed files with 584 additions and 8 deletions

View File

@@ -37,11 +37,41 @@
#include "google_breakpad/processor/basic_source_line_resolver.h"
#include "google_breakpad/processor/minidump_processor.h"
#include "google_breakpad/processor/process_state.h"
#ifndef _WIN32
#include "processor/exploitability_linux.h"
#endif // _WIN32
#include "processor/simple_symbol_supplier.h"
#ifndef _WIN32
namespace google_breakpad {
class ExploitabilityLinuxTest : public ExploitabilityLinux {
public:
using ExploitabilityLinux::DisassembleBytes;
using ExploitabilityLinux::TokenizeObjdumpInstruction;
using ExploitabilityLinux::CalculateAddress;
};
class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext {
public:
explicit ExploitabilityLinuxTestMinidumpContext(
const MDRawContextAMD64& context) : MinidumpContext(NULL) {
valid_ = true;
SetContextAMD64(new MDRawContextAMD64(context));
SetContextFlags(MD_CONTEXT_AMD64);
}
};
} // namespace google_breakpad
#endif // _WIN32
namespace {
using google_breakpad::BasicSourceLineResolver;
#ifndef _WIN32
using google_breakpad::ExploitabilityLinuxTest;
using google_breakpad::ExploitabilityLinuxTestMinidumpContext;
#endif // _WIN32
using google_breakpad::MinidumpProcessor;
using google_breakpad::ProcessState;
using google_breakpad::SimpleSymbolSupplier;
@@ -59,6 +89,7 @@ ExploitabilityFor(const string& filename) {
SimpleSymbolSupplier supplier(TestDataDir() + "/symbols");
BasicSourceLineResolver resolver;
MinidumpProcessor processor(&supplier, &resolver, true);
processor.set_enable_objdump(true);
ProcessState state;
string minidump_file = TestDataDir() + "/" + filename;
@@ -135,6 +166,95 @@ TEST(ExploitabilityTest, TestLinuxEngine) {
ExploitabilityFor("linux_executable_stack.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_executable_heap.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp"));
#ifndef _WIN32
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_write_to_nonwritable_module.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_write_to_nonwritable_region_math.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_write_to_outside_module.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_write_to_outside_module_via_math.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
ExploitabilityFor("linux_write_to_under_4k.dmp"));
#endif // _WIN32
}
#ifndef _WIN32
TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) {
ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL));
uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0};
char buffer[1024] = {0};
ASSERT_TRUE(ExploitabilityLinuxTest::DisassembleBytes("i386:x86-64",
bytes,
1024,
buffer));
std::stringstream objdump_stream;
objdump_stream.str(string(buffer));
string line = "";
while ((line.find("0:") == string::npos) && getline(objdump_stream, line)) {
}
ASSERT_EQ(line, " 0:\tc7 00 05 00 00 00 \tmov DWORD PTR [rax],0x5");
}
TEST(ExploitabilityLinuxUtilsTest, TokenizeObjdumpInstructionTest) {
ASSERT_FALSE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction("",
NULL,
NULL,
NULL));
string line = "0: c7 00 05 00 00 00 mov DWORD PTR [rax],0x5";
string operation = "";
string dest = "";
string src = "";
ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
&operation,
&dest,
&src));
ASSERT_EQ(operation, "mov");
ASSERT_EQ(dest, "[rax]");
ASSERT_EQ(src, "0x5");
line = "0: c3 ret";
ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
&operation,
&dest,
&src));
ASSERT_EQ(operation, "ret");
ASSERT_EQ(dest, "");
ASSERT_EQ(src, "");
line = "0: 5f pop rdi";
ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
&operation,
&dest,
&src));
ASSERT_EQ(operation, "pop");
ASSERT_EQ(dest, "rdi");
ASSERT_EQ(src, "");
}
TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) {
MDRawContextAMD64 raw_context;
raw_context.rdx = 12345;
ExploitabilityLinuxTestMinidumpContext context(raw_context);
ASSERT_EQ(context.GetContextAMD64()->rdx, 12345);
ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("", context, NULL));
uint64_t write_address = 0;
ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx-0x4D2",
context,
&write_address));
ASSERT_EQ(write_address, 11111);
ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx+0x4D2",
context,
&write_address));
ASSERT_EQ(write_address, 13579);
ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("rdx+rax",
context,
&write_address));
ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("0x3482+0x4D2",
context,
&write_address));
}
#endif // _WIN32
} // namespace