1 // Copyright 2022 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 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
7
8 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
9
10 #if BUILDFLAG(ENABLE_PKEYS)
11
12 #include "base/allocator/partition_allocator/page_allocator_constants.h"
13 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
14 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
15
16 #include <cstddef>
17 #include <cstdint>
18
19 #if !BUILDFLAG(HAS_64_BIT_POINTERS)
20 #error "pkey support requires 64 bit pointers"
21 #endif
22
23 #define PA_PKEY_ALIGN_SZ SystemPageSize()
24 #define PA_PKEY_ALIGN_OFFSET_MASK (PA_PKEY_ALIGN_SZ - 1)
25 #define PA_PKEY_ALIGN_BASE_MASK (~PA_PKEY_ALIGN_OFFSET_MASK)
26 #define PA_PKEY_ALIGN alignas(PA_PKEY_ALIGN_SZ)
27
28 #define PA_PKEY_FILL_PAGE_SZ(size) \
29 ((PA_PKEY_ALIGN_SZ - (size & PA_PKEY_ALIGN_OFFSET_MASK)) % PA_PKEY_ALIGN_SZ)
30 // Calculate the required padding so that the last element of a page-aligned
31 // array lands on a page boundary. In other words, calculate that padding so
32 // that (count-1) elements are a multiple of page size.
33 #define PA_PKEY_ARRAY_PAD_SZ(Type, count) \
34 PA_PKEY_FILL_PAGE_SZ(sizeof(Type) * (count - 1))
35
36 namespace partition_alloc::internal {
37
38 constexpr int kDefaultPkey = 0;
39 constexpr int kInvalidPkey = -1;
40
41 // Check if the CPU supports pkeys.
42 bool CPUHasPkeySupport();
43
44 // A wrapper around pkey_mprotect that falls back to regular mprotect if
45 // PkeySettings::enabled is false.
46 [[nodiscard]] int PkeyMprotectIfEnabled(void* addr,
47 size_t len,
48 int prot,
49 int pkey);
50 // A wrapper around pkey_mprotect without fallback.
51 [[nodiscard]] int PkeyMprotect(void* addr, size_t len, int prot, int pkey);
52
53 // If we set up a pkey pool, we need to tag global variables with the pkey to
54 // make them readable in case default pkey access is disabled. Called once
55 // during pkey pool initialization.
56 void TagGlobalsWithPkey(int pkey);
57
58 int PkeyAlloc(int access_rights);
59
60 void PkeyFree(int pkey);
61
62 // Read the pkru register (the current pkey state).
63 uint32_t Rdpkru();
64
65 // Write the pkru register (the current pkey state).
66 void Wrpkru(uint32_t pkru);
67
68 struct PkeySettings {
69 bool enabled = false;
70 char pad_[PA_PKEY_FILL_PAGE_SZ(sizeof(enabled))] = {};
71 static PkeySettings settings PA_PKEY_ALIGN PA_CONSTINIT;
72 };
73
74 #if BUILDFLAG(PA_DCHECK_IS_ON)
75
PA_COMPONENT_EXPORT(PARTITION_ALLOC)76 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LiftPkeyRestrictionsScope {
77 public:
78 static constexpr uint32_t kDefaultPkeyValue = 0x55555554;
79 static constexpr uint32_t kAllowAllPkeyValue = 0x0;
80
81 LiftPkeyRestrictionsScope();
82 ~LiftPkeyRestrictionsScope();
83
84 private:
85 uint32_t saved_pkey_value_;
86 };
87
88 #endif // BUILDFLAG(PA_DCHECK_IS_ON)
89
90 } // namespace partition_alloc::internal
91
92 #else // BUILDFLAG(ENABLE_PKEYS)
93 #define PA_PKEY_ALIGN
94 #define PA_PKEY_FILL_PAGE_SZ(size) 0
95 #define PA_PKEY_ARRAY_PAD_SZ(Type, size) 0
96 #endif // BUILDFLAG(ENABLE_PKEYS)
97
98 #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
99