PageRenderTime 42ms CodeModel.GetById 14ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/processor/exploitability_win.cc

http://github.com/tomahawk-player/tomahawk
C++ | 290 lines | 209 code | 29 blank | 52 comment | 36 complexity | 377445abcc374fc109d1a15a20321e87 MD5 | raw file
  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// exploitability_win.cc: Windows specific exploitability engine.
 31//
 32// Provides a guess at the exploitability of the crash for the Windows
 33// platform given a minidump and process_state.
 34//
 35// Author: Cris Neckar
 36
 37#include <vector>
 38
 39#include "processor/exploitability_win.h"
 40
 41#include "google_breakpad/common/minidump_exception_win32.h"
 42#include "google_breakpad/processor/minidump.h"
 43#include "processor/disassembler_x86.h"
 44#include "processor/logging.h"
 45#include "processor/scoped_ptr.h"
 46
 47#include "third_party/libdisasm/libdis.h"
 48
 49namespace google_breakpad {
 50
 51// The cutoff that we use to judge if and address is likely an offset
 52// from various interesting addresses.
 53static const u_int64_t kProbableNullOffset = 4096;
 54static const u_int64_t kProbableStackOffset = 8192;
 55
 56// The various cutoffs for the different ratings.
 57static const size_t kHighCutoff        = 100;
 58static const size_t kMediumCutoff      = 80;
 59static const size_t kLowCutoff         = 50;
 60static const size_t kInterestingCutoff = 25;
 61
 62// Predefined incremental values for conditional weighting.
 63static const size_t kTinyBump          = 5;
 64static const size_t kSmallBump         = 20;
 65static const size_t kMediumBump        = 50;
 66static const size_t kLargeBump         = 70;
 67static const size_t kHugeBump          = 90;
 68
 69// The maximum number of bytes to disassemble past the program counter.
 70static const size_t kDisassembleBytesBeyondPC = 2048;
 71
 72ExploitabilityWin::ExploitabilityWin(Minidump *dump,
 73                                     ProcessState *process_state)
 74    : Exploitability(dump, process_state) { }
 75
 76ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() {
 77  MinidumpException *exception = dump_->GetException();
 78  if (!exception) {
 79    BPLOG(INFO) << "Minidump does not have exception record.";
 80    return EXPLOITABILITY_ERR_PROCESSING;
 81  }
 82
 83  const MDRawExceptionStream *raw_exception = exception->exception();
 84  if (!raw_exception) {
 85    BPLOG(INFO) << "Could not obtain raw exception info.";
 86    return EXPLOITABILITY_ERR_PROCESSING;
 87  }
 88
 89  const MinidumpContext *context = exception->GetContext();
 90  if (!context) {
 91    BPLOG(INFO) << "Could not obtain exception context.";
 92    return EXPLOITABILITY_ERR_PROCESSING;
 93  }
 94
 95  MinidumpMemoryList *memory_list = dump_->GetMemoryList();
 96  bool memory_available = true;
 97  if (!memory_list) {
 98    BPLOG(INFO) << "Minidump memory segments not available.";
 99    memory_available = false;
100  }
101  u_int64_t address = process_state_->crash_address();
102  u_int32_t exception_code = raw_exception->exception_record.exception_code;
103
104  u_int32_t exploitability_weight = 0;
105
106  u_int64_t stack_ptr = 0;
107  u_int64_t instruction_ptr = 0;
108  u_int64_t this_ptr = 0;
109
110  switch (context->GetContextCPU()) {
111    case MD_CONTEXT_X86:
112      stack_ptr = context->GetContextX86()->esp;
113      instruction_ptr = context->GetContextX86()->eip;
114      this_ptr = context->GetContextX86()->ecx;
115      break;
116    case MD_CONTEXT_AMD64:
117      stack_ptr = context->GetContextAMD64()->rsp;
118      instruction_ptr = context->GetContextAMD64()->rip;
119      this_ptr = context->GetContextAMD64()->rcx;
120      break;
121    default:
122      BPLOG(INFO) << "Unsupported architecture.";
123      return EXPLOITABILITY_ERR_PROCESSING;
124  }
125
126  // Check if we are executing on the stack.
127  if (instruction_ptr <= (stack_ptr + kProbableStackOffset) &&
128      instruction_ptr >= (stack_ptr - kProbableStackOffset))
129    exploitability_weight += kHugeBump;
130
131  switch (exception_code) {
132    // This is almost certainly recursion.
133    case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
134      exploitability_weight += kTinyBump;
135      break;
136
137    // These exceptions tend to be benign and we can generally ignore them.
138    case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
139    case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
140    case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
141    case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
142    case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
143    case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
144    case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
145      exploitability_weight += kTinyBump;
146      break;
147
148    // These exceptions will typically mean that we have jumped where we
149    // shouldn't.
150    case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
151    case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
152    case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
153      exploitability_weight += kLargeBump;
154      break;
155
156    // These represent bugs in exception handlers.
157    case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
158    case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
159      exploitability_weight += kSmallBump;
160      break;
161
162    case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
163    case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
164      exploitability_weight += kHugeBump;
165      break;
166
167    case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
168      exploitability_weight += kLargeBump;
169      break;
170
171    case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
172      bool near_null = (address <= kProbableNullOffset);
173      bool bad_read = false;
174      bool bad_write = false;
175      if (raw_exception->exception_record.number_parameters >= 1) {
176        MDAccessViolationTypeWin av_type =
177            static_cast<MDAccessViolationTypeWin>
178            (raw_exception->exception_record.exception_information[0]);
179        switch (av_type) {
180          case MD_ACCESS_VIOLATION_WIN_READ:
181            bad_read = true;
182            if (near_null)
183              exploitability_weight += kSmallBump;
184            else
185              exploitability_weight += kMediumBump;
186            break;
187          case MD_ACCESS_VIOLATION_WIN_WRITE:
188            bad_write = true;
189            if (near_null)
190              exploitability_weight += kSmallBump;
191            else
192              exploitability_weight += kHugeBump;
193            break;
194          case MD_ACCESS_VIOLATION_WIN_EXEC:
195            if (near_null)
196              exploitability_weight += kSmallBump;
197            else
198              exploitability_weight += kHugeBump;
199            break;
200          default:
201            BPLOG(INFO) << "Unrecognized access violation type.";
202            return EXPLOITABILITY_ERR_PROCESSING;
203            break;
204        }
205        MinidumpMemoryRegion *instruction_region = 0;
206        if (memory_available) {
207          instruction_region =
208              memory_list->GetMemoryRegionForAddress(instruction_ptr);
209        }
210        if (!near_null && instruction_region &&
211            context->GetContextCPU() == MD_CONTEXT_X86 &&
212            (bad_read || bad_write)) {
213          // Perform checks related to memory around instruction pointer.
214          u_int32_t memory_offset =
215              instruction_ptr - instruction_region->GetBase();
216          u_int32_t available_memory =
217              instruction_region->GetSize() - memory_offset;
218          available_memory = available_memory > kDisassembleBytesBeyondPC ?
219              kDisassembleBytesBeyondPC : available_memory;
220          if (available_memory) {
221            const u_int8_t *raw_memory =
222                instruction_region->GetMemory() + memory_offset;
223            DisassemblerX86 disassembler(raw_memory,
224                                         available_memory,
225                                         instruction_ptr);
226            disassembler.NextInstruction();
227            if (bad_read)
228              disassembler.setBadRead();
229            else
230              disassembler.setBadWrite();
231            if (disassembler.currentInstructionValid()) {
232              // Check if the faulting instruction falls into one of
233              // several interesting groups.
234              switch (disassembler.currentInstructionGroup()) {
235                case libdis::insn_controlflow:
236                  exploitability_weight += kLargeBump;
237                  break;
238                case libdis::insn_string:
239                  exploitability_weight += kHugeBump;
240                  break;
241                default:
242                  break;
243              }
244              // Loop the disassembler through the code and check if it
245              // IDed any interesting conditions in the near future.
246              // Multiple flags may be set so treat each equally.
247              while (disassembler.NextInstruction() &&
248                     disassembler.currentInstructionValid() &&
249                     !disassembler.endOfBlock())
250                continue;
251              if (disassembler.flags() & DISX86_BAD_BRANCH_TARGET)
252                exploitability_weight += kLargeBump;
253              if (disassembler.flags() & DISX86_BAD_ARGUMENT_PASSED)
254                exploitability_weight += kTinyBump;
255              if (disassembler.flags() & DISX86_BAD_WRITE)
256                exploitability_weight += kMediumBump;
257              if (disassembler.flags() & DISX86_BAD_BLOCK_WRITE)
258                exploitability_weight += kMediumBump;
259              if (disassembler.flags() & DISX86_BAD_READ)
260                exploitability_weight += kTinyBump;
261              if (disassembler.flags() & DISX86_BAD_BLOCK_READ)
262                exploitability_weight += kTinyBump;
263              if (disassembler.flags() & DISX86_BAD_COMPARISON)
264                exploitability_weight += kTinyBump;
265            }
266          }
267        }
268        if (!near_null && AddressIsAscii(address))
269          exploitability_weight += kMediumBump;
270      } else {
271        BPLOG(INFO) << "Access violation type parameter missing.";
272        return EXPLOITABILITY_ERR_PROCESSING;
273      }
274  }
275
276  // Based on the calculated weight we return a simplified classification.
277  BPLOG(INFO) << "Calculated exploitability weight: " << exploitability_weight;
278  if (exploitability_weight >= kHighCutoff)
279    return EXPLOITABILITY_HIGH;
280  if (exploitability_weight >= kMediumCutoff)
281    return EXPLOITABLITY_MEDIUM;
282  if (exploitability_weight >= kLowCutoff)
283    return EXPLOITABILITY_LOW;
284  if (exploitability_weight >= kInterestingCutoff)
285    return EXPLOITABILITY_INTERESTING;
286
287  return EXPLOITABILITY_NONE;
288}
289
290}  // namespace google_breakpad