Provided by: manpages-fr_4.15.0-9_all bug

NOM

       pkeys – Aperçu des clés de protection de la mémoire

DESCRIPTION

       Les  clés  de protection de la mémoire (Memory Protection Keys — pkeys) sont une extension
       des permissions de la mémoire basées sur les  pages.  Les  permissions  normales  de  page
       nécessitent  des  appels système coûteux et des invalidations du TLB lors de modifications
       de permission. Les clés de protection de la mémoire fournissent un mécanisme pour  changer
       les  protections  sans  avoir  besoin  de  modifier  la  table  des  pages  lors de chaque
       modification de permission.

       Pour utiliser pkeys, le logiciel doit d’abord « étiqueter » une page  dans  la  table  des
       pages avec une pkey. Une fois cette étiquette posée, une application a seulement à changer
       le contenu d’un registre pour retirer l’accès en écriture ou tous les  accès  à  une  page
       étiquetée.

       Les  clés  de  protection  de  la mémoire fonctionnent en conjonction avec les permissions
       PROT_READ, PROT_WRITE  et  PROT_EXEC  existantes  passées  aux  appels  système  tels  que
       mprotect(2) et mmap(2), mais agissent toujours pour restreindre encore plus ces mécanismes
       de permission traditionnels.

       Si un processus réalise un accès qui enfreint les  restrictions  de  pkey,  il  reçoit  un
       signal  SIGSEGV. Consultez sigaction(2) pour des détails sur l’information disponible avec
       ce signal.

       Pour utiliser la fonctionnalité de pkeys, le processeur doit la prendre en  charge  et  le
       noyau  doit  contenir une prise en charge pour la fonctionnalité d’un processeur donné. Au
       tout début de 2016, seuls les processeurs x86 d’Intel à venir étaient pris  en  charge  et
       ceux-ci  géraient 16 clés de protection de la mémoire pour chaque processus. Cependant, la
       pkey 0 est utilisée comme clé par défaut, donc un maximum de 15 sont disponibles pour  une
       utilisation  effective  d’application.  La  clé par défaut est affectée à n’importe quelle
       région de la mémoire pour laquelle une pkey n’a pas été assignée explicitement à l’aide de
       pkey_mprotect(2).

       Les  clés  de  protection ont la capacité d’ajouter une couche de sécurité et de fiabilité
       aux applications, mais elles n’ont pas été conçues principalement pour une  fonctionnalité
       de  sécurité.  Par  exemple, WRPKRU est une instruction entièrement non privilégiée, aussi
       les pkeys sont inutiles dans tous les cas où un attaquant contrôle  le  registre  PKRU  ou
       peut exécuter des instructions arbitraires.

       Les  applications  doivent  être  très  précautionneuses  pour  assurer  de  ne  pas faire
       « fuiter »  leurs  clés  de  protection.  Par  exemple,  avant   d’appeler   pkey_free(2),
       l’application  doit  être  sûre  qu’aucune mémoire a cette pkey assignée. Si l’application
       laisse la  pkey  libérée  assignée,  un  prochain  utilisateur  de  cette  pkey  peut  par
       inadvertance  modifier  les  permissions  d’une  structure  de  données étrangère, pouvant
       impacter la sécurité ou la stabilité. Le noyau permet  actuellement  aux  pkeys  en  cours
       d’avoir  pkey_free(2)  appelée  sur  elles  car  cela  pourrait  avoir des implications de
       performance de processeur ou de mémoire pour réaliser  des  vérifications  supplémentaires
       nécessaires  pour désactiver cet appel. L’implémentation des vérifications nécessaires est
       laissée  aux  applications.  Celles-ci  peuvent  mettre  en  œuvre  ces  vérifications  en
       parcourant  le  fichier  /proc/[pid]/smaps  pour  des  régions de la mémoire ayant la pkey
       assignée. Plus de détails sont fournis dans proc(5).

       Toute application voulant utiliser  les  clés  de  protection  doivent  être  capables  de
       fonctionner  sans  elles. Elles peuvent être indisponibles parce que le matériel exécutant
       cette application ne les prennent pas en charge, le code du noyau ne fournit aucune  prise
       en  charge  ou  cette  prise  en  charge  a  été désactivée, ou parce que les clés ont été
       allouées, peut être par une bibliothèque utilisée par l’application. Il est recommandé aux
       applications  voulant  utiliser les clés de protection de simplement appeler pkey_alloc(2)
       et de tester si l’appel réussit au lieu d’essayer de détecter une prise en  charge  de  la
       fonctionnalité par tout autre moyen.

       Quoique  non  nécessaire,  la  prise en charge matérielle des clés de protection peut être
       déterminée à l’aide de l’instruction cpuid. La manière de réaliser cela est  décrite  dans
       le  manuel pour les développeurs de logiciels pour Intel. Le noyau réalise ce dénombrement
       et expose cette information dans le champ « flags » de /proc/cpuinfo.  La  chaîne  « pku »
       dans  ce  champ  indique la prise en charge matérielle des clés de protection et la chaîne
       « ospke » indique que le noyau gère et active la prise en charge des clés de protection.

       Les  applications  utilisant  les  threads  et  les  clés  de  protection   doivent   être
       particulièrement  attentives.  Les  threads  héritent des droits des clés de protection de
       leur parent au  moment  de  l’appel  système  clone(2).  Les  applications  doivent  aussi
       s’assurer que leurs propres permissions sont appropriées pour les threads enfant au moment
       de l’appel clone(2) ou de s’assurer que chaque  thread  enfant  peut  réaliser  sa  propre
       initialisation des droits de clés de protection.

   Comportement du gestionnaire de signal
       Chaque  fois  qu’un  gestionnaire  de  signal  est  invoqué  (y  compris  pour les signaux
       imbriqués), le thread obtient temporairement un nouvel ensemble par défaut  de  droits  de
       clés de protection qui outrepasse les droits du contexte interrompu. Cela signifie que les
       applications  doivent  rétablir  les  droits  désirés  des  clés  de  protection  lors  de
       l’utilisation  d’un gestionnaire de signal si ces droits différent de ceux par défaut. Les
       droits de n’importe quel contexte sont restaurés lors du renvoi du gestionnaire de signal.

       Ce comportement de signal est inhabituel et est dû au fait que le registre PKRU  x86  (qui
       stocke les droits d’accès des clés de protection) est géré avec le même mécanisme matériel
       (XSAVE) qui gère les registres de virgule flottante. Le comportement du signal est le même
       que celui des registres de virgule flottante.

   Appels système des clés de protection
       Le  noyau Linux met en œuvre les appels système suivants relatifs aux clés de protection :
       pkey_mprotect(2), pkey_alloc(2) et pkey_free(2).

       Les appels système de Linux pour pkey sont  disponibles  uniquement  si  le  noyau  a  été
       configuré et construit avec l’option CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS.

