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