Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
66d37570 DH |
2 | #ifndef _ASM_X86_PKEYS_H |
3 | #define _ASM_X86_PKEYS_H | |
4 | ||
16171bff DH |
5 | /* |
6 | * If more than 16 keys are ever supported, a thorough audit | |
7 | * will be necessary to ensure that the types that store key | |
8 | * numbers and masks have sufficient capacity. | |
9 | */ | |
8a1dc55a | 10 | #define arch_max_pkey() (cpu_feature_enabled(X86_FEATURE_OSPKE) ? 16 : 1) |
66d37570 | 11 | |
84594296 DH |
12 | extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, |
13 | unsigned long init_val); | |
14 | ||
3f36c942 ME |
15 | static inline bool arch_pkeys_enabled(void) |
16 | { | |
8a1dc55a | 17 | return cpu_feature_enabled(X86_FEATURE_OSPKE); |
3f36c942 ME |
18 | } |
19 | ||
62b5f7d0 DH |
20 | /* |
21 | * Try to dedicate one of the protection keys to be used as an | |
22 | * execute-only protection key. | |
23 | */ | |
62b5f7d0 DH |
24 | extern int __execute_only_pkey(struct mm_struct *mm); |
25 | static inline int execute_only_pkey(struct mm_struct *mm) | |
26 | { | |
8a1dc55a | 27 | if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) |
0a0b1520 | 28 | return ARCH_DEFAULT_PKEY; |
62b5f7d0 DH |
29 | |
30 | return __execute_only_pkey(mm); | |
31 | } | |
32 | ||
33 | extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma, | |
34 | int prot, int pkey); | |
35 | static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, | |
36 | int prot, int pkey) | |
37 | { | |
8a1dc55a | 38 | if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) |
62b5f7d0 DH |
39 | return 0; |
40 | ||
41 | return __arch_override_mprotect_pkey(vma, prot, pkey); | |
42 | } | |
43 | ||
a8502b67 DH |
44 | #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | VM_PKEY_BIT3) |
45 | ||
e8c24d3a DH |
46 | #define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map) |
47 | #define mm_set_pkey_allocated(mm, pkey) do { \ | |
48 | mm_pkey_allocation_map(mm) |= (1U << pkey); \ | |
49 | } while (0) | |
50 | #define mm_set_pkey_free(mm, pkey) do { \ | |
51 | mm_pkey_allocation_map(mm) &= ~(1U << pkey); \ | |
52 | } while (0) | |
53 | ||
54 | static inline | |
55 | bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey) | |
56 | { | |
58ab9a08 DH |
57 | /* |
58 | * "Allocated" pkeys are those that have been returned | |
2fa9d1cf DH |
59 | * from pkey_alloc() or pkey 0 which is allocated |
60 | * implicitly when the mm is created. | |
58ab9a08 | 61 | */ |
2fa9d1cf | 62 | if (pkey < 0) |
58ab9a08 DH |
63 | return false; |
64 | if (pkey >= arch_max_pkey()) | |
65 | return false; | |
0a0b1520 DH |
66 | /* |
67 | * The exec-only pkey is set in the allocation map, but | |
68 | * is not available to any of the user interfaces like | |
69 | * mprotect_pkey(). | |
70 | */ | |
71 | if (pkey == mm->context.execute_only_pkey) | |
72 | return false; | |
73 | ||
e8c24d3a DH |
74 | return mm_pkey_allocation_map(mm) & (1U << pkey); |
75 | } | |
76 | ||
77 | /* | |
78 | * Returns a positive, 4-bit key on success, or -1 on failure. | |
79 | */ | |
80 | static inline | |
81 | int mm_pkey_alloc(struct mm_struct *mm) | |
82 | { | |
83 | /* | |
84 | * Note: this is the one and only place we make sure | |
85 | * that the pkey is valid as far as the hardware is | |
86 | * concerned. The rest of the kernel trusts that | |
87 | * only good, valid pkeys come out of here. | |
88 | */ | |
89 | u16 all_pkeys_mask = ((1U << arch_max_pkey()) - 1); | |
90 | int ret; | |
91 | ||
92 | /* | |
93 | * Are we out of pkeys? We must handle this specially | |
94 | * because ffz() behavior is undefined if there are no | |
95 | * zeros. | |
96 | */ | |
97 | if (mm_pkey_allocation_map(mm) == all_pkeys_mask) | |
98 | return -1; | |
99 | ||
100 | ret = ffz(mm_pkey_allocation_map(mm)); | |
101 | ||
102 | mm_set_pkey_allocated(mm, ret); | |
103 | ||
104 | return ret; | |
105 | } | |
106 | ||
107 | static inline | |
108 | int mm_pkey_free(struct mm_struct *mm, int pkey) | |
109 | { | |
e8c24d3a DH |
110 | if (!mm_pkey_is_allocated(mm, pkey)) |
111 | return -EINVAL; | |
112 | ||
113 | mm_set_pkey_free(mm, pkey); | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
555934a7 ME |
118 | static inline int vma_pkey(struct vm_area_struct *vma) |
119 | { | |
120 | unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 | | |
121 | VM_PKEY_BIT2 | VM_PKEY_BIT3; | |
122 | ||
123 | return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT; | |
124 | } | |
125 | ||
66d37570 | 126 | #endif /*_ASM_X86_PKEYS_H */ |