heap_helper.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2017 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 "sandbox/win/src/heap_helper.h"
  5. #include <windows.h>
  6. #include "base/logging.h"
  7. #include "base/memory/raw_ptr_exclusion.h"
  8. #include "base/memory/ref_counted.h"
  9. #include "base/win/windows_version.h"
  10. namespace sandbox {
  11. namespace {
  12. #pragma pack(1)
  13. // These are undocumented, but readily found on the internet.
  14. constexpr DWORD kHeapClass8 = 0x00008000; // CSR port heap
  15. constexpr DWORD kHeapClassMask = 0x0000f000;
  16. constexpr DWORD kHeapSegmentSignature = 0xffeeffee;
  17. constexpr DWORD kHeapSignature = 0xeeffeeff;
  18. typedef struct _HEAP_ENTRY {
  19. PVOID Data1;
  20. PVOID Data2;
  21. } HEAP_ENTRY, *PHEAP_ENTRY;
  22. // The _HEAP struct is not documented, so char arrays are used to space out the
  23. // struct of the fields that are not relevant. However, this spacing is
  24. // different because of the different pointer widths between 32 and 64-bit.
  25. // So 32 and 64 bit structs are defined.
  26. struct _HEAP_32 {
  27. HEAP_ENTRY HeapEntry;
  28. DWORD SegmentSignature;
  29. DWORD SegmentFlags;
  30. LIST_ENTRY SegmentListEntry;
  31. // `Heap` is not a raw_ptr<...>, because reinterpret_cast of uninitialized
  32. // memory to raw_ptr can cause ref-counting mismatch.
  33. RAW_PTR_EXCLUSION struct _HEAP_32* Heap;
  34. char Unknown0[0x24];
  35. // Offset 0x40
  36. DWORD Flags;
  37. // Offset 0x60
  38. char Unknown1[0x1c];
  39. DWORD Signature;
  40. // Other stuff that is not relevant.
  41. };
  42. struct _HEAP_64 {
  43. HEAP_ENTRY HeapEntry;
  44. DWORD SegmentSignature;
  45. DWORD SegmentFlags;
  46. LIST_ENTRY SegmentListEntry;
  47. // `Heap` is not a raw_ptr<...>, because reinterpret_cast of uninitialized
  48. // memory to raw_ptr can cause ref-counting mismatch.
  49. RAW_PTR_EXCLUSION struct _HEAP_64* Heap;
  50. char Unknown0[0x40];
  51. // Offset 0x70
  52. DWORD Flags;
  53. // Offset 0x98
  54. char Unknown1[0x24];
  55. DWORD Signature;
  56. // Other stuff that is not relevant.
  57. };
  58. #if defined(_WIN64)
  59. using _HEAP = _HEAP_64;
  60. #else // defined(_WIN64)
  61. using _HEAP = _HEAP_32;
  62. #endif // defined(_WIN64)
  63. bool ValidateHeap(_HEAP* heap) {
  64. if (heap->SegmentSignature != kHeapSegmentSignature)
  65. return false;
  66. if (heap->Heap != heap)
  67. return false;
  68. if (heap->Signature != kHeapSignature)
  69. return false;
  70. return true;
  71. }
  72. } // namespace
  73. bool HeapFlags(HANDLE handle, DWORD* flags) {
  74. if (!handle || !flags) {
  75. // This is an error.
  76. return false;
  77. }
  78. _HEAP* heap = reinterpret_cast<_HEAP*>(handle);
  79. if (!ValidateHeap(heap)) {
  80. DLOG(ERROR) << "unable to validate heap";
  81. return false;
  82. }
  83. *flags = heap->Flags;
  84. return true;
  85. }
  86. HANDLE FindCsrPortHeap() {
  87. if (base::win::GetVersion() < base::win::Version::WIN10) {
  88. // This functionality has not been verified on versions before Win10.
  89. return nullptr;
  90. }
  91. DWORD number_of_heaps = ::GetProcessHeaps(0, nullptr);
  92. std::unique_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
  93. if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
  94. return nullptr;
  95. // Search for the CSR port heap handle, identified purely based on flags.
  96. HANDLE csr_port_heap = nullptr;
  97. for (size_t i = 0; i < number_of_heaps; ++i) {
  98. HANDLE handle = all_heaps[i];
  99. DWORD flags = 0;
  100. if (!HeapFlags(handle, &flags)) {
  101. DLOG(ERROR) << "Unable to get flags for this heap";
  102. continue;
  103. }
  104. if ((flags & kHeapClassMask) == kHeapClass8) {
  105. if (csr_port_heap) {
  106. DLOG(ERROR) << "Found multiple suitable CSR Port heaps";
  107. return nullptr;
  108. }
  109. csr_port_heap = handle;
  110. }
  111. }
  112. return csr_port_heap;
  113. }
  114. } // namespace sandbox