mprotect(2) System Calls Manual mprotect(2) NOM mprotect, pkey_mprotect - Definir la protection d'une partie de la memoire BIBLIOTHEQUE Bibliotheque C standard (libc, -lc) SYNOPSIS #include int mprotect(void addr[.len], size_t len, int prot); #define _GNU_SOURCE /* Consultez feature_test_macros(7) */ #include int pkey_mprotect(void addr[.len], size_t len, int prot, int pkey); DESCRIPTION mprotect() change les protections d'acces pour la (les) page(s) de memoire du processus appelant contenant tout ou une partie de l'intervalle [addr, addr+len-1]. addr doit etre aligne sur une limite de page. Si le processus appelant essaie d'acceder a la memoire en violant la protection, le noyau genere un signal SIGSEGV pour ce processus. prot est une combinaison des attributs d'acces suivants : PROT_NONE ou le resultat d'une operation OU bit a bit parmi les autres valeurs de la liste suivante : PROT_NONE On ne peut pas acceder du tout a la zone de memoire. PROT_READ On peut lire la zone de memoire. PROT_WRITE On peut modifier la zone de memoire. PROT_EXEC La zone de memoire peut contenir du code executable. PROT_SEM (depuis Linux 2.5.7) La memoire peut etre utilisee pour des operations atomiques. Cet attribut a ete introduit dans l'implementation de futex(2) (afin de garantir la possibilite d'effectuer des operations atomiques exigees par des commandes comme FUTEX_WAIT), mais il n'est actuellement utilise sur aucune architecture. PROT_SAO (depuis Linux 2.6.26) La memoire devrait avoir une forte organisation de son acces. Cette fonctionnalite est specifique a l'architecture PowerPC (la version 2.06 de la specification 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'a la fin d'une projection qui grandit vers le haut (de telles projections sont creees pour la zone de la pile sur une architecture -- par exemple HP-PARISC -- dont la pile a tendance a s'accroitre vers le haut). PROT_GROWSDOWN Appliquer le mode de protection vers le bas jusqu'au debut d'une projection qui grandit vers le bas (il pourrait s'agir d'un segment de pile ou d'un segment projete avec un drapeau MAP_GROWSDOWN positionne). Comme mprotect(), pkey_mprotect() modifie la protection des pages indiquees par addr et len. Le parametre pkey indique la cle de protection (voir pkeys(7))) a assigner a la memoire. La cle de protection doit etre allouee avec pkey_alloc(2) avant d'etre passee a pkey_mprotect(). Pour un exemple d'utilisation de cet appel systeme, voir pkeys(7). VALEUR RENVOYEE mprotect() et pkey_mprotect() renvoient 0 s'ils reussissent. En cas d'erreur, ces appels systeme renvoient -1 et errno est defini pour indiquer l'erreur. ERREURS EACCES L'acces specifie n'est pas possible sur ce type de memoire. Cela se produit par exemple si vous utilisez mmap(2) pour representer un fichier en lecture seule en memoire, 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 systeme. EINVAL (pkey_mprotect()) pkey n'a pas ete alloue avec pkey_alloc(2) EINVAL PROT_GROWSUP et PROT_GROWSDOWN etaient indiques tous les deux dans prot. EINVAL Drapeaux non valables indiques dans prot. EINVAL (Architecture PowerPC) PROT_SAO etait indique dans prot, mais la fonctionnalite materielle 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'etend sur des pages non projetees (avant Linux 2.4.19, l'erreur EFAULT etait produite a tort dans ce cas). ENOMEM La modification de la protection d'une zone de la memoire ferait depasser le nombre maximal autorise de projections avec des attributs differents (comme la protection en lecture vs lecture/ecriture) (par exemple, positionner une protection d'une plage PROT_READ au milieu d'une zone protegee par PROT_READ|PROT_WRITE donnerait trois projections : deux en lecture/ecriture aux extremites et une en lecture seule au milieu). VERSIONS POSIX indique que le comportement de mprotect() n'est pas specifie s'il s'applique a une zone de memoire non obtenue a l'aide de mmap(2). Sous Linux, il est toujours autorise d'appeler mprotect() sur une adresse de l'espace d'adressage du processus (excepte pour la zone vsyscall du noyau). En particulier, il peut etre utilise pour rendre une projection de code existante accessible en ecriture. La difference entre PROT_EXEC et PROT_READ depend de l'architecture, de la version du noyau et de l'etat du processus. Sur certaines, si READ_IMPLIES_EXEC est positionne dans les drapeaux de la personnalite d'un processus (voir personality(2)), le fait d'indiquer PROT_READ ajoutera implicitement PROT_EXEC. Sur certaines architectures materielles (comme i386), PROT_WRITE implique PROT_READ. POSIX.1 indique qu'une implementation peut autoriser un acces autre que celui donne dans prot, mais doit au minimum autoriser l'acces en ecriture si PROT_WRITE etait passe, et ne doit autoriser aucun acces si PROT_NONE etait passe. Les applications devraient faire attention quand elles melangent l'utilisation de mprotect() et de pkey_mprotect(). Sur x86, quand mprotect() est utilise avec prot positionne sur PROT_EXEC, une pkey peut etre allouee et positionnee implicitement sur la memoire par le noyau, mais uniquement quand la pkey etait de 0 precedemment. Sur les systemes qui ne gerent pas les cles de protection dans le materiel, pkey_mprotect() peut toujours etre utilise, mais pkey doit etre positionne sur -1. Si elle est appelee ainsi, l'operation pkey_mprotect() est equivalente a mprotect(). STANDARDS mproject() POSIX.1-2008. pkey_mprotect() Linux. HISTORIQUE mproject() POSIX.1-2001, SVr4. pkey_mprotect() Linux 4.9, glibc 2.27. NOTES EXEMPLES Le programme ci-dessous montre l'utilisation de mprotect(). Il alloue quatre pages de memoire, rend la troisieme accessible en lecture seule, puis execute une boucle qui se deplace en avancant dans la region allouee et en modifiant son contenu. Voici un exemple d'execution de ce programme : $ ./a.out Debut de la region : 0x804c000 Recu SIGSEGV a l'adresse : 0x804e000 Source du programme #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) { /* Remarque : appeler printf() a partir d'un gestionnaire de signal n'est pas sur (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 facon simple de montrer que le gestionnaire a ete appele. */ printf("Recu SIGSEGV a l'adresse : %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"); /* Allouer un tampon aligne 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("Debut de la region : %p\n", buffer); if (mprotect(buffer + pagesize * 2, pagesize, PROT_READ) == -1) handle_error("mprotect"); for (char *p = buffer ; ; ) *(p++) = 'a'; printf("Boucle terminee\n"); /* Ne devrait jamais arriver */ exit(EXIT_SUCCESS); } VOIR AUSSI mmap(2), sysconf(3), pkeys(7) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot et Jean-Philippe MENGUAL Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 mprotect(2)