invalid_access_win.cc 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/debug/invalid_access_win.h"
  5. #include <intrin.h>
  6. #include <stdlib.h>
  7. #include <windows.h>
  8. #include "base/check.h"
  9. #include "base/win/windows_version.h"
  10. #include "build/build_config.h"
  11. namespace base {
  12. namespace debug {
  13. namespace win {
  14. namespace {
  15. #if defined(ARCH_CPU_X86_FAMILY)
  16. // On x86/x64 systems, nop instructions are generally 1 byte.
  17. static constexpr int kNopInstructionSize = 1;
  18. #elif defined(ARCH_CPU_ARM64)
  19. // On Arm systems, all instructions are 4 bytes, fixed size.
  20. static constexpr int kNopInstructionSize = 4;
  21. #else
  22. #error "Unsupported architecture"
  23. #endif
  24. // Function that can be jumped midway into safely.
  25. __attribute__((naked)) int nop_sled() {
  26. asm("nop\n"
  27. "nop\n"
  28. "ret\n");
  29. }
  30. using FuncType = decltype(&nop_sled);
  31. void IndirectCall(FuncType* func) {
  32. // This code always generates CFG guards.
  33. (*func)();
  34. }
  35. void CreateSyntheticHeapCorruption() {
  36. EXCEPTION_RECORD record = {};
  37. record.ExceptionCode = STATUS_HEAP_CORRUPTION;
  38. RaiseFailFastException(&record, nullptr,
  39. FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
  40. }
  41. } // namespace
  42. void TerminateWithHeapCorruption() {
  43. __try {
  44. // Pre-Windows 10, it's hard to trigger a heap corruption fast fail, so
  45. // artificially create one instead.
  46. if (base::win::GetVersion() < base::win::Version::WIN10)
  47. CreateSyntheticHeapCorruption();
  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. HeapFree(heap, 0, addr);
  58. HeapDestroy(heap);
  59. } __except (EXCEPTION_EXECUTE_HANDLER) {
  60. // Heap corruption exception should never be caught.
  61. CHECK(false);
  62. }
  63. // Should never reach here.
  64. abort();
  65. }
  66. void TerminateWithControlFlowViolation() {
  67. // Call into the middle of the NOP sled.
  68. FuncType func = reinterpret_cast<FuncType>(
  69. (reinterpret_cast<uintptr_t>(nop_sled)) + kNopInstructionSize);
  70. __try {
  71. // Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers.
  72. IndirectCall(&func);
  73. } __except (EXCEPTION_EXECUTE_HANDLER) {
  74. // CFG fast fail should never be caught.
  75. CHECK(false);
  76. }
  77. // Should only reach here if CFG is disabled.
  78. abort();
  79. }
  80. } // namespace win
  81. } // namespace debug
  82. } // namespace base