mprotect(2) System Calls Manual mprotect(2) mprotect, pkey_mprotect - LIBRARY Standard C library (libc, -lc) #include int mprotect(void addr[.len], size_t len, int prot); #define _GNU_SOURCE /* feature_test_macros(7) */ #include int pkey_mprotect(void addr[.len], size_t len, int prot, int pkey); mprotect() , , , [addr, addr+len-1]. addr . , SIGSEGV. prot is a combination of the following access flags: PROT_NONE or a bitwise OR of the other values in the following list: PROT_NONE . PROT_READ . PROT_WRITE . PROT_EXEC . PROT_SEM ( Linux 2.5.7) . futex(2) ( , FUTEX_WAIT), . PROT_SAO ( Linux 2.6.26) . PowerPC ( 2.06 SAO , , POWER 7 PowerPC A2). ( Linux 2.6.0), prot : 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--for example, HP-PARISC--that have an upwardly growing stack.) PROT_GROWSDOWN , ( , MAP_GROWSDOWN). mprotect(), pkey_mprotect() , addr len. pkey ( pkeys(7)), . pkey_alloc(2) pkey_mprotect(). pkeys(7). On success, mprotect() and pkey_mprotect() return zero. On error, these system calls return -1, and errno is set to indicate the error. EACCES . , , mmap(2) , mprotect() PROT_WRITE. EINVAL addr . EINVAL (pkey_mprotect()) pkey pkey_alloc(2). EINVAL prot , PROT_GROWSUP PROT_GROWSDOWN. EINVAL prot. EINVAL ( PowerPC ) prot PROT_SAO, SAO. ENOMEM . ENOMEM Addresses in the range [addr, addr+len-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 error EFAULT was incorrectly produced for these cases.) ENOMEM ( /). , PROT_READ , PROT_READ|PROT_WRITE, : , / . POSIX says that the behavior of mprotect() is unspecified if it is applied to a region of memory that was not obtained via mmap(2). Linux mprotect() ( vsyscall). , . PROT_EXEC PROT_READ , . READ_IMPLIES_EXEC ( personality(2)), PROT_READ PROT_EXEC. (, i386) PROT_WRITE PROT_READ. POSIX.1 , prot, PROT_WRITE, , PROT_NONE. mprotect() pkey_mprotect() . x86, mprotect() prot PROT_EXEC, pkey , pkey 0. pkey_mprotect() , pkey -1. pkey_mprotect() mprotect(). mprotect() POSIX.1-2008. pkey_mprotect() Linux. mprotect() POSIX.1-2001, SVr4. pkey_mprotect() Linux 4.9, glibc 2.27. , , mprotect(). , , , , . : $ ./a.out : 0x804c000 SIGSEGV : 0x804e000 #include #include #include #include #include #include #define handle_error(msg) \ 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\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) 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\n", buffer); if (mprotect(buffer + pagesize * 2, pagesize, PROT_READ) == -1) handle_error("mprotect"); for (char *p = buffer ; ; ) *(p++) = 'a'; printf("Loop completed\n"); /* Should never happen */ exit(EXIT_SUCCESS); } . mmap(2), sysconf(3), pkeys(7) aereiae , Alexey , Azamat Hackimov , Dmitriy S. Seregin , Dmitry Bolkhovskikh , ITriskTI , Max Is , Yuri Kozlov , ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . mprotect(2)