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