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 #include "partition_alloc/thread_isolation/pkey.h"
6
7 #if BUILDFLAG(ENABLE_PKEYS)
8
9 #include <errno.h>
10 #include <sys/mman.h>
11 #include <sys/syscall.h>
12 #include <unistd.h>
13
14 #include "partition_alloc/partition_alloc_base/cpu.h"
15 #include "partition_alloc/partition_alloc_check.h"
16 #include "partition_alloc/thread_isolation/thread_isolation.h"
17
18 #if !BUILDFLAG(IS_LINUX)
19 #error "This pkey code is currently only supported on Linux"
20 #endif
21
22 namespace partition_alloc::internal {
23
PA_COMPONENT_EXPORT(PARTITION_ALLOC)24 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
25 bool CPUHasPkeySupport() {
26 return base::CPU::GetInstanceNoAllocation().has_pku();
27 }
28
PA_COMPONENT_EXPORT(PARTITION_ALLOC)29 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
30 int PkeyMprotect(void* addr, size_t len, int prot, int pkey) {
31 return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
32 }
33
TagMemoryWithPkey(int pkey,void * address,size_t size)34 void TagMemoryWithPkey(int pkey, void* address, size_t size) {
35 PA_DCHECK((reinterpret_cast<uintptr_t>(address) &
36 PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) == 0);
37 PA_PCHECK(PkeyMprotect(address,
38 (size + PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) &
39 PA_THREAD_ISOLATED_ALIGN_BASE_MASK,
40 PROT_READ | PROT_WRITE, pkey) == 0);
41 }
42
PA_COMPONENT_EXPORT(PARTITION_ALLOC)43 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
44 int PkeyAlloc(int access_rights) {
45 return syscall(SYS_pkey_alloc, 0, access_rights);
46 }
47
PA_COMPONENT_EXPORT(PARTITION_ALLOC)48 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
49 void PkeyFree(int pkey) {
50 PA_PCHECK(syscall(SYS_pkey_free, pkey) == 0);
51 }
52
Rdpkru()53 uint32_t Rdpkru() {
54 uint32_t pkru;
55 asm volatile(".byte 0x0f,0x01,0xee\n" : "=a"(pkru) : "c"(0), "d"(0));
56 return pkru;
57 }
58
Wrpkru(uint32_t pkru)59 void Wrpkru(uint32_t pkru) {
60 asm volatile(".byte 0x0f,0x01,0xef\n" : : "a"(pkru), "c"(0), "d"(0));
61 }
62
63 #if BUILDFLAG(PA_DCHECK_IS_ON)
64
LiftPkeyRestrictionsScope()65 LiftPkeyRestrictionsScope::LiftPkeyRestrictionsScope()
66 : saved_pkey_value_(kDefaultPkeyValue) {
67 if (!ThreadIsolationSettings::settings.enabled) {
68 return;
69 }
70 saved_pkey_value_ = Rdpkru();
71 if (saved_pkey_value_ != kDefaultPkeyValue) {
72 Wrpkru(kAllowAllPkeyValue);
73 }
74 }
75
~LiftPkeyRestrictionsScope()76 LiftPkeyRestrictionsScope::~LiftPkeyRestrictionsScope() {
77 if (!ThreadIsolationSettings::settings.enabled) {
78 return;
79 }
80 if (Rdpkru() != saved_pkey_value_) {
81 Wrpkru(saved_pkey_value_);
82 }
83 }
84
85 #endif // BUILDFLAG(PA_DCHECK_IS_ON)
86
87 } // namespace partition_alloc::internal
88
89 #endif // BUILDFLAG(ENABLE_PKEYS)
90