/ src / processor / exploitability_linux.cc
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