summaryrefslogtreecommitdiff
path: root/chromium/sandbox/win/src/heap_helper.cc
blob: 907249f71765ffb4989d1757fb20be00a5b61435 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2017 The Chromium Authors
// 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/logging.h"
#include "base/memory/raw_ptr_exclusion.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;
  // `Heap` is not a raw_ptr<...>, because reinterpret_cast of uninitialized
  // memory to raw_ptr can cause ref-counting mismatch.
  RAW_PTR_EXCLUSION 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;
  // `Heap` is not a raw_ptr<...>, because reinterpret_cast of uninitialized
  // memory to raw_ptr can cause ref-counting mismatch.
  RAW_PTR_EXCLUSION 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