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