Provided by: manpages-fr-dev_4.13-4_all bug

NOM

       mprotect, pkey_mprotect - Définir la protection d'une partie de la mémoire

SYNOPSIS

       #include <sys/mman.h>

       int mprotect(void *addr, size_t len, int prot);

       #define _GNU_SOURCE             /* Consultez feature_test_macros(7) */
       #include <sys/mman.h>

       int pkey_mprotect(void *addr, size_t len, int prot, int pkey);

DESCRIPTION

       mprotect()  change  les  protections d'accès pour la (les) page(s) de mémoire du processus
       appelant contenant tout ou une partie de l'intervalle [addr, addr+len-1]. addr  doit  être
       aligné sur une limite de page.

       Si  le processus appelant essaie d'accéder à la mémoire en violant la protection, le noyau
       génère un signal SIGSEGV pour ce processus.

       prot est une combinaison des attributs d'accès suivants : PROT_NONE ou le  résultat  d’une
       opération OU bit à bit parmi les autres valeurs de la liste suivante :

       PROT_NONE
              On ne peut pas accéder du tout à la zone de mémoire.

       PROT_READ
              On peut lire la zone de mémoire.

       PROT_WRITE
              On peut modifier la zone de mémoire.

       PROT_EXEC
              La zone de mémoire peut contenir du code exécutable.

       PROT_SEM (depuis Linux 2.5.7)
              La  mémoire  peut  être  utilisée pour des opérations atomiques. Cet attribut a été
              introduit dans l'implémentation  de  futex(2)  (afin  de  garantir  la  possibilité
              d'effectuer  des  opérations atomiques exigées par des commandes comme FUTEX_WAIT),
              mais il n'est actuellement utilisé sur aucune architecture.

       PROT_SAO (depuis Linux 2.6.26)
              La mémoire devrait avoir une forte organisation de son accès. Cette  fonctionnalité
              est  spécifique  à  l'architecture  PowerPC (la version 2.06 de la spécification de
              l'architecture ajoute la fonction SAO du processeur,  disponible  par  exemple  sur
              POWER 7 ou PowerPC A2).

       En  outre  (depuis Linux 2.6.0), il est possible de positionner les attributs suivants sur
       prot :

       PROT_GROWSUP
              Appliquer le mode de protection jusqu'à la fin d'une projection qui grandit vers le
              haut  (de  telles  projections  sont  créées  pour  la  zone  de  la  pile  sur une
              architecture — par exemple HP-PARISC — dont la pile a tendance à  s'accroître  vers
              le haut).

       PROT_GROWSDOWN
              Appliquer  le  mode  de  protection vers le bas jusqu'au début d'une projection qui
              grandit vers le bas (il pourrait s'agir  d'un  segment  de  pile  ou  d'un  segment
              projeté avec un drapeau MAP_GROWSDOWN positionné).

       Comme  mprotect(),  pkey_mprotect()  modifie la protection des pages indiquées par addr et
       len. Le paramètre pkey indique la clé de protection  (voir  pkeys(7)))  à  assigner  à  la
       mémoire.  La  clé de protection doit être allouée avec pkey_alloc(2) avant d'être passée à
       pkey_mprotect(). Pour un exemple d'utilisation de cet appel système, voir pkeys(7).

VALEUR RENVOYÉE

       mprotect() et pkey_mprotect() renvoient 0 s'ils réussissent. En cas d'erreur,  ces  appels
       système renvoient -1 et errno est positionné adéquatement.

ERREURS

       EACCES L'accès  spécifié  n'est  pas  possible sur ce type de mémoire. Cela se produit par
              exemple si vous utilisez mmap(2) pour représenter un fichier en  lecture  seule  en
              mémoire, et puis demandez de marquer cette zone avec PROT_WRITE.

       EINVAL addr  n'est  pas  un  pointeur valable, ou ce n'est pas un multiple de la taille de
              page du système.

       EINVAL (pkey_mprotect()) pkey n'a pas été alloué avec pkey_alloc(2)

       EINVAL PROT_GROWSUP et PROT_GROWSDOWN étaient indiqués tous les deux dans prot.

       EINVAL Drapeaux non valables indiqués dans prot.

       EINVAL (Architecture PowerPC) PROT_SAO était indiqué dans  prot,  mais  la  fonctionnalité
              matérielle SAO n'est pas disponible.

       ENOMEM Impossible d'allouer des structures internes au noyau.

       ENOMEM Les  adresses  dans  l'intervalle  [addr,  addr+len-1]  ne  sont  pas valables dans
              l'espace d'adressage du processus,  ou  l'intervalle  s'étend  sur  des  pages  non
              projetées  (dans  les  noyaux antérieurs à 2.4.19, l'erreur EFAULT était produite à
              tort dans ce cas).

       ENOMEM La modification de la protection d'une zone de la mémoire ferait dépasser le nombre
              maximal  autorisé de projections avec des attributs différents (comme la protection
              en lecture vs lecture/écriture) (par  exemple,  positionner  une  protection  d'une
              plage  PROT_READ  au  milieu d'une zone protégée par PROT_READ|PROT_WRITE donnerait
              trois projections : deux en lecture/écriture aux extrémités et une en lecture seule
              au milieu).

