xref: /aosp_15_r20/external/cronet/base/debug/invalid_access_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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