| .\" Copyright (C) 2007 Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" and Copyright (C) 1995 Michael Shields <shields@tembel.org>. |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of this |
| .\" manual under the conditions for verbatim copying, provided that the |
| .\" entire resulting derived work is distributed under the terms of a |
| .\" permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume no |
| .\" responsibility for errors or omissions, or for damages resulting from |
| .\" the use of the information contained herein. The author(s) may not |
| .\" have taken the same level of care in the production of this manual, |
| .\" which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and author of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .\" Modified 1996-10-22 by Eric S. Raymond <esr@thyrsus.com> |
| .\" Modified 1997-05-31 by Andries Brouwer <aeb@cwi.nl> |
| .\" Modified 2003-08-24 by Andries Brouwer <aeb@cwi.nl> |
| .\" Modified 2004-08-16 by Andi Kleen <ak@muc.de> |
| .\" 2007-06-02, mtk: Fairly substantial rewrites and additions, and |
| .\" a much improved example program. |
| .\" |
| .TH MPROTECT 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| mprotect, pkey_mprotect \- set protection on a region of memory |
| .SH SYNOPSIS |
| .nf |
| .B #include <sys/mman.h> |
| .PP |
| .BI "int mprotect(void *" addr ", size_t " len ", int " prot ); |
| .PP |
| .BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */" |
| .B #include <sys/mman.h> |
| .PP |
| .BI "int pkey_mprotect(void *" addr ", size_t " len ", int " prot ", int " pkey ");" |
| .fi |
| .SH DESCRIPTION |
| .BR mprotect () |
| changes the access protections for the calling process's memory pages |
| containing any part of the address range in the |
| interval [\fIaddr\fP,\ \fIaddr\fP+\fIlen\fP\-1]. |
| .I addr |
| must be aligned to a page boundary. |
| .PP |
| If the calling process tries to access memory in a manner |
| that violates the protections, then the kernel generates a |
| .B SIGSEGV |
| signal for the process. |
| .PP |
| .I prot |
| is a combination of the following access flags: |
| .B PROT_NONE |
| or a bitwise-or of the other values in the following list: |
| .TP |
| .B PROT_NONE |
| The memory cannot be accessed at all. |
| .TP |
| .B PROT_READ |
| The memory can be read. |
| .TP |
| .B PROT_WRITE |
| The memory can be modified. |
| .TP |
| .B PROT_EXEC |
| The memory can be executed. |
| .TP |
| .BR PROT_SEM " (since Linux 2.5.7)" |
| The memory can be used for atomic operations. |
| This flag was introduced as part of the |
| .BR futex (2) |
| implementation (in order to guarantee the ability to perform atomic |
| operations required by commands such as |
| .BR FUTEX_WAIT ), |
| but is not currently used in on any architecture. |
| .TP |
| .BR PROT_SAO " (since Linux 2.6.26)" |
| .\" commit aba46c5027cb59d98052231b36efcbbde9c77a1d |
| .\" commit ef3d3246a0d06be622867d21af25f997aeeb105f |
| The memory should have strong access ordering. |
| This feature is specific to |
| the PowerPC architecture |
| (version 2.06 of the architecture specification adds the SAO CPU feature, |
| and it is available on POWER 7 or PowerPC A2, for example). |
| .PP |
| Additionally (since Linux 2.6.0), |
| .I prot |
| can have one of the following flags set: |
| .TP |
| .\" mm/mmap.c: |
| .\" vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) | |
| .\" mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; |
| .\" And calc_vm_flag_bits converts only GROWSDOWN/DENYWRITE/LOCKED. |
| .B PROT_GROWSUP |
| Apply the protection mode up to the end of a mapping |
| that grows upwards. |
| (Such mappings are created for the stack area on |
| architectures\(emfor example, HP-PARISC\(emthat |
| have an upwardly growing stack.) |
| .\" The VMA is one that was marked with VM_GROWSUP by the kernel |
| .\" when the stack was created. Note that (unlike VM_GROWSDOWN), |
| .\" there is no mmap() flag (analogous to MAP_GROWSDOWN) for |
| .\" creating a VMA that is marked VM_GROWSUP. |
| .TP |
| .B 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 the |
| .B MAP_GROWSDOWN |
| flag set). |
| .PP |
| Like |
| .BR mprotect (), |
| .BR pkey_mprotect () |
| changes the protection on the pages specified by |
| .IR addr |
| and |
| .IR len . |
| The |
| .I pkey |
| argument specifies the protection key (see |
| .BR pkeys (7)) |
| to assign to the memory. |
| The protection key must be allocated with |
| .BR pkey_alloc (2) |
| before it is passed to |
| .BR pkey_mprotect (). |
| For an example of the use of this system call, see |
| .BR pkeys (7). |
| .SH RETURN VALUE |
| On success, |
| .BR mprotect () |
| and |
| .BR pkey_mprotect () |
| return zero. |
| On error, these system calls return \-1, and |
| .I errno |
| is set to indicate the error. |
| .SH ERRORS |
| .TP |
| .B EACCES |
| The memory cannot be given the specified access. |
| This can happen, for example, if you |
| .BR mmap (2) |
| a file to which you have read-only access, then ask |
| .BR mprotect () |
| to mark it |
| .BR PROT_WRITE . |
| .TP |
| .B EINVAL |
| \fIaddr\fP is not a valid pointer, |
| or not a multiple of the system page size. |
| .TP |
| .BR EINVAL |
| .RB ( pkey_mprotect ()) |
| \fIpkey\fP has not been allocated with |
| .BR pkey_alloc (2) |
| .TP |
| .BR EINVAL |
| Both |
| .BR PROT_GROWSUP |
| and |
| .BR PROT_GROWSDOWN |
| were specified in |
| .IR prot . |
| .TP |
| .BR EINVAL |
| Invalid flags specified in |
| .IR prot . |
| .TP |
| .BR EINVAL |
| (PowerPC architecture) |
| .B PROT_SAO |
| was specified in |
| .IR prot , |
| but SAO hardware feature is not available. |
| .TP |
| .B ENOMEM |
| Internal kernel structures could not be allocated. |
| .TP |
| .B ENOMEM |
| Addresses in the range |
| .RI [ addr , |
| .IR addr + len \-1] |
| are invalid for the address space of the process, |
| or specify one or more pages that are not mapped. |
| (Before kernel 2.4.19, the error |
| .BR EFAULT |
| was incorrectly produced for these cases.) |
| .TP |
| .B ENOMEM |
| Changing the protection of a memory region would result in the total number of |
| mappings with distinct attributes (e.g., read versus read/write protection) |
| exceeding the allowed maximum. |
| .\" I.e., the number of VMAs would exceed the 64 kB maximum |
| (For example, making the protection of a range |
| .BR PROT_READ |
| in the middle of a region currently protected as |
| .BR PROT_READ|PROT_WRITE |
| would result in three mappings: |
| two read/write mappings at each end and a read-only mapping in the middle.) |
| .SH VERSIONS |
| .BR pkey_mprotect () |
| first appeared in Linux 4.9; |
| library support was added in glibc 2.27. |
| .SH CONFORMING TO |
| .BR mprotect (): |
| POSIX.1-2001, POSIX.1-2008, SVr4. |
| .\" SVr4 defines an additional error |
| .\" code EAGAIN. The SVr4 error conditions don't map neatly onto Linux's. |
| POSIX says that the behavior of |
| .BR mprotect () |
| is unspecified if it is applied to a region of memory that |
| was not obtained via |
| .BR mmap (2). |
| .PP |
| .BR pkey_mprotect () |
| is a nonportable Linux extension. |
| .SH NOTES |
| On Linux, it is always permissible to call |
| .BR 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. |
| .PP |
| Whether |
| .B PROT_EXEC |
| has any effect different from |
| .B PROT_READ |
| depends on processor architecture, kernel version, and process state. |
| If |
| .B READ_IMPLIES_EXEC |
| is set in the process's personality flags (see |
| .BR personality (2)), |
| specifying |
| .B PROT_READ |
| will implicitly add |
| .BR PROT_EXEC . |
| .PP |
| On some hardware architectures (e.g., i386), |
| .B PROT_WRITE |
| implies |
| .BR PROT_READ . |
| .PP |
| POSIX.1 says that an implementation may permit access |
| other than that specified in |
| .IR prot , |
| but at a minimum can allow write access only if |
| .B PROT_WRITE |
| has been set, and must not allow any access if |
| .B PROT_NONE |
| has been set. |
| .PP |
| Applications should be careful when mixing use of |
| .BR mprotect () |
| and |
| .BR pkey_mprotect (). |
| On x86, when |
| .BR mprotect () |
| is used with |
| .IR prot |
| set to |
| .B PROT_EXEC |
| a pkey may be allocated and set on the memory implicitly |
| by the kernel, but only when the pkey was 0 previously. |
| .PP |
| On systems that do not support protection keys in hardware, |
| .BR pkey_mprotect () |
| may still be used, but |
| .IR pkey |
| must be set to \-1. |
| When called this way, the operation of |
| .BR pkey_mprotect () |
| is equivalent to |
| .BR mprotect (). |
| .SH EXAMPLES |
| .\" sigaction.2 refers to this example |
| The program below demonstrates the use of |
| .BR mprotect (). |
| The program allocates four pages of memory, makes the third |
| of these pages read-only, and then executes a loop that walks upward |
| through the allocated region modifying bytes. |
| .PP |
| An example of what we might see when running the program is the |
| following: |
| .PP |
| .in +4n |
| .EX |
| .RB "$" " ./a.out" |
| Start of region: 0x804c000 |
| Got SIGSEGV at address: 0x804e000 |
| .EE |
| .in |
| .SS Program source |
| \& |
| .EX |
| #include <unistd.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <malloc.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <sys/mman.h> |
| |
| #define handle_error(msg) \e |
| do { perror(msg); exit(EXIT_FAILURE); } while (0) |
| |
| 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\en", si\->si_addr); |
| exit(EXIT_FAILURE); |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int pagesize; |
| struct sigaction sa; |
| |
| sa.sa_flags = SA_SIGINFO; |
| sigemptyset(&sa.sa_mask); |
| sa.sa_sigaction = handler; |
| if (sigaction(SIGSEGV, &sa, NULL) == \-1) |
| handle_error("sigaction"); |
| |
| pagesize = sysconf(_SC_PAGE_SIZE); |
| if (pagesize == \-1) |
| handle_error("sysconf"); |
| |
| /* Allocate a buffer aligned on a page boundary; |
| initial protection is PROT_READ | PROT_WRITE. */ |
| |
| buffer = memalign(pagesize, 4 * pagesize); |
| if (buffer == NULL) |
| handle_error("memalign"); |
| |
| printf("Start of region: %p\en", buffer); |
| |
| if (mprotect(buffer + pagesize * 2, pagesize, |
| PROT_READ) == \-1) |
| handle_error("mprotect"); |
| |
| for (char *p = buffer ; ; ) |
| *(p++) = \(aqa\(aq; |
| |
| printf("Loop completed\en"); /* Should never happen */ |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .SH SEE ALSO |
| .BR mmap (2), |
| .BR sysconf (3), |
| .BR pkeys (7) |