]>
Commit | Line | Data |
---|---|---|
452f5494 DH |
1 | .\" Copyright (C) 2016 Intel Corporation |
2 | .\" | |
3 | .\" %%%LICENSE_START(VERBATIM) | |
4 | .\" Permission is granted to make and distribute verbatim copies of this | |
5 | .\" manual provided the copyright notice and this permission notice are | |
6 | .\" preserved on all copies. | |
7 | .\" | |
8 | .\" Permission is granted to copy and distribute modified versions of this | |
9 | .\" manual under the conditions for verbatim copying, provided that the | |
10 | .\" entire resulting derived work is distributed under the terms of a | |
11 | .\" permission notice identical to this one. | |
12 | .\" | |
13 | .\" Since the Linux kernel and libraries are constantly changing, this | |
14 | .\" manual page may be incorrect or out-of-date. The author(s) assume no | |
15 | .\" responsibility for errors or omissions, or for damages resulting from | |
16 | .\" the use of the information contained herein. The author(s) may not | |
17 | .\" have taken the same level of care in the production of this manual, | |
18 | .\" which is licensed free of charge, as they might when working | |
19 | .\" professionally. | |
20 | .\" | |
21 | .\" Formatted or processed versions of this manual, if unaccompanied by | |
22 | .\" the source, must acknowledge the copyright and authors of this work. | |
23 | .\" %%%LICENSE_END | |
24 | .\" | |
25 | .TH PKEYS 7 2016-03-03 "Linux" "Linux Programmer's Manual" | |
26 | .SH NAME | |
27 | pkeys \- overview of Memory Protection Keys | |
28 | .SH DESCRIPTION | |
29 | Memory Protection Keys (pkeys) are an extension to existing | |
30 | page-based memory permissions. | |
31 | Normal page permissions using | |
32 | page tables require expensive system calls and TLB invalidations | |
33 | when changing permissions. | |
34 | Memory Protection Keys provide a mechanism for changing | |
35 | protections without requiring modification of the page tables on | |
36 | every permission change. | |
37 | ||
435f231a | 38 | To use pkeys, software must first "tag" a page in the page tables |
452f5494 DH |
39 | with a pkey. |
40 | After this tag is in place, an application only has | |
41 | to change the contents of a register in order to remove write | |
42 | access, or all access to a tagged page. | |
43 | ||
435f231a MK |
44 | Protection keys work in conjunction with the existing |
45 | .BR PROT_READ / | |
46 | .BR PROT_WRITE / | |
47 | .BR PROT_EXEC | |
48 | permissions passed to system calls such as | |
452f5494 DH |
49 | .BR mprotect (2) |
50 | and | |
51 | .BR mmap (2), | |
52 | but always act to further restrict these traditional permission | |
53 | mechanisms. | |
54 | ||
79a2a437 MK |
55 | If a process performs an access that violates pkey |
56 | restrictions, it receives a | |
57 | .BR SIGSEGV | |
58 | signal. | |
59 | See | |
60 | .BR sigaction (2) | |
61 | for details of the information available with that signal. | |
62 | ||
435f231a | 63 | To use the pkeys feature, the processor must support it, and the kernel |
452f5494 DH |
64 | must contain support for the feature on a given processor. |
65 | As of early 2016 only future Intel x86 processors are supported, | |
66 | and this hardware supports 16 protection keys in each process. | |
67 | However, pkey 0 is used as the default key, so a maximum of 15 | |
68 | are available for actual application use. | |
69 | The default key is assigned to any memory region for which a | |
70 | pkey has not been explicitly assigned via | |
435f231a | 71 | .BR pkey_mprotect (2). |
452f5494 | 72 | |
435f231a | 73 | Protection keys have the potential to add a layer of security and |
452f5494 | 74 | reliability to applications. |
435f231a | 75 | But they have not been primarily designed as |
452f5494 DH |
76 | a security feature. |
77 | For instance, WRPKRU is a completely unprivileged | |
78 | instruction, so pkeys are useless in any case that an attacker controls | |
79 | the PKRU register or can execute arbitrary instructions. | |
80 | ||
81 | Applications should be very careful to ensure that they do not "leak" | |
82 | protection keys. | |
435f231a MK |
83 | For instance, before calling |
84 | .BR pkey_free (2), | |
452f5494 DH |
85 | the application should be sure that no memory has that pkey assigned. |
86 | If the application left the freed pkey assigned, a future user of | |
87 | that pkey might inadvertently change the permissions of an unrelated | |
435f231a | 88 | data structure, which could impact security or stability. |
452f5494 | 89 | The kernel currently allows in-use pkeys to have |
435f231a | 90 | .BR pkey_free (2) |
452f5494 DH |
91 | called on them because it would have processor or memory performance |
92 | implications to perform the additional checks needed to disallow it. | |
435f231a MK |
93 | Implementation of the necessary checks is left up to applications. |
94 | Applications may implement these checks by searching the | |
95 | .IR /proc/[pid]/smaps | |
96 | file for memory regions with the pkey assigned. | |
97 | Further details can be found in | |
98 | .BR proc (5). | |
452f5494 DH |
99 | |
100 | Any application wanting to use protection keys needs to be able | |
101 | to function without them. | |
102 | They might be unavailable because the hardware that the | |
103 | application runs on does not support them, the kernel code does | |
104 | not contain support, the kernel support has been disabled, or | |
105 | because the keys have all been allocated, perhaps by a library | |
106 | the application is using. | |
107 | It is recommended that applications wanting to use protection | |
108 | keys should simply call | |
435f231a MK |
109 | .BR pkey_alloc (2) |
110 | and test whether the call succeeds, | |
452f5494 | 111 | instead of attempting to detect support for the |
435f231a | 112 | feature in any other way. |
452f5494 DH |
113 | |
114 | Although unnecessary, hardware support for protection keys may be | |
435f231a MK |
115 | enumerated with the |
116 | .I cpuid | |
117 | instruction. | |
118 | Details of how to do this can be found in the Intel Software | |
452f5494 | 119 | Developers Manual. |
435f231a MK |
120 | The kernel performs this enumeration and exposes the information in |
121 | .IR /proc/cpuinfo | |
122 | under the "flags" field. | |
123 | The string "pku" in this field indicates hardware support for protection | |
124 | keys and the string "ospke" indicates that the kernel contains and has | |
452f5494 DH |
125 | enabled protection keys support. |
126 | ||
127 | Applications using threads and protection keys should be especially | |
128 | careful. | |
129 | Threads inherit the protection key rights of the parent at the time | |
130 | of the | |
131 | .BR clone (2), | |
132 | system call. | |
133 | Applications should either ensure that their own permissions are | |
435f231a | 134 | appropriate for child threads at the time when |
452f5494 | 135 | .BR clone (2) |
435f231a | 136 | is called, or ensure that each child thread can perform its |
452f5494 | 137 | own initialization of protection key rights. |
3b3d46e7 | 138 | .\" |
c92965c2 DH |
139 | .SS Signal Handler Behavior |
140 | Each time a signal handler is invoked (including nested signals), the | |
141 | thread is temporarily given a new, default set of protection key rights | |
142 | that override the rights from the interrupted context. | |
143 | This means that applications must re-establish their desired protection | |
144 | key rights upon entering a signal handler if the desired rights differ | |
145 | from the defaults. | |
146 | The rights of any interrupted context are restored when the signal | |
147 | handler returns. | |
148 | ||
149 | This signal behavior is unusual and is due to the fact that the x86 PKRU | |
150 | register (which stores protection key access rights) is managed with the | |
151 | same hardware mechanism (XSAVE) that manages floating-point registers. | |
152 | The signal behavior is the same as that of floating point registers. | |
3b3d46e7 | 153 | .\" |
452f5494 DH |
154 | .SS Protection Keys system calls |
155 | The Linux kernel implements the following pkey-related system calls: | |
156 | .BR pkey_mprotect (2), | |
157 | .BR pkey_alloc (2), | |
158 | and | |
435f231a MK |
159 | .BR pkey_free (2). |
160 | ||
452f5494 | 161 | The Linux pkey system calls are available only if the kernel was |
435f231a | 162 | configured and built with the |
452f5494 DH |
163 | .BR CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS |
164 | option. | |
165 | .SH EXAMPLE | |
166 | .PP | |
435f231a | 167 | The program below allocates a page of memory with read and write permissions. |
452f5494 DH |
168 | It then writes some data to the memory and successfully reads it |
169 | back. | |
170 | After that, it attempts to allocate a protection key and | |
435f231a MK |
171 | disallows access to the page by using the WRPKRU instruction. |
172 | It then tries to access the page, | |
452f5494 | 173 | which we now expect to cause a fatal signal to the application. |
435f231a | 174 | |
452f5494 DH |
175 | .in +4n |
176 | .nf | |
177 | .RB "$" " ./a.out" | |
178 | buffer contains: 73 | |
179 | about to read buffer again... | |
180 | Segmentation fault (core dumped) | |
181 | .fi | |
182 | .in | |
183 | .SS Program source | |
184 | \& | |
185 | .nf | |
186 | #define _GNU_SOURCE | |
187 | #include <unistd.h> | |
188 | #include <sys/syscall.h> | |
189 | #include <stdio.h> | |
190 | #include <sys/mman.h> | |
191 | ||
8bb4e767 MK |
192 | static inline void |
193 | wrpkru(unsigned int pkru) | |
452f5494 | 194 | { |
8bb4e767 MK |
195 | unsigned int eax = pkru; |
196 | unsigned int ecx = 0; | |
197 | unsigned int edx = 0; | |
452f5494 | 198 | |
8bb4e767 MK |
199 | asm volatile(".byte 0x0f,0x01,0xef\\n\\t" |
200 | : : "a" (eax), "c" (ecx), "d" (edx)); | |
452f5494 DH |
201 | } |
202 | ||
8bb4e767 MK |
203 | int |
204 | pkey_set(int pkey, unsigned long rights, unsigned long flags) | |
452f5494 | 205 | { |
8bb4e767 | 206 | unsigned int pkru = (rights << (2 * pkey)); |
452f5494 DH |
207 | return wrpkru(pkru); |
208 | } | |
209 | ||
8bb4e767 MK |
210 | int |
211 | pkey_mprotect(void *ptr, size_t size, unsigned long orig_prot, | |
212 | unsigned long pkey) | |
452f5494 DH |
213 | { |
214 | return syscall(SYS_pkey_mprotect, ptr, size, orig_prot, pkey); | |
215 | } | |
216 | ||
8bb4e767 MK |
217 | int |
218 | pkey_alloc(void) | |
452f5494 DH |
219 | { |
220 | return syscall(SYS_pkey_alloc, 0, 0); | |
221 | } | |
222 | ||
8bb4e767 MK |
223 | int |
224 | pkey_free(unsigned long pkey) | |
452f5494 DH |
225 | { |
226 | return syscall(SYS_pkey_free, pkey); | |
227 | } | |
228 | ||
8bb4e767 MK |
229 | #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \\ |
230 | } while (0) | |
231 | ||
232 | int | |
233 | main(void) | |
452f5494 DH |
234 | { |
235 | int status; | |
236 | int pkey; | |
237 | int *buffer; | |
238 | ||
8bb4e767 MK |
239 | /* |
240 | *Allocate one page of memory | |
241 | */ | |
242 | buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, | |
243 | MAP_ANONYMOUS | MAP_PRIVATE, \-1, 0); | |
452f5494 | 244 | if (buffer == MAP_FAILED) |
8bb4e767 | 245 | errExit("mmap"); |
452f5494 | 246 | |
8bb4e767 MK |
247 | /* |
248 | * Put some random data into the page (still OK to touch) | |
249 | */ | |
250 | *buffer = __LINE__; | |
452f5494 DH |
251 | printf("buffer contains: %d\\n", *buffer); |
252 | ||
8bb4e767 MK |
253 | /* |
254 | * Allocate a protection key: | |
255 | */ | |
452f5494 | 256 | pkey = pkey_alloc(); |
8bb4e767 MK |
257 | if (pkey == \-1) |
258 | errExit("pkey_alloc"); | |
452f5494 | 259 | |
8bb4e767 MK |
260 | /* |
261 | * Disable access to any memory with "pkey" set, | |
262 | * even though there is none right now | |
263 | */ | |
452f5494 DH |
264 | status = pkey_set(pkey, PKEY_DISABLE_ACCESS, 0); |
265 | if (status) | |
8bb4e767 | 266 | errExit("pkey_set"); |
452f5494 DH |
267 | |
268 | /* | |
8bb4e767 MK |
269 | * Set the protection key on "buffer". |
270 | * Note that it is still read/write as far as mprotect() is | |
452f5494 DH |
271 | * concerned and the previous pkey_set() overrides it. |
272 | */ | |
8bb4e767 MK |
273 | status = pkey_mprotect(buffer, getpagesize(), |
274 | PROT_READ | PROT_WRITE, pkey); | |
275 | if (status == -1) | |
276 | errExit("pkey_mprotect"); | |
452f5494 DH |
277 | |
278 | printf("about to read buffer again...\\n"); | |
8bb4e767 MK |
279 | |
280 | /* | |
281 | * This will crash, because we have disallowed access | |
282 | */ | |
452f5494 DH |
283 | printf("buffer contains: %d\\n", *buffer); |
284 | ||
285 | status = pkey_free(pkey); | |
8bb4e767 MK |
286 | if (status == -1) |
287 | errExit("pkey_free"); | |
452f5494 | 288 | |
8bb4e767 | 289 | exit(EXIT_SUCCESS); |
452f5494 DH |
290 | } |
291 | .SH SEE ALSO | |
292 | .BR pkey_alloc (2), | |
293 | .BR pkey_free (2), | |
294 | .BR pkey_mprotect (2), | |
435f231a | 295 | .BR sigaction (2) |