pkeys(7)
๐ธ pkeys โ a lil overview of Memory Protection Keys ๐ธ
okay bestie, welcome to pkeys(7), the section 7 miscellaneous info page that's gonna make you the moment you finally Get It about Memory Protection Keys ๐ this is the whole lore drop, no skimming.
โจ NAME โจ
pkeys โ the overview of Memory Protection Keys, periodt.
๐ซถ DESCRIPTION ๐ซถ
so. Memory Protection Keys (aka pkeys) are an extension to the memory permissions you already know and love, the page-based ones ๐ Normal page permissions using page tables? They're lowkey expensive โ changing them means expensive system calls and TLB invalidations every single time ๐ญ Memory Protection Keys give you a mechanism to change protections without having to modify the page tables on every permission change. iconic behavior honestly.
To actually use pkeys, your software has to first "tag" a page in the page tables with a pkey. Once that tag is in place, an application only has to change the contents of a register in order to remove write access โ or all access โ to a tagged page. that's the whole flex ๐
Protection keys work in conjunction with the existing PROT_READ, PROT_WRITE, and PROT_EXEC permissions you pass to system calls such as mprotect(2) and mmap(2), but they always act to further restrict those traditional permission mechanisms. never loosen, only tighten. main character energy โจ
If a process performs an access that violates pkey restrictions, it receives a SIGSEGV signal. See sigaction(2) for details of the information available with that signal. (yes bestie, you get โจdetailsโจ with it, go look.)
To use the pkeys feature, the processor must support it, and the kernel must contain support for the feature on a given processor. As of early 2016 only future Intel x86 processors are supported, and this hardware supports 16 protection keys in each process. HOWEVER โ and this is the plot twist ๐ โ pkey 0 is used as the default key, so a maximum of 15 are available for actual application use. The default key is assigned to any memory region for which a pkey has not been explicitly assigned via pkey_mprotect(2).
Protection keys have the potential to add a layer of security and reliability to applications. But โ and say it with me โ they have not been primarily designed as a security feature ๐จ For instance, WRPKRU is a completely unprivileged instruction, so pkeys are useless in any case that an attacker controls the PKRU register or can execute arbitrary instructions. fr fr, keep that in mind.
๐ซง Applications should be very careful to ensure that they do not "leak" protection keys. For instance, before callingpkey_free(2), the application should be sure that no memory has that pkey assigned. If the application left the freed pkey assigned, a future user of that pkey might inadvertently change the permissions of an unrelated data structure, which could impact security or stability. The kernel currently allows in-use pkeys to havepkey_free(2)called on them because it would have processor or memory performance implications to perform the additional checks needed to disallow it. Implementation of the necessary checks is left up to applications. Applications may implement these checks by searching the/proc/pid/smapsfile for memory regions with the pkey assigned. Further details can be found inproc(5).
Any application wanting to use protection keys needs to be able to function without them ๐ค They might be unavailable because the hardware that the application runs on does not support them, the kernel code does not contain support, the kernel support has been disabled, or because the keys have all been allocated โ perhaps by a library the application is using. Recommended move: applications wanting to use protection keys should simply call pkey_alloc(2) and test whether the call succeeds, instead of attempting to detect support for the feature in any other way. don't be weird about it, just ask and see if it says yes ๐
Although unnecessary, hardware support for protection keys may be enumerated with the cpuid instruction. Details of how to do this can be found in the Intel Software Developers Manual. The kernel performs this enumeration and exposes the information in /proc/cpuinfo under the "flags" field. The string "pku" in this field indicates hardware support for protection keys and the string "ospke" indicates that the kernel contains and has enabled protection keys support. cute little easter eggs in there for you ๐ฅโจ
Applications using threads and protection keys should be especially careful ๐งต๐งต Threads inherit the protection key rights of the parent at the time of the clone(2) system call. Applications should either ensure that their own permissions are appropriate for child threads at the time when clone(2) is called, or ensure that each child thread can perform its own initialization of protection key rights. pick your fighter, just don't leave it vibes-only.
๐ง Signal Handler Behavior ๐ง
Each time a signal handler is invoked (including nested signals), the thread is temporarily given a new, default set of protection key rights that override the rights from the interrupted context. This means that applications must re-establish their desired protection key rights upon entering a signal handler if the desired rights differ from the defaults. The rights of any interrupted context are restored when the signal handler returns. so like, your rights get temporarily swapped and then handed back. give them back. ๐
This signal behavior is unusual and is due to the fact that the x86 PKRU register (which stores protection key access rights) is managed with the same hardware mechanism (XSAVE) that manages floating-point registers. The signal behavior is the same as that of floating-point registers. it's giving "same energy, same quirk" ๐
๐ Protection Keys system calls ๐
The Linux kernel implements the following pkey-related system calls: pkey_mprotect(2), pkey_alloc(2), and pkey_free(2). the holy trinity, the trio, the girlies ๐ซถ
The Linux pkey system calls are available only if the kernel was configured and built with the CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS option. remember it, or you'll be debugging in the dark bestie ๐
๐ EXAMPLES ๐
okay so the program below allocates a page of memory with read and write permissions. It then writes some data to the memory and successfully reads it back. After that, it attempts to allocate a protection key and disallows access to the page by using the WRPKRU instruction. It then tries to access the page, which we now expect to cause a fatal signal to the application ๐ญ๐
$ ./a.out
buffer contains: 73
about to read buffer again...
Segmentation fault (core dumped)
yes. that's the expected ending. the segfault is not a bug, it's โจthe bitโจ
๐ Program source ๐
#define _GNU_SOURCE
#include <err.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int
main(void)
{
int status;
int pkey;
int *buffer;
/*
* Allocate one page of memory.
*/
buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (buffer == MAP_FAILED)
err(EXIT_FAILURE, "mmap");
/*
* Put some random data into the page (still OK to touch).
*/
*buffer = __LINE__;
printf("buffer contains: %d\n", *buffer);
/*
* Allocate a protection key:
*/
pkey = pkey_alloc(0, 0);
if (pkey == -1)
err(EXIT_FAILURE, "pkey_alloc");
/*
* Disable access to any memory with "pkey" set,
* even though there is none right now.
*/
status = pkey_set(pkey, PKEY_DISABLE_ACCESS);
if (status)
err(EXIT_FAILURE, "pkey_set");
/*
* Set the protection key on "buffer".
* Note that it is still read/write as far as mprotect() is
* concerned and the previous pkey_set() overrides it.
*/
status = pkey_mprotect(buffer, getpagesize(),
PROT_READ | PROT_WRITE, pkey);
if (status == -1)
err(EXIT_FAILURE, "pkey_mprotect");
printf("about to read buffer again...\n");
/*
* This will crash, because we have disallowed access.
*/
printf("buffer contains: %d\n", *buffer);
status = pkey_free(pkey);
if (status == -1)
err(EXIT_FAILURE, "pkey_free");
exit(EXIT_SUCCESS);
}
you can literally run this, bestie, and watch the universe do exactly what it just said it would ๐
๐ธ SEE ALSO ๐ธ
go read them. iykyk ๐ฆ
okay that's the whole page!! this one came from Linux man-pages 6.20, dated 2026-02-08 โ shoutout to the man-pages girlies for keeping the lore accurate, mwah ๐๐โจ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 2016, Intel Corp
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms