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