toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2010 Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // exploitability_win.cc: Windows specific exploitability engine.
michael@0 31 //
michael@0 32 // Provides a guess at the exploitability of the crash for the Windows
michael@0 33 // platform given a minidump and process_state.
michael@0 34 //
michael@0 35 // Author: Cris Neckar
michael@0 36
michael@0 37 #include <vector>
michael@0 38
michael@0 39 #include "processor/exploitability_win.h"
michael@0 40
michael@0 41 #include "common/scoped_ptr.h"
michael@0 42 #include "google_breakpad/common/minidump_exception_win32.h"
michael@0 43 #include "google_breakpad/processor/minidump.h"
michael@0 44 #include "processor/disassembler_x86.h"
michael@0 45 #include "processor/logging.h"
michael@0 46
michael@0 47 #include "third_party/libdisasm/libdis.h"
michael@0 48
michael@0 49 namespace google_breakpad {
michael@0 50
michael@0 51 // The cutoff that we use to judge if and address is likely an offset
michael@0 52 // from various interesting addresses.
michael@0 53 static const uint64_t kProbableNullOffset = 4096;
michael@0 54 static const uint64_t kProbableStackOffset = 8192;
michael@0 55
michael@0 56 // The various cutoffs for the different ratings.
michael@0 57 static const size_t kHighCutoff = 100;
michael@0 58 static const size_t kMediumCutoff = 80;
michael@0 59 static const size_t kLowCutoff = 50;
michael@0 60 static const size_t kInterestingCutoff = 25;
michael@0 61
michael@0 62 // Predefined incremental values for conditional weighting.
michael@0 63 static const size_t kTinyBump = 5;
michael@0 64 static const size_t kSmallBump = 20;
michael@0 65 static const size_t kMediumBump = 50;
michael@0 66 static const size_t kLargeBump = 70;
michael@0 67 static const size_t kHugeBump = 90;
michael@0 68
michael@0 69 // The maximum number of bytes to disassemble past the program counter.
michael@0 70 static const size_t kDisassembleBytesBeyondPC = 2048;
michael@0 71
michael@0 72 ExploitabilityWin::ExploitabilityWin(Minidump *dump,
michael@0 73 ProcessState *process_state)
michael@0 74 : Exploitability(dump, process_state) { }
michael@0 75
michael@0 76 ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() {
michael@0 77 MinidumpException *exception = dump_->GetException();
michael@0 78 if (!exception) {
michael@0 79 BPLOG(INFO) << "Minidump does not have exception record.";
michael@0 80 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 81 }
michael@0 82
michael@0 83 const MDRawExceptionStream *raw_exception = exception->exception();
michael@0 84 if (!raw_exception) {
michael@0 85 BPLOG(INFO) << "Could not obtain raw exception info.";
michael@0 86 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 87 }
michael@0 88
michael@0 89 const MinidumpContext *context = exception->GetContext();
michael@0 90 if (!context) {
michael@0 91 BPLOG(INFO) << "Could not obtain exception context.";
michael@0 92 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 93 }
michael@0 94
michael@0 95 MinidumpMemoryList *memory_list = dump_->GetMemoryList();
michael@0 96 bool memory_available = true;
michael@0 97 if (!memory_list) {
michael@0 98 BPLOG(INFO) << "Minidump memory segments not available.";
michael@0 99 memory_available = false;
michael@0 100 }
michael@0 101 uint64_t address = process_state_->crash_address();
michael@0 102 uint32_t exception_code = raw_exception->exception_record.exception_code;
michael@0 103
michael@0 104 uint32_t exploitability_weight = 0;
michael@0 105
michael@0 106 uint64_t stack_ptr = 0;
michael@0 107 uint64_t instruction_ptr = 0;
michael@0 108 uint64_t this_ptr = 0;
michael@0 109
michael@0 110 switch (context->GetContextCPU()) {
michael@0 111 case MD_CONTEXT_X86:
michael@0 112 stack_ptr = context->GetContextX86()->esp;
michael@0 113 instruction_ptr = context->GetContextX86()->eip;
michael@0 114 this_ptr = context->GetContextX86()->ecx;
michael@0 115 break;
michael@0 116 case MD_CONTEXT_AMD64:
michael@0 117 stack_ptr = context->GetContextAMD64()->rsp;
michael@0 118 instruction_ptr = context->GetContextAMD64()->rip;
michael@0 119 this_ptr = context->GetContextAMD64()->rcx;
michael@0 120 break;
michael@0 121 default:
michael@0 122 BPLOG(INFO) << "Unsupported architecture.";
michael@0 123 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 124 }
michael@0 125
michael@0 126 // Check if we are executing on the stack.
michael@0 127 if (instruction_ptr <= (stack_ptr + kProbableStackOffset) &&
michael@0 128 instruction_ptr >= (stack_ptr - kProbableStackOffset))
michael@0 129 exploitability_weight += kHugeBump;
michael@0 130
michael@0 131 switch (exception_code) {
michael@0 132 // This is almost certainly recursion.
michael@0 133 case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
michael@0 134 exploitability_weight += kTinyBump;
michael@0 135 break;
michael@0 136
michael@0 137 // These exceptions tend to be benign and we can generally ignore them.
michael@0 138 case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
michael@0 139 case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
michael@0 140 case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
michael@0 141 case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
michael@0 142 case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
michael@0 143 case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
michael@0 144 case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
michael@0 145 exploitability_weight += kTinyBump;
michael@0 146 break;
michael@0 147
michael@0 148 // These exceptions will typically mean that we have jumped where we
michael@0 149 // shouldn't.
michael@0 150 case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
michael@0 151 case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
michael@0 152 case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
michael@0 153 exploitability_weight += kLargeBump;
michael@0 154 break;
michael@0 155
michael@0 156 // These represent bugs in exception handlers.
michael@0 157 case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
michael@0 158 case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
michael@0 159 exploitability_weight += kSmallBump;
michael@0 160 break;
michael@0 161
michael@0 162 case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
michael@0 163 case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
michael@0 164 exploitability_weight += kHugeBump;
michael@0 165 break;
michael@0 166
michael@0 167 case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
michael@0 168 exploitability_weight += kLargeBump;
michael@0 169 break;
michael@0 170
michael@0 171 case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
michael@0 172 bool near_null = (address <= kProbableNullOffset);
michael@0 173 bool bad_read = false;
michael@0 174 bool bad_write = false;
michael@0 175 if (raw_exception->exception_record.number_parameters >= 1) {
michael@0 176 MDAccessViolationTypeWin av_type =
michael@0 177 static_cast<MDAccessViolationTypeWin>
michael@0 178 (raw_exception->exception_record.exception_information[0]);
michael@0 179 switch (av_type) {
michael@0 180 case MD_ACCESS_VIOLATION_WIN_READ:
michael@0 181 bad_read = true;
michael@0 182 if (near_null)
michael@0 183 exploitability_weight += kSmallBump;
michael@0 184 else
michael@0 185 exploitability_weight += kMediumBump;
michael@0 186 break;
michael@0 187 case MD_ACCESS_VIOLATION_WIN_WRITE:
michael@0 188 bad_write = true;
michael@0 189 if (near_null)
michael@0 190 exploitability_weight += kSmallBump;
michael@0 191 else
michael@0 192 exploitability_weight += kHugeBump;
michael@0 193 break;
michael@0 194 case MD_ACCESS_VIOLATION_WIN_EXEC:
michael@0 195 if (near_null)
michael@0 196 exploitability_weight += kSmallBump;
michael@0 197 else
michael@0 198 exploitability_weight += kHugeBump;
michael@0 199 break;
michael@0 200 default:
michael@0 201 BPLOG(INFO) << "Unrecognized access violation type.";
michael@0 202 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 203 break;
michael@0 204 }
michael@0 205 MinidumpMemoryRegion *instruction_region = 0;
michael@0 206 if (memory_available) {
michael@0 207 instruction_region =
michael@0 208 memory_list->GetMemoryRegionForAddress(instruction_ptr);
michael@0 209 }
michael@0 210 if (!near_null && instruction_region &&
michael@0 211 context->GetContextCPU() == MD_CONTEXT_X86 &&
michael@0 212 (bad_read || bad_write)) {
michael@0 213 // Perform checks related to memory around instruction pointer.
michael@0 214 uint32_t memory_offset =
michael@0 215 instruction_ptr - instruction_region->GetBase();
michael@0 216 uint32_t available_memory =
michael@0 217 instruction_region->GetSize() - memory_offset;
michael@0 218 available_memory = available_memory > kDisassembleBytesBeyondPC ?
michael@0 219 kDisassembleBytesBeyondPC : available_memory;
michael@0 220 if (available_memory) {
michael@0 221 const uint8_t *raw_memory =
michael@0 222 instruction_region->GetMemory() + memory_offset;
michael@0 223 DisassemblerX86 disassembler(raw_memory,
michael@0 224 available_memory,
michael@0 225 instruction_ptr);
michael@0 226 disassembler.NextInstruction();
michael@0 227 if (bad_read)
michael@0 228 disassembler.setBadRead();
michael@0 229 else
michael@0 230 disassembler.setBadWrite();
michael@0 231 if (disassembler.currentInstructionValid()) {
michael@0 232 // Check if the faulting instruction falls into one of
michael@0 233 // several interesting groups.
michael@0 234 switch (disassembler.currentInstructionGroup()) {
michael@0 235 case libdis::insn_controlflow:
michael@0 236 exploitability_weight += kLargeBump;
michael@0 237 break;
michael@0 238 case libdis::insn_string:
michael@0 239 exploitability_weight += kHugeBump;
michael@0 240 break;
michael@0 241 default:
michael@0 242 break;
michael@0 243 }
michael@0 244 // Loop the disassembler through the code and check if it
michael@0 245 // IDed any interesting conditions in the near future.
michael@0 246 // Multiple flags may be set so treat each equally.
michael@0 247 while (disassembler.NextInstruction() &&
michael@0 248 disassembler.currentInstructionValid() &&
michael@0 249 !disassembler.endOfBlock())
michael@0 250 continue;
michael@0 251 if (disassembler.flags() & DISX86_BAD_BRANCH_TARGET)
michael@0 252 exploitability_weight += kLargeBump;
michael@0 253 if (disassembler.flags() & DISX86_BAD_ARGUMENT_PASSED)
michael@0 254 exploitability_weight += kTinyBump;
michael@0 255 if (disassembler.flags() & DISX86_BAD_WRITE)
michael@0 256 exploitability_weight += kMediumBump;
michael@0 257 if (disassembler.flags() & DISX86_BAD_BLOCK_WRITE)
michael@0 258 exploitability_weight += kMediumBump;
michael@0 259 if (disassembler.flags() & DISX86_BAD_READ)
michael@0 260 exploitability_weight += kTinyBump;
michael@0 261 if (disassembler.flags() & DISX86_BAD_BLOCK_READ)
michael@0 262 exploitability_weight += kTinyBump;
michael@0 263 if (disassembler.flags() & DISX86_BAD_COMPARISON)
michael@0 264 exploitability_weight += kTinyBump;
michael@0 265 }
michael@0 266 }
michael@0 267 }
michael@0 268 if (!near_null && AddressIsAscii(address))
michael@0 269 exploitability_weight += kMediumBump;
michael@0 270 } else {
michael@0 271 BPLOG(INFO) << "Access violation type parameter missing.";
michael@0 272 return EXPLOITABILITY_ERR_PROCESSING;
michael@0 273 }
michael@0 274 }
michael@0 275
michael@0 276 // Based on the calculated weight we return a simplified classification.
michael@0 277 BPLOG(INFO) << "Calculated exploitability weight: " << exploitability_weight;
michael@0 278 if (exploitability_weight >= kHighCutoff)
michael@0 279 return EXPLOITABILITY_HIGH;
michael@0 280 if (exploitability_weight >= kMediumCutoff)
michael@0 281 return EXPLOITABLITY_MEDIUM;
michael@0 282 if (exploitability_weight >= kLowCutoff)
michael@0 283 return EXPLOITABILITY_LOW;
michael@0 284 if (exploitability_weight >= kInterestingCutoff)
michael@0 285 return EXPLOITABILITY_INTERESTING;
michael@0 286
michael@0 287 return EXPLOITABILITY_NONE;
michael@0 288 }
michael@0 289
michael@0 290 } // namespace google_breakpad

mercurial