Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/mm/pkeys.c
26442 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Intel Memory Protection Keys management
4
* Copyright (c) 2015, Intel Corporation.
5
*/
6
#include <linux/debugfs.h> /* debugfs_create_u32() */
7
#include <linux/mm_types.h> /* mm_struct, vma, etc... */
8
#include <linux/pkeys.h> /* PKEY_* */
9
#include <uapi/asm-generic/mman-common.h>
10
11
#include <asm/cpufeature.h> /* boot_cpu_has, ... */
12
#include <asm/mmu_context.h> /* vma_pkey() */
13
14
int __execute_only_pkey(struct mm_struct *mm)
15
{
16
bool need_to_set_mm_pkey = false;
17
int execute_only_pkey = mm->context.execute_only_pkey;
18
int ret;
19
20
/* Do we need to assign a pkey for mm's execute-only maps? */
21
if (execute_only_pkey == -1) {
22
/* Go allocate one to use, which might fail */
23
execute_only_pkey = mm_pkey_alloc(mm);
24
if (execute_only_pkey < 0)
25
return -1;
26
need_to_set_mm_pkey = true;
27
}
28
29
/*
30
* We do not want to go through the relatively costly
31
* dance to set PKRU if we do not need to. Check it
32
* first and assume that if the execute-only pkey is
33
* write-disabled that we do not have to set it
34
* ourselves.
35
*/
36
if (!need_to_set_mm_pkey &&
37
!__pkru_allows_read(read_pkru(), execute_only_pkey)) {
38
return execute_only_pkey;
39
}
40
41
/*
42
* Set up PKRU so that it denies access for everything
43
* other than execution.
44
*/
45
ret = arch_set_user_pkey_access(current, execute_only_pkey,
46
PKEY_DISABLE_ACCESS);
47
/*
48
* If the PKRU-set operation failed somehow, just return
49
* 0 and effectively disable execute-only support.
50
*/
51
if (ret) {
52
mm_set_pkey_free(mm, execute_only_pkey);
53
return -1;
54
}
55
56
/* We got one, store it and use it from here on out */
57
if (need_to_set_mm_pkey)
58
mm->context.execute_only_pkey = execute_only_pkey;
59
return execute_only_pkey;
60
}
61
62
static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
63
{
64
/* Do this check first since the vm_flags should be hot */
65
if ((vma->vm_flags & VM_ACCESS_FLAGS) != VM_EXEC)
66
return false;
67
if (vma_pkey(vma) != vma->vm_mm->context.execute_only_pkey)
68
return false;
69
70
return true;
71
}
72
73
/*
74
* This is only called for *plain* mprotect calls.
75
*/
76
int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey)
77
{
78
/*
79
* Is this an mprotect_pkey() call? If so, never
80
* override the value that came from the user.
81
*/
82
if (pkey != -1)
83
return pkey;
84
85
/*
86
* The mapping is execute-only. Go try to get the
87
* execute-only protection key. If we fail to do that,
88
* fall through as if we do not have execute-only
89
* support in this mm.
90
*/
91
if (prot == PROT_EXEC) {
92
pkey = execute_only_pkey(vma->vm_mm);
93
if (pkey > 0)
94
return pkey;
95
} else if (vma_is_pkey_exec_only(vma)) {
96
/*
97
* Protections are *not* PROT_EXEC, but the mapping
98
* is using the exec-only pkey. This mapping was
99
* PROT_EXEC and will no longer be. Move back to
100
* the default pkey.
101
*/
102
return ARCH_DEFAULT_PKEY;
103
}
104
105
/*
106
* This is a vanilla, non-pkey mprotect (or we failed to
107
* setup execute-only), inherit the pkey from the VMA we
108
* are working on.
109
*/
110
return vma_pkey(vma);
111
}
112
113
#define PKRU_AD_MASK(pkey) (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
114
115
/*
116
* Make the default PKRU value (at execve() time) as restrictive
117
* as possible. This ensures that any threads clone()'d early
118
* in the process's lifetime will not accidentally get access
119
* to data which is pkey-protected later on.
120
*/
121
u32 init_pkru_value = PKRU_AD_MASK( 1) | PKRU_AD_MASK( 2) |
122
PKRU_AD_MASK( 3) | PKRU_AD_MASK( 4) |
123
PKRU_AD_MASK( 5) | PKRU_AD_MASK( 6) |
124
PKRU_AD_MASK( 7) | PKRU_AD_MASK( 8) |
125
PKRU_AD_MASK( 9) | PKRU_AD_MASK(10) |
126
PKRU_AD_MASK(11) | PKRU_AD_MASK(12) |
127
PKRU_AD_MASK(13) | PKRU_AD_MASK(14) |
128
PKRU_AD_MASK(15);
129
130
static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf,
131
size_t count, loff_t *ppos)
132
{
133
char buf[32];
134
unsigned int len;
135
136
len = sprintf(buf, "0x%x\n", init_pkru_value);
137
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
138
}
139
140
static ssize_t init_pkru_write_file(struct file *file,
141
const char __user *user_buf, size_t count, loff_t *ppos)
142
{
143
char buf[32];
144
ssize_t len;
145
u32 new_init_pkru;
146
147
len = min(count, sizeof(buf) - 1);
148
if (copy_from_user(buf, user_buf, len))
149
return -EFAULT;
150
151
/* Make the buffer a valid string that we can not overrun */
152
buf[len] = '\0';
153
if (kstrtouint(buf, 0, &new_init_pkru))
154
return -EINVAL;
155
156
/*
157
* Don't allow insane settings that will blow the system
158
* up immediately if someone attempts to disable access
159
* or writes to pkey 0.
160
*/
161
if (new_init_pkru & (PKRU_AD_BIT|PKRU_WD_BIT))
162
return -EINVAL;
163
164
WRITE_ONCE(init_pkru_value, new_init_pkru);
165
return count;
166
}
167
168
static const struct file_operations fops_init_pkru = {
169
.read = init_pkru_read_file,
170
.write = init_pkru_write_file,
171
.llseek = default_llseek,
172
};
173
174
static int __init create_init_pkru_value(void)
175
{
176
/* Do not expose the file if pkeys are not supported. */
177
if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
178
return 0;
179
180
debugfs_create_file("init_pkru", S_IRUSR | S_IWUSR,
181
arch_debugfs_dir, NULL, &fops_init_pkru);
182
return 0;
183
}
184
late_initcall(create_init_pkru_value);
185
186
static __init int setup_init_pkru(char *opt)
187
{
188
u32 new_init_pkru;
189
190
if (kstrtouint(opt, 0, &new_init_pkru))
191
return 1;
192
193
WRITE_ONCE(init_pkru_value, new_init_pkru);
194
195
return 1;
196
}
197
__setup("init_pkru=", setup_init_pkru);
198
199