exploitability_linux.cc
1 // Copyright 2013 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // exploitability_linux.cc: Linux specific exploitability engine. 30 // 31 // Provides a guess at the exploitability of the crash for the Linux 32 // platform given a minidump and process_state. 33 // 34 // Author: Matthew Riley 35 36 #ifdef HAVE_CONFIG_H 37 #include <config.h> // Must come first 38 #endif 39 40 #include "processor/exploitability_linux.h" 41 42 #include <string.h> 43 44 #include "google_breakpad/common/minidump_exception_linux.h" 45 #include "google_breakpad/processor/call_stack.h" 46 #include "google_breakpad/processor/process_state.h" 47 #include "google_breakpad/processor/stack_frame.h" 48 #ifdef __linux__ 49 #include "processor/disassembler_objdump.h" 50 #endif 51 #include "processor/logging.h" 52 53 namespace { 54 55 // Prefixes for memory mapping names. 56 constexpr char kHeapPrefix[] = "[heap"; 57 constexpr char kStackPrefix[] = "[stack"; 58 59 // This function in libc is called if the program was compiled with 60 // -fstack-protector and a function's stack canary changes. 61 constexpr char kStackCheckFailureFunction[] = "__stack_chk_fail"; 62 63 // This function in libc is called if the program was compiled with 64 // -D_FORTIFY_SOURCE=2, a function like strcpy() is called, and the runtime 65 // can determine that the call would overflow the target buffer. 66 constexpr char kBoundsCheckFailureFunction[] = "__chk_fail"; 67 68 } // namespace 69 70 namespace google_breakpad { 71 72 ExploitabilityLinux::ExploitabilityLinux(Minidump* dump, 73 ProcessState* process_state) 74 : Exploitability(dump, process_state), 75 enable_objdump_(false) { } 76 77 ExploitabilityLinux::ExploitabilityLinux(Minidump* dump, 78 ProcessState* process_state, 79 bool enable_objdump) 80 : Exploitability(dump, process_state), 81 enable_objdump_(enable_objdump) { } 82 83 84 ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { 85 // Check the crashing thread for functions suggesting a buffer overflow or 86 // stack smash. 87 if (process_state_->requesting_thread() != -1) { 88 CallStack* crashing_thread = 89 process_state_->threads()->at(process_state_->requesting_thread()); 90 const vector<StackFrame*>& crashing_thread_frames = 91 *crashing_thread->frames(); 92 for (size_t i = 0; i < crashing_thread_frames.size(); ++i) { 93 if (crashing_thread_frames[i]->function_name == 94 kStackCheckFailureFunction) { 95 return EXPLOITABILITY_HIGH; 96 } 97 98 if (crashing_thread_frames[i]->function_name == 99 kBoundsCheckFailureFunction) { 100 return EXPLOITABILITY_HIGH; 101 } 102 } 103 } 104 105 // Getting exception data. (It should exist for all minidumps.) 106 MinidumpException* exception = dump_->GetException(); 107 if (exception == NULL) { 108 BPLOG(INFO) << "No exception record."; 109 return EXPLOITABILITY_ERR_PROCESSING; 110 } 111 const MDRawExceptionStream* raw_exception_stream = exception->exception(); 112 if (raw_exception_stream == NULL) { 113 BPLOG(INFO) << "No raw exception stream."; 114 return EXPLOITABILITY_ERR_PROCESSING; 115 } 116 117 // Checking for benign exceptions that caused the crash. 118 if (this->BenignCrashTrigger(raw_exception_stream)) { 119 return EXPLOITABILITY_NONE; 120 } 121 122 // Check if the instruction pointer is in a valid instruction region 123 // by finding if it maps to an executable part of memory. 124 uint64_t instruction_ptr = 0; 125 uint64_t stack_ptr = 0; 126 127 const MinidumpContext* context = exception->GetContext(); 128 if (context == NULL) { 129 BPLOG(INFO) << "No exception context."; 130 return EXPLOITABILITY_ERR_PROCESSING; 131 } 132 133 // Getting the instruction pointer. 134 if (!context->GetInstructionPointer(&instruction_ptr)) { 135 BPLOG(INFO) << "Failed to retrieve instruction pointer."; 136 return EXPLOITABILITY_ERR_PROCESSING; 137 } 138 139 // Getting the stack pointer. 140 if (!context->GetStackPointer(&stack_ptr)) { 141 BPLOG(INFO) << "Failed to retrieve stack pointer."; 142 return EXPLOITABILITY_ERR_PROCESSING; 143 } 144 145 // Checking for the instruction pointer in a valid instruction region, 146 // a misplaced stack pointer, and an executable stack or heap. 147 if (!this->InstructionPointerInCode(instruction_ptr) || 148 this->StackPointerOffStack(stack_ptr) || 149 this->ExecutableStackOrHeap()) { 150 return EXPLOITABILITY_HIGH; 151 } 152 153 // Check for write to read only memory or invalid memory, shelling out 154 // to objdump is enabled. 155 if (enable_objdump_ && this->EndedOnIllegalWrite(instruction_ptr)) { 156 return EXPLOITABILITY_HIGH; 157 } 158 159 // There was no strong evidence suggesting exploitability, but the minidump 160 // does not appear totally benign either. 161 return EXPLOITABILITY_INTERESTING; 162 } 163 164 bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { 165 #ifndef __linux__ 166 BPLOG(INFO) << "MinGW does not support fork and exec. Terminating method."; 167 return false; 168 #else 169 // Get memory region containing instruction pointer. 170 MinidumpMemoryList* memory_list = dump_->GetMemoryList(); 171 MinidumpMemoryRegion* memory_region = 172 memory_list ? 173 memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL; 174 if (!memory_region) { 175 BPLOG(INFO) << "No memory region around instruction pointer."; 176 return false; 177 } 178 179 // Get exception data to find architecture. 180 string architecture = ""; 181 MinidumpException* exception = dump_->GetException(); 182 // This should never evaluate to true, since this should not be reachable 183 // without checking for exception data earlier. 184 if (!exception) { 185 BPLOG(INFO) << "No exception data."; 186 return false; 187 } 188 const MDRawExceptionStream* raw_exception_stream = exception->exception(); 189 const MinidumpContext* context = exception->GetContext(); 190 // This should not evaluate to true, for the same reason mentioned above. 191 if (!raw_exception_stream || !context) { 192 BPLOG(INFO) << "No exception or architecture data."; 193 return false; 194 } 195 196 DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region, 197 instruction_ptr); 198 if (!disassembler.IsValid()) { 199 BPLOG(INFO) << "Disassembling fault instruction failed."; 200 return false; 201 } 202 203 // Check if the operation is a write to memory. 204 // First, the instruction must one that can write to memory. 205 auto instruction = disassembler.operation(); 206 if (!instruction.compare("mov") || !instruction.compare("inc") || 207 !instruction.compare("dec") || !instruction.compare("and") || 208 !instruction.compare("or") || !instruction.compare("xor") || 209 !instruction.compare("not") || !instruction.compare("neg") || 210 !instruction.compare("add") || !instruction.compare("sub") || 211 !instruction.compare("shl") || !instruction.compare("shr")) { 212 uint64_t write_address = 0; 213 214 // Check that the destination is a memory address. CalculateDestAddress will 215 // return false if the destination is not a memory address. 216 if (!disassembler.CalculateDestAddress(*context, write_address)) { 217 return false; 218 } 219 220 // If the program crashed as a result of a write, the destination of 221 // the write must have been an address that did not permit writing. 222 // However, if the address is under 4k, due to program protections, 223 // the crash does not suggest exploitability for writes with such a 224 // low target address. 225 return write_address > 4096; 226 } else { 227 return false; 228 } 229 #endif // __linux__ 230 } 231 232 bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { 233 MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); 234 // Inconclusive if there are no mappings available. 235 if (!linux_maps_list) { 236 return false; 237 } 238 const MinidumpLinuxMaps* linux_maps = 239 linux_maps_list->GetLinuxMapsForAddress(stack_ptr); 240 // Checks if the stack pointer maps to a valid mapping and if the mapping 241 // is not the stack. If the mapping has no name, it is inconclusive whether 242 // it is off the stack. 243 return !linux_maps || (linux_maps->GetPathname().compare("") && 244 linux_maps->GetPathname().compare( 245 0, strlen(kStackPrefix), kStackPrefix)); 246 } 247 248 bool ExploitabilityLinux::ExecutableStackOrHeap() { 249 MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); 250 if (linux_maps_list) { 251 for (size_t i = 0; i < linux_maps_list->get_maps_count(); i++) { 252 const MinidumpLinuxMaps* linux_maps = 253 linux_maps_list->GetLinuxMapsAtIndex(i); 254 // Check for executable stack or heap for each mapping. 255 if (linux_maps && (!linux_maps->GetPathname().compare( 256 0, strlen(kStackPrefix), kStackPrefix) || 257 !linux_maps->GetPathname().compare( 258 0, strlen(kHeapPrefix), kHeapPrefix)) && 259 linux_maps->IsExecutable()) { 260 return true; 261 } 262 } 263 } 264 return false; 265 } 266 267 bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { 268 // Get Linux memory mapping from /proc/self/maps. Checking whether the 269 // region the instruction pointer is in has executable permission can tell 270 // whether it is in a valid code region. If there is no mapping for the 271 // instruction pointer, it is indicative that the instruction pointer is 272 // not within a module, which implies that it is outside a valid area. 273 MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); 274 const MinidumpLinuxMaps* linux_maps = 275 linux_maps_list ? 276 linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : NULL; 277 return linux_maps ? linux_maps->IsExecutable() : false; 278 } 279 280 bool ExploitabilityLinux::BenignCrashTrigger( 281 const MDRawExceptionStream* raw_exception_stream) { 282 // Check the cause of crash. 283 // If the exception of the crash is a benign exception, 284 // it is probably not exploitable. 285 switch (raw_exception_stream->exception_record.exception_code) { 286 case MD_EXCEPTION_CODE_LIN_SIGHUP: 287 case MD_EXCEPTION_CODE_LIN_SIGINT: 288 case MD_EXCEPTION_CODE_LIN_SIGQUIT: 289 case MD_EXCEPTION_CODE_LIN_SIGTRAP: 290 case MD_EXCEPTION_CODE_LIN_SIGABRT: 291 case MD_EXCEPTION_CODE_LIN_SIGFPE: 292 case MD_EXCEPTION_CODE_LIN_SIGKILL: 293 case MD_EXCEPTION_CODE_LIN_SIGUSR1: 294 case MD_EXCEPTION_CODE_LIN_SIGUSR2: 295 case MD_EXCEPTION_CODE_LIN_SIGPIPE: 296 case MD_EXCEPTION_CODE_LIN_SIGALRM: 297 case MD_EXCEPTION_CODE_LIN_SIGTERM: 298 case MD_EXCEPTION_CODE_LIN_SIGCHLD: 299 case MD_EXCEPTION_CODE_LIN_SIGCONT: 300 case MD_EXCEPTION_CODE_LIN_SIGSTOP: 301 case MD_EXCEPTION_CODE_LIN_SIGTSTP: 302 case MD_EXCEPTION_CODE_LIN_SIGTTIN: 303 case MD_EXCEPTION_CODE_LIN_SIGTTOU: 304 case MD_EXCEPTION_CODE_LIN_SIGURG: 305 case MD_EXCEPTION_CODE_LIN_SIGXCPU: 306 case MD_EXCEPTION_CODE_LIN_SIGXFSZ: 307 case MD_EXCEPTION_CODE_LIN_SIGVTALRM: 308 case MD_EXCEPTION_CODE_LIN_SIGPROF: 309 case MD_EXCEPTION_CODE_LIN_SIGWINCH: 310 case MD_EXCEPTION_CODE_LIN_SIGIO: 311 case MD_EXCEPTION_CODE_LIN_SIGPWR: 312 case MD_EXCEPTION_CODE_LIN_SIGSYS: 313 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: 314 return true; 315 default: 316 return false; 317 } 318 } 319 320 } // namespace google_breakpad