VERSIONS

       pkey_mprotect()  est  apparu  dans  Linux  4.9 ;  la  bibliothèque glibc le gère depuis la
       version 2.27.

CONFORMITÉ

       mprotect() : POSIX.1-2001, POSIX.1-2008,  SVr4.  POSIX  indique  que  le  comportement  de
       mprotect()  n'est  pas spécifié s'il s'applique à une zone de mémoire non obtenue à l'aide
       de mmap(2).

       pkey_mprotect() est une extension Linux non portable.

NOTES

       Sous Linux, il est toujours autorisé d'appeler mprotect()  sur  une  adresse  de  l'espace
       d'adressage du processus (excepté pour la zone vsyscall du noyau). En particulier, il peut
       être utilisé pour rendre une projection de code existante accessible en écriture.

       La différence entre PROT_EXEC et PROT_READ dépend de  l'architecture,  de  la  version  du
       noyau  et  de l'état du processus. Sur certaines, si READ_IMPLIES_EXEC est positionné dans
       les drapeaux de la personnalité d'un processus (voir personality(2)), le  fait  d'indiquer
       PROT_READ ajoutera implicitement PROT_EXEC.

       Sur certaines architectures matérielles (comme i386), PROT_WRITE implique PROT_READ.

       POSIX.1  indique  qu'une implémentation peut autoriser un accès autre que celui donné dans
       prot, mais doit au minimum autoriser l'accès en écriture si PROT_WRITE était passé, et  ne
       doit autoriser aucun accès si PROT_NONE était passé.

       Les  applications  devraient  faire  attention  quand  elles  mélangent  l'utilisation  de
       mprotect() et de  pkey_mprotect().  Sur  x86,  quand  mprotect()  est  utilisé  avec  prot
       positionné  sur  PROT_EXEC, une pkey peut être allouée et positionnée implicitement sur la
       mémoire par le noyau, mais uniquement quand la pkey était de 0 précédemment.

       Sur  les  systèmes  qui  ne  gèrent  pas  les  clés  de  protection  dans   le   matériel,
       pkey_mprotect() peut toujours être utilisé, mais pkey doit être positionné sur -1. Si elle
       est appelée ainsi, l'opération pkey_mprotect() est équivalente à mprotect().

EXEMPLES

       Le programme ci-dessous montre l'utilisation de mprotect().  Il  alloue  quatre  pages  de
       mémoire,  rend  la  troisième  accessible en lecture seule, puis exécute une boucle qui se
       déplace en avançant dans la région allouée et en modifiant son contenu.

       Voici un exemple d'exécution de ce programme :

           $ ./a.out
           Début de la région :       0x804c000
           Reçu SIGSEGV à l'adresse : 0x804e000

   Source du programme

       #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) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

       static char *buffer;

       static void
       handler(int sig, siginfo_t *si, void *unused)
       {
           /* Remarque : appeler printf() à partir d'un gestionnaire de signal
              n'est pas sûr (vous ne devriez pas le faire dans des programmes en
              production) car printf() n'est pas async-signal-safe ; voir
              signal-safety(7). Cependant, nous utilisons printf() ici comme façon
              simple de montrer que le gestionnaire a été appelé. */

       static void
           printf("Reçu SIGSEGV à l'adresse : %p\n", 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");

           /* Allouer un tampon aligné sur une limite de page ;
              la protection initiale est PROT_READ | PROT_WRITE */

           buffer = memalign(pagesize, 4 * pagesize);
           if (buffer == NULL)
               handle_error("memalign");

           printf("Début de la région :       %p\n", buffer);

           if (mprotect(buffer + pagesize * 2, pagesize,
                       PROT_READ) == -1)
               handle_error("mprotect");

           for (char *p = buffer ; ; )
               *(p++) = 'a';

           printf("Boucle terminée\n");     /* Ne devrait jamais arriver */
           exit(EXIT_SUCCESS);
       }

VOIR AUSSI

       mmap(2), sysconf(3), pkeys(7)

COLOPHON

       Cette page fait partie de la publication 5.10 du projet man-pages Linux.  Une  description
       du  projet et des instructions pour signaler des anomalies et la dernière version de cette
       page peuvent être trouvées à l'adresse https://www.kernel.org/doc/man-pages/.

TRADUCTION

       La traduction française de cette  page  de  manuel  a  été  créée  par  Christophe  Blaess
       <https://www.blaess.fr/christophe/>,  Stéphan  Rafin  <stephan.rafin@laposte.net>, Thierry
       Vignaud <tvignaud@mandriva.com>, François Micaux, Alain  Portal  <aportal@univ-montp2.fr>,
       Jean-Philippe    Guérard   <fevrier@tigreraye.org>,   Jean-Luc   Coulon   (f5ibh)   <jean-
       luc.coulon@wanadoo.fr>,   Julien    Cristau    <jcristau@debian.org>,    Thomas    Huriaux
       <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin
       Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,  Denis
       Barbier  <barbier@debian.org>,  David  Prévot <david@tilapin.org> et Jean-Philippe MENGUAL
       <jpmengual@debian.org>

       Cette traduction est une documentation libre ; veuillez vous reporter  à  la  GNU  General
       Public   License   version 3  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  concernant  les
       conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

       Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un
       message à debian-l10n-french@lists.debian.org ⟨⟩.