Provided by: manpages-ru-dev_4.27.0-1_all bug

НАИМЕНОВАНИЕ

       mprotect, pkey_mprotect - контролирует доступ к области памяти

БИБЛИОТЕКА

       Стандартная библиотека языка C (libc, -lc)

ОБЗОР

       #include <sys/mman.h>

       int mprotect(void addr[.len], size_t len, int prot);

       #define _GNU_SOURCE             /* смотрите feature_test_macros(7) */
       #include <sys/mman.h>

       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 <malloc.h>
       #include <signal.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/mman.h>
       #include <unistd.h>

       #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  <aereiae@gmail.com>,  Alexey
       <a.chepugov@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>,
       Dmitry Bolkhovskikh <d20052005@yandex.ru>, ITriskTI <ITriskTI@gmail.com>,  Max  Is  <ismax799@gmail.com>,
       Yuri   Kozlov   <yuray@komyakino.ru>,   Иван   Павлов  <pavia00@gmail.com>,  Малянов  Евгений  Викторович
       <maljanow@outlook.com> и Kirill Rekhov <krekhov.dev@gmail.com>

       Этот перевод является свободной программной документацией; он распространяется на условиях  общедоступной
       лицензии  GNU  (GNU  General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

       Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите  об  этом
       разработчику(ам)   по   его(их)  адресу(ам)  электронной  почты  или  по  адресу  списка рассылки русских
       переводчиков.

Справочные страницы Linux 6.9.1                  15 июня 2024 г.                                     mprotect(2)