EXEMPLES

       Le  programme  ci-dessous  alloue  une  page de mémoire avec les permissions en lecture et
       écriture. Puis il écrit quelques données dans la mémoire et les relit avec  succès.  Après
       cela,  il  essaie  d’allouer  une  clé  de  protection  et  désactive l’accès à la page en
       utilisant l’instruction WRPKRU. Il essaie alors d’accéder  à  la  page  qui  est  supposée
       provoquer un signal fatal pour l’application.

           $ ./a.out
           le buffer contient : 73
           sur le point de lire le buffer de nouveau...
           Segmentation fault (core dumped)

   Source du programme

       #define _GNU_SOURCE
       #include <unistd.h>
       #include <sys/syscall.h>
       #include <stdio.h>
       #include <sys/mman.h>

       static inline void
       wrpkru(unsigned int pkru)
       {
           unsigned int eax = pkru;
           unsigned int ecx = 0;
           unsigned int edx = 0;

           asm volatile(".byte 0x0f,0x01,0xef\n\t"
                        : : "a" (eax), "c" (ecx), "d" (edx));
       }

       int
       pkey_set(int pkey, unsigned long rights, unsigned long flags)
       {
           unsigned int pkru = (rights << (2 * pkey));
           return wrpkru(pkru);
       }

       int
       pkey_mprotect(void *ptr, size_t size, unsigned long orig_prot,
                     unsigned long pkey)
       {
           return syscall(SYS_pkey_mprotect, ptr, size, orig_prot, pkey);
       }

       int
       pkey_alloc(void)
       {
           return syscall(SYS_pkey_alloc, 0, 0);
       }

       int
       pkey_free(unsigned long pkey)
       {
           return syscall(SYS_pkey_free, pkey);
       }

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                                  } while (0)

       int
       main(void)
       {
           int status;
           int pkey;
           int *buffer;

           /*
            * Allocation d’une page de mémoire.
            */
           buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
           if (buffer == MAP_FAILED)
               errExit("mmap");

           /*
            * Mise de données aléatoires dans la page (toujours OK à affecter).
            */
           *buffer = __LINE__;
           printf("le buffer contient : %d\n", *buffer);

           /*
            * Allocation d’une clé de protection :
            */
           pkey = pkey_alloc();
           if (pkey == -1)
               errExit("pkey_alloc");

           /*
            * Désactivation de l’accès à toute mémoire avec l’ensemble
            * « pkey », même si aucun droit n’existe à ce moment.
            */
           status = pkey_set(pkey, PKEY_DISABLE_ACCESS, 0);
           if (status)
               errExit("pkey_set");

           /*
            * Mettre la clé de protection dans « buffer ».
            * Noter que c’est toujours lect./écrit. aussi longtemps que mprotect()
            * est concerné et que le pkey_set() précédent l’écrase.
            */
           status = pkey_mprotect(buffer, getpagesize(),
                                  PROT_READ | PROT_WRITE, pkey);
           if (status == -1)
               errExit("pkey_mprotect");

           printf("sur le point de lire le buffer de nouveau...\n");

           /*
            * Ceci va planter car l’accès a été désactivé.
            */
           printf("le buffer contient : %d\n", *buffer);

           status = pkey_free(pkey);
           if (status == -1)
               errExit("pkey_free");

           exit(EXIT_SUCCESS);
       }

VOIR AUSSI

       pkey_alloc(2), pkey_free(2), pkey_mprotect(2), sigaction(2)

COLOPHON

       Cette  page  fait partie de la publication 5.13 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-Paul  Guillonneau
       <guillonneau.jeanpaul@free.fr>

       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⟩.