• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/debug/invalid_access_win.h"
11 
12 #include <windows.h>
13 
14 #include <intrin.h>
15 #include <stdlib.h>
16 
17 #include "base/check.h"
18 #include "base/notreached.h"
19 #include "build/build_config.h"
20 
21 namespace base {
22 namespace debug {
23 namespace win {
24 
25 namespace {
26 
27 #if defined(ARCH_CPU_X86_FAMILY)
28 // On x86/x64 systems, nop instructions are generally 1 byte.
29 static constexpr int kNopInstructionSize = 1;
30 #elif defined(ARCH_CPU_ARM64)
31 // On Arm systems, all instructions are 4 bytes, fixed size.
32 static constexpr int kNopInstructionSize = 4;
33 #else
34 #error "Unsupported architecture"
35 #endif
36 
37 // Function that can be jumped midway into safely.
nop_sled()38 __attribute__((naked)) int nop_sled() {
39   asm("nop\n"
40       "nop\n"
41       "ret\n");
42 }
43 
44 using FuncType = decltype(&nop_sled);
45 
IndirectCall(FuncType * func)46 void IndirectCall(FuncType* func) {
47   // This code always generates CFG guards.
48   (*func)();
49 }
50 
51 }  // namespace
52 
TerminateWithHeapCorruption()53 void TerminateWithHeapCorruption() {
54   __try {
55     HANDLE heap = ::HeapCreate(0, 0, 0);
56     CHECK(heap);
57     CHECK(HeapSetInformation(heap, HeapEnableTerminationOnCorruption, nullptr,
58                              0));
59     void* addr = ::HeapAlloc(heap, 0, 0x1000);
60     CHECK(addr);
61     // Corrupt heap header.
62     char* addr_mutable = reinterpret_cast<char*>(addr);
63     memset(addr_mutable - sizeof(addr), 0xCC, sizeof(addr));
64 
65     HeapFree(heap, 0, addr);
66     HeapDestroy(heap);
67   } __except (EXCEPTION_EXECUTE_HANDLER) {
68     // Heap corruption exception should never be caught.
69     NOTREACHED();
70   }
71   // Should never reach here.
72   abort();
73 }
74 
TerminateWithControlFlowViolation()75 void TerminateWithControlFlowViolation() {
76   // Call into the middle of the NOP sled.
77   FuncType func = reinterpret_cast<FuncType>(
78       (reinterpret_cast<uintptr_t>(nop_sled)) + kNopInstructionSize);
79   __try {
80     // Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers.
81     IndirectCall(&func);
82   } __except (EXCEPTION_EXECUTE_HANDLER) {
83     // CFG fast fail should never be caught.
84     NOTREACHED();
85   }
86   // Should only reach here if CFG is disabled.
87   abort();
88 }
89 
90 }  // namespace win
91 }  // namespace debug
92 }  // namespace base
93