1 // Copyright 2021 the V8 project 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 
5 #if !V8_ENABLE_WEBASSEMBLY
6 #error This header should only be included if WebAssembly is enabled.
7 #endif  // !V8_ENABLE_WEBASSEMBLY
8 
9 #ifndef V8_WASM_MEMORY_PROTECTION_KEY_H_
10 #define V8_WASM_MEMORY_PROTECTION_KEY_H_
11 
12 #if defined(V8_OS_LINUX) && defined(V8_HOST_ARCH_X64)
13 #include <sys/mman.h>  // For STATIC_ASSERT of permission values.
14 #undef MAP_TYPE  // Conflicts with MAP_TYPE in Torque-generated instance-types.h
15 #endif
16 
17 #include "include/v8-platform.h"
18 #include "src/base/address-region.h"
19 
20 namespace v8 {
21 namespace internal {
22 namespace wasm {
23 
24 // TODO(dlehmann): Move this to base/platform/platform.h {OS} (lower-level API)
25 // and {base::PageAllocator} (higher-level, exported API) once the API is more
26 // stable and we have converged on a better design (e.g., typed class wrapper
27 // around int memory protection key).
28 
29 // Sentinel value if there is no PKU support or allocation of a key failed.
30 // This is also the return value on an error of pkey_alloc() and has the
31 // benefit that calling pkey_mprotect() with -1 behaves the same as regular
32 // mprotect().
33 constexpr int kNoMemoryProtectionKey = -1;
34 
35 // Permissions for memory protection keys on top of the page's permissions.
36 // NOTE: Since there is no executable bit, the executable permission cannot be
37 // withdrawn by memory protection keys.
38 enum MemoryProtectionKeyPermission {
39   kNoRestrictions = 0,
40   kDisableAccess = 1,
41   kDisableWrite = 2,
42 };
43 
44 // If sys/mman.h has PKEY support (on newer Linux distributions), ensure that
45 // our definitions of the permissions is consistent with the ones in glibc.
46 #if defined(PKEY_DISABLE_ACCESS)
47 STATIC_ASSERT(kDisableAccess == PKEY_DISABLE_ACCESS);
48 STATIC_ASSERT(kDisableWrite == PKEY_DISABLE_WRITE);
49 #endif
50 
51 // Allocates a memory protection key on platforms with PKU support, returns
52 // {kNoMemoryProtectionKey} on platforms without support or when allocation
53 // failed at runtime.
54 int AllocateMemoryProtectionKey();
55 
56 // Frees the given memory protection key, to make it available again for the
57 // next call to {AllocateMemoryProtectionKey()}. Note that this does NOT
58 // invalidate access rights to pages that are still tied to that key. That is,
59 // if the key is reused and pages with that key are still accessable, this might
60 // be a security issue. See
61 // https://www.gnu.org/software/libc/manual/html_mono/libc.html#Memory-Protection-Keys
62 void FreeMemoryProtectionKey(int key);
63 
64 // Associates a memory protection {key} with the given {region}.
65 // If {key} is {kNoMemoryProtectionKey} this behaves like "plain"
66 // {SetPermissions()} and associates the default key to the region. That is,
67 // explicitly calling with {kNoMemoryProtectionKey} can be used to disassociate
68 // any protection key from a region. This also means "plain" {SetPermissions()}
69 // disassociates the key from a region, making the key's access restrictions
70 // irrelevant/inactive for that region.
71 // Returns true if changing permissions and key was successful. (Returns a bool
72 // to be consistent with {SetPermissions()}).
73 // The {page_permissions} are the permissions of the page, not the key. For
74 // changing the permissions of the key, use
75 // {SetPermissionsForMemoryProtectionKey()} instead.
76 bool SetPermissionsAndMemoryProtectionKey(
77     PageAllocator* page_allocator, base::AddressRegion region,
78     PageAllocator::Permission page_permissions, int key);
79 
80 // Set the key's permissions. {key} must be valid, i.e. not
81 // {kNoMemoryProtectionKey}.
82 void SetPermissionsForMemoryProtectionKey(
83     int key, MemoryProtectionKeyPermission permissions);
84 
85 // Returns {true} if the protection key {key} is write-enabled for the current
86 // thread.
87 bool MemoryProtectionKeyWritable(int key);
88 
89 }  // namespace wasm
90 }  // namespace internal
91 }  // namespace v8
92 
93 #endif  // V8_WASM_MEMORY_PROTECTION_KEY_H_
94