mprotect(2)
๐ฆ NAME ๐ฆ
okay so bestie, welcome to mprotect(2) โ this is the System Calls Manual page, section 2, and it's all about how you change the protection on a region of memory ๐
mprotect,pkey_mprotectโ set protection on a region of memory
๐ LIBRARY ๐
Standard C library (libc, -lc) ๐ซถ
โจ SYNOPSIS โจ
#include <sys/mman.h>
int mprotect(size_t size;
void addr[size], size_t size, int prot);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/mman.h>
int pkey_mprotect(size_t size;
void addr[size], size_t size, int prot, int pkey);
๐ธ DESCRIPTION ๐ธ
so mprotect() changes the access protections for the calling process's memory pages that contain any part of the address range in the interval [addr, addr+size-1]. and listen โ addr must be aligned to a page boundary, no exceptions, she's not flexible about this ๐ญ
and if your process tries to access memory in a way that violates the protections? the kernel just generates a SIGSEGV signal for the process. like. it will simply end you ๐
prot is a combination of these access flags: either PROT_NONE, or a bitwise OR of the other values in the list below ๐
PROT_NONEโ the memory cannot be accessed at all. full lockdown, no touching, not even a peek ๐PROT_READโ the memory can be read ๐PROT_WRITEโ the memory can be modified โ๏ธPROT_EXECโ the memory can be executed ๐PROT_SEM(since Linux 2.5.7) โ the memory can be used for atomic operations. this flag got introduced as part of thefutex(2)implementation (the whole point was to guarantee the ability to perform atomic operations that commands likeFUTEX_WAITneed), but it is not currently used on any architecture. iconic in theory, unused in practice ๐PROT_SAO(since Linux 2.6.26) โ the memory should have strong access ordering. this one is specific to the PowerPC architecture (version 2.06 of the architecture specification adds the SAO CPU feature, and it's available on POWER 7 or PowerPC A2, for example) โก
additionally (since Linux 2.6.0), prot can have one of the following flags set:
PROT_GROWSUPโ apply the protection mode up to the end of a mapping that grows upwards. (mappings like this get created for the stack area on architectures โ HP-PARISC, for example โ that have an upwardly growing stack โฌ๏ธ)PROT_GROWSDOWNโ apply the protection mode down to the beginning of a mapping that grows downward (which should be a stack segment, or a segment mapped with theMAP_GROWSDOWNflag set โฌ๏ธ)
and just like mprotect(), pkey_mprotect() changes the protection on the pages specified by addr and size. the pkey argument specifies the protection key (see pkeys(7)) to assign to the memory. lowkey important: that protection key must be allocated with pkey_alloc(2) before you pass it to pkey_mprotect(). for an example of how this system call gets used, see pkeys(7) ๐
๐ RETURN VALUE ๐
on success, mprotect() and pkey_mprotect() return zero. on error, these system calls return -1, and errno is set to indicate the error ๐จ
๐ ERRORS ๐
EACCESโ the memory cannot be given the specified access. this can happen, for example, if yoummap(2)a file that you only have read-only access to, and then askmprotect()to mark itPROT_WRITE. bestie. you cannot write to what you cannot write to ๐ซEINVALโaddris not a valid pointer, or not a multiple of the system page size.EINVALโ (pkey_mprotect())pkeyhas not been allocated withpkey_alloc(2).EINVALโ bothPROT_GROWSUPandPROT_GROWSDOWNwere specified inprot. pick a lane, not both ๐EINVALโ invalid flags specified inprot.EINVALโ (PowerPC architecture)PROT_SAOwas specified inprot, but the SAO hardware feature is not available.ENOMEMโ internal kernel structures could not be allocated.ENOMEMโ addresses in the range [addr, addr+size-1] are invalid for the address space of the process, or specify one or more pages that are not mapped. (before Linux 2.4.19, the errorEFAULTwas incorrectly produced for these cases ๐ซข)ENOMEMโ changing the protection of a memory region would result in the total number of mappings with distinct attributes (read versus read/write protection, for example) exceeding the allowed maximum. (for example: making the protection of a rangePROT_READin the middle of a region currently protected asPROT_READ|PROT_WRITEwould result in three mappings โ two read/write mappings at each end, and a read-only mapping in the middle ๐ฅด)
๐ VERSIONS ๐
POSIX says that the behavior of mprotect() is unspecified if it's applied to a region of memory that wasn't obtained via mmap(2).
on Linux though, it's always permissible to call mprotect() on any address in a process's address space (except for the kernel vsyscall area). in particular, it can be used to change existing code mappings to be writable. yeah, she really said that ๐ณ
whether PROT_EXEC has any effect different from PROT_READ depends on processor architecture, kernel version, and process state. if READ_IMPLIES_EXEC is set in the process's personality flags (see personality(2)), then specifying PROT_READ will implicitly add PROT_EXEC โจ
on some hardware architectures (e.g., i386), PROT_WRITE implies PROT_READ.
POSIX.1 says that an implementation may permit access other than that specified in prot, but at a minimum it can allow write access only if PROT_WRITE has been set, and it must not allow any access if PROT_NONE has been set. no cap ๐งข
applications should be careful when mixing use of mprotect() and pkey_mprotect(). on x86, when mprotect() is used with prot set to PROT_EXEC, a pkey may be allocated and set on the memory implicitly by the kernel โ but only when the pkey was 0 previously ๐
on systems that do not support protection keys in hardware, pkey_mprotect() may still be used, but pkey must be set to -1. when called this way, the operation of pkey_mprotect() is equivalent to mprotect() ๐ช
๐ STANDARDS ๐
mprotect()โ POSIX.1-2024.pkey_mprotect()โ Linux.
๐ HISTORY ๐
mprotect()โ SVr4, SUSv1, POSIX.1-1996.pkey_mprotect()โ Linux 4.9, glibc 2.27.
๐ซถ NOTES ๐ซถ
(ngl bestie, this section is literally empty in the original. a vibe, honestly ๐)
๐ EXAMPLES ๐
the program below demonstrates the use of mprotect(). what it does: it allocates four pages of memory, makes the third of those pages read-only, and then executes a loop that walks upward through the allocated region modifying bytes ๐ถโ๏ธ
an example of what we might see when running the program is the following:
$ ./a.out
Start of region: 0x804c000
Got SIGSEGV at address: 0x804e000
๐ Program source ๐
#include <err.h>
#include <malloc.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
static char *buffer;
static void
handler(int sig, siginfo_t *si, void *unused)
{
/* Note: calling printf() from a signal handler is not safe
(and should not be done in production programs), since
printf() is not async-signal-safe; see signal-safety(7).
Nevertheless, we use printf() here as a simple way of
showing that the handler was called. */
printf("Got SIGSEGV at address: %p\n", si->si_addr);
exit(EXIT_FAILURE);
}
int
main(void)
{
int pagesize;
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
if (sigaction(SIGSEGV, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction");
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize == -1)
err(EXIT_FAILURE, "sysconf");
/* Allocate a buffer aligned on a page boundary;
initial protection is PROT_READ | PROT_WRITE. */
buffer = memalign(pagesize, 4 * pagesize);
if (buffer == NULL)
err(EXIT_FAILURE, "memalign");
printf("Start of region: %p\n", buffer);
if (mprotect(buffer + pagesize * 2, pagesize,
PROT_READ) == -1)
err(EXIT_FAILURE, "mprotect");
for (char *p = buffer ; ; )
*(p++) = 'a';
printf("Loop completed\n"); /* Should never happen */
exit(EXIT_SUCCESS);
}
lowkey note: that printf("Loop completed\n"); line should literally never happen โ if you ever see it, something has gone very wrong ๐
๐ SEE ALSO ๐
and that's the whole page bestie, you ate that ๐ซถ this was Linux man-pages 6.20, dated 2026-02-11. go forth and protect your memory regions responsibly, 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 1995, Michael Shields <shields@tembel.org>
- Copyright 2007, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms