diff options
Diffstat (limited to 'security/sandbox/chromium/sandbox/win/src/heap_helper.cc')
-rw-r--r-- | security/sandbox/chromium/sandbox/win/src/heap_helper.cc | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/security/sandbox/chromium/sandbox/win/src/heap_helper.cc b/security/sandbox/chromium/sandbox/win/src/heap_helper.cc new file mode 100644 index 0000000000..b0f4498fea --- /dev/null +++ b/security/sandbox/chromium/sandbox/win/src/heap_helper.cc @@ -0,0 +1,124 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/win/src/heap_helper.h" + +#include <windows.h> + +#include "base/memory/ref_counted.h" +#include "base/win/windows_version.h" + +namespace sandbox { +namespace { +#pragma pack(1) + +// These are undocumented, but readily found on the internet. +constexpr DWORD kHeapClass8 = 0x00008000; // CSR port heap +constexpr DWORD kHeapClassMask = 0x0000f000; + +constexpr DWORD kHeapSegmentSignature = 0xffeeffee; +constexpr DWORD kHeapSignature = 0xeeffeeff; + +typedef struct _HEAP_ENTRY { + PVOID Data1; + PVOID Data2; +} HEAP_ENTRY, *PHEAP_ENTRY; + +// The _HEAP struct is not documented, so char arrays are used to space out the +// struct of the fields that are not relevant. However, this spacing is +// different because of the different pointer widths between 32 and 64-bit. +// So 32 and 64 bit structs are defined. +struct _HEAP_32 { + HEAP_ENTRY HeapEntry; + DWORD SegmentSignature; + DWORD SegmentFlags; + LIST_ENTRY SegmentListEntry; + struct _HEAP_32* Heap; + char Unknown0[0x24]; + // Offset 0x40 + DWORD Flags; + // Offset 0x60 + char Unknown1[0x1c]; + DWORD Signature; + // Other stuff that is not relevant. +}; + +struct _HEAP_64 { + HEAP_ENTRY HeapEntry; + DWORD SegmentSignature; + DWORD SegmentFlags; + LIST_ENTRY SegmentListEntry; + struct _HEAP_64* Heap; + char Unknown0[0x40]; + // Offset 0x70 + DWORD Flags; + // Offset 0x98 + char Unknown1[0x24]; + DWORD Signature; + // Other stuff that is not relevant. +}; + +#if defined(_WIN64) +using _HEAP = _HEAP_64; +#else // defined(_WIN64) +using _HEAP = _HEAP_32; +#endif // defined(_WIN64) + +bool ValidateHeap(_HEAP* heap) { + if (heap->SegmentSignature != kHeapSegmentSignature) + return false; + if (heap->Heap != heap) + return false; + if (heap->Signature != kHeapSignature) + return false; + return true; +} + +} // namespace + +bool HeapFlags(HANDLE handle, DWORD* flags) { + if (!handle || !flags) { + // This is an error. + return false; + } + _HEAP* heap = reinterpret_cast<_HEAP*>(handle); + if (!ValidateHeap(heap)) { + DLOG(ERROR) << "unable to validate heap"; + return false; + } + *flags = heap->Flags; + return true; +} + +HANDLE FindCsrPortHeap() { + if (base::win::GetVersion() < base::win::Version::WIN10) { + // This functionality has not been verified on versions before Win10. + return nullptr; + } + DWORD number_of_heaps = ::GetProcessHeaps(0, nullptr); + std::unique_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]); + if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps) + return nullptr; + + // Search for the CSR port heap handle, identified purely based on flags. + HANDLE csr_port_heap = nullptr; + for (size_t i = 0; i < number_of_heaps; ++i) { + HANDLE handle = all_heaps[i]; + DWORD flags = 0; + if (!HeapFlags(handle, &flags)) { + DLOG(ERROR) << "Unable to get flags for this heap"; + continue; + } + if ((flags & kHeapClassMask) == kHeapClass8) { + if (csr_port_heap) { + DLOG(ERROR) << "Found multiple suitable CSR Port heaps"; + return nullptr; + } + csr_port_heap = handle; + } + } + return csr_port_heap; +} + +} // namespace sandbox |