1 // Copyright (c) 2010, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
29
30 #include <stdlib.h>
31 #include <unistd.h>
32
33 #include <string>
34
35 #include "breakpad_googletest_includes.h"
36 #include "common/using_std_string.h"
37 #include "google_breakpad/processor/basic_source_line_resolver.h"
38 #include "google_breakpad/processor/minidump_processor.h"
39 #include "google_breakpad/processor/process_state.h"
40 #ifndef _WIN32
41 #include "processor/exploitability_linux.h"
42 #endif // _WIN32
43 #include "processor/simple_symbol_supplier.h"
44
45 #ifndef _WIN32
46 namespace google_breakpad {
47
48 class ExploitabilityLinuxTest : public ExploitabilityLinux {
49 public:
50 using ExploitabilityLinux::CalculateAddress;
51 using ExploitabilityLinux::DisassembleBytes;
52 using ExploitabilityLinux::GetObjdumpInstructionLine;
53 using ExploitabilityLinux::TokenizeObjdumpInstruction;
54 };
55
56 class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext {
57 public:
ExploitabilityLinuxTestMinidumpContext(const MDRawContextAMD64 & context)58 explicit ExploitabilityLinuxTestMinidumpContext(
59 const MDRawContextAMD64& context) : MinidumpContext(NULL) {
60 valid_ = true;
61 SetContextAMD64(new MDRawContextAMD64(context));
62 SetContextFlags(MD_CONTEXT_AMD64);
63 }
64 };
65
66 } // namespace google_breakpad
67 #endif // _WIN32
68
69 namespace {
70
71 using google_breakpad::BasicSourceLineResolver;
72 #ifndef _WIN32
73 using google_breakpad::ExploitabilityLinuxTest;
74 using google_breakpad::ExploitabilityLinuxTestMinidumpContext;
75 #endif // _WIN32
76 using google_breakpad::MinidumpProcessor;
77 using google_breakpad::ProcessState;
78 using google_breakpad::SimpleSymbolSupplier;
79
TestDataDir()80 string TestDataDir() {
81 return string(getenv("srcdir") ? getenv("srcdir") : ".") +
82 "/src/processor/testdata";
83 }
84
85 // Find the given dump file in <srcdir>/src/processor/testdata, process it,
86 // and get the exploitability rating. Returns EXPLOITABILITY_ERR_PROCESSING
87 // if the crash dump can't be processed.
88 google_breakpad::ExploitabilityRating
ExploitabilityFor(const string & filename)89 ExploitabilityFor(const string& filename) {
90 SimpleSymbolSupplier supplier(TestDataDir() + "/symbols");
91 BasicSourceLineResolver resolver;
92 MinidumpProcessor processor(&supplier, &resolver, true);
93 processor.set_enable_objdump(true);
94 ProcessState state;
95
96 string minidump_file = TestDataDir() + "/" + filename;
97
98 if (processor.Process(minidump_file, &state) !=
99 google_breakpad::PROCESS_OK) {
100 return google_breakpad::EXPLOITABILITY_ERR_PROCESSING;
101 }
102
103 return state.exploitability();
104 }
105
TEST(ExploitabilityTest,TestWindowsEngine)106 TEST(ExploitabilityTest, TestWindowsEngine) {
107 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
108 ExploitabilityFor("ascii_read_av.dmp"));
109 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
110 ExploitabilityFor("ascii_read_av_block_write.dmp"));
111 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
112 ExploitabilityFor("ascii_read_av_clobber_write.dmp"));
113 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
114 ExploitabilityFor("ascii_read_av_conditional.dmp"));
115 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
116 ExploitabilityFor("ascii_read_av_then_jmp.dmp"));
117 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
118 ExploitabilityFor("ascii_read_av_xchg_write.dmp"));
119 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
120 ExploitabilityFor("ascii_write_av.dmp"));
121 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
122 ExploitabilityFor("ascii_write_av_arg_to_call.dmp"));
123 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE,
124 ExploitabilityFor("null_read_av.dmp"));
125 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE,
126 ExploitabilityFor("null_write_av.dmp"));
127 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE,
128 ExploitabilityFor("stack_exhaustion.dmp"));
129 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
130 ExploitabilityFor("exec_av_on_stack.dmp"));
131 ASSERT_EQ(google_breakpad::EXPLOITABILITY_MEDIUM,
132 ExploitabilityFor("write_av_non_null.dmp"));
133 ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW,
134 ExploitabilityFor("read_av_non_null.dmp"));
135 ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW,
136 ExploitabilityFor("read_av_clobber_write.dmp"));
137 ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW,
138 ExploitabilityFor("read_av_conditional.dmp"));
139 }
140
TEST(ExploitabilityTest,TestLinuxEngine)141 TEST(ExploitabilityTest, TestLinuxEngine) {
142 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
143 ExploitabilityFor("linux_null_read_av.dmp"));
144 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
145 ExploitabilityFor("linux_overflow.dmp"));
146 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
147 ExploitabilityFor("linux_stacksmash.dmp"));
148 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE,
149 ExploitabilityFor("linux_divide_by_zero.dmp"));
150 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
151 ExploitabilityFor("linux_null_dereference.dmp"));
152 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
153 ExploitabilityFor("linux_jmp_to_0.dmp"));
154 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
155 ExploitabilityFor("linux_outside_module.dmp"));
156 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE,
157 ExploitabilityFor("linux_raise_sigabrt.dmp"));
158 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
159 ExploitabilityFor("linux_inside_module_exe_region1.dmp"));
160 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
161 ExploitabilityFor("linux_inside_module_exe_region2.dmp"));
162 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
163 ExploitabilityFor("linux_stack_pointer_in_stack.dmp"));
164 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
165 ExploitabilityFor("linux_stack_pointer_in_stack_alt_name.dmp"));
166 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
167 ExploitabilityFor("linux_stack_pointer_in_module.dmp"));
168 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
169 ExploitabilityFor("linux_executable_stack.dmp"));
170 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
171 ExploitabilityFor("linux_executable_heap.dmp"));
172 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
173 ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp"));
174 #ifndef _WIN32
175 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
176 ExploitabilityFor("linux_write_to_nonwritable_module.dmp"));
177 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
178 ExploitabilityFor("linux_write_to_nonwritable_region_math.dmp"));
179 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
180 ExploitabilityFor("linux_write_to_outside_module.dmp"));
181 ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
182 ExploitabilityFor("linux_write_to_outside_module_via_math.dmp"));
183 ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
184 ExploitabilityFor("linux_write_to_under_4k.dmp"));
185 #endif // _WIN32
186 }
187
188 #ifndef _WIN32
TEST(ExploitabilityLinuxUtilsTest,DisassembleBytesTest)189 TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) {
190 ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL));
191 uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0};
192 char buffer[1024] = {0};
193 ASSERT_TRUE(ExploitabilityLinuxTest::DisassembleBytes("i386:x86-64",
194 bytes,
195 1024,
196 buffer));
197 std::stringstream objdump_stream;
198 objdump_stream.str(string(buffer));
199 string line = "";
200 while (line.find("<.data>") == string::npos)
201 getline(objdump_stream, line);
202 getline(objdump_stream, line);
203 ASSERT_EQ(line, " 0:\tc7 00 05 00 00 00 \tmov DWORD PTR [rax],0x5");
204 }
205
TEST(ExploitabilityLinuxUtilsTest,GetObjdumpInstructionLine)206 TEST(ExploitabilityLinuxUtilsTest, GetObjdumpInstructionLine) {
207 string disassebly =
208 "\n"
209 "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n"
210 "// Trying to confuse the parser 0:\n"
211 "\n"
212 "Disassembly of section .data:\n"
213 "\n"
214 "0000000000000000 <.data>:\n"
215 " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n"
216 " 6:\t5d \tpop rbp\n"
217 " 7:\tc3 \tret \n"
218 " 8:\t55 \tpush rbp\n"
219 " 9:\t48 89 e5 \tmov rbp,rsp\n"
220 " c:\t53 \tpush rbx\n"
221 " d:\t48 \trex.W\n"
222 " e:\t81 \t.byte 0x81\n";
223 string line;
224 EXPECT_TRUE(ExploitabilityLinuxTest::GetObjdumpInstructionLine(
225 disassebly.c_str(), &line));
226 EXPECT_EQ(" 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1", line);
227
228 // There is no "0:" after "<.data>:". Expected to return false.
229 disassebly =
230 "\n"
231 "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n"
232 "// Trying to confuse the parser 0:\n"
233 "\n"
234 "Disassembly of section .data:\n"
235 "\n"
236 " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n"
237 " 6:\t5d \tpop rbp\n"
238 " 7:\tc3 \tret \n"
239 " 8:\t55 \tpush rbp\n"
240 " 9:\t48 89 e5 \tmov rbp,rsp\n"
241 " d:\t48 \trex.W\n"
242 "0000000000000000 <.data>:\n"
243 " c:\t53 \tpush rbx\n";
244 EXPECT_FALSE(ExploitabilityLinuxTest::GetObjdumpInstructionLine(
245 disassebly.c_str(), &line));
246 }
247
TEST(ExploitabilityLinuxUtilsTest,TokenizeObjdumpInstructionTest)248 TEST(ExploitabilityLinuxUtilsTest, TokenizeObjdumpInstructionTest) {
249 ASSERT_FALSE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction("",
250 NULL,
251 NULL,
252 NULL));
253 string line = "0: c7 00 05 00 00 00 mov DWORD PTR [rax],0x5";
254 string operation = "";
255 string dest = "";
256 string src = "";
257 ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
258 &operation,
259 &dest,
260 &src));
261 ASSERT_EQ(operation, "mov");
262 ASSERT_EQ(dest, "[rax]");
263 ASSERT_EQ(src, "0x5");
264 line = "0: c3 ret";
265 ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
266 &operation,
267 &dest,
268 &src));
269 ASSERT_EQ(operation, "ret");
270 ASSERT_EQ(dest, "");
271 ASSERT_EQ(src, "");
272 line = "0: 5f pop rdi";
273 ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
274 &operation,
275 &dest,
276 &src));
277 ASSERT_EQ(operation, "pop");
278 ASSERT_EQ(dest, "rdi");
279 ASSERT_EQ(src, "");
280 }
281
TEST(ExploitabilityLinuxUtilsTest,CalculateAddressTest)282 TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) {
283 MDRawContextAMD64 raw_context;
284 raw_context.rdx = 12345;
285 ExploitabilityLinuxTestMinidumpContext context(raw_context);
286 ASSERT_EQ(context.GetContextAMD64()->rdx, 12345U);
287 ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("", context, NULL));
288 uint64_t write_address = 0;
289 ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx-0x4D2",
290 context,
291 &write_address));
292 ASSERT_EQ(write_address, 11111U);
293 ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx+0x4D2",
294 context,
295 &write_address));
296 ASSERT_EQ(write_address, 13579U);
297 ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("rdx+rax",
298 context,
299 &write_address));
300 ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("0x3482+0x4D2",
301 context,
302 &write_address));
303 }
304 #endif // _WIN32
305
306 } // namespace
307