MPROTECT

Manuel du programmeur Linux (2)
5 janvier 2014
 

NOM

mprotect - Changer la protection d'une partie de la mémoire  

SYNOPSIS

#include <sys/mman.h>

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

DESCRIPTION

mprotect() change la protection pour la (les) page(s) mémoire du processus appelant contenant tout ou une partie de l'intervalle [addraddr+len-1]. addr doit être aligné sur une 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 soit PROT_NONE, soit un OU binaire « | » entre les valeurs suivantes :

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.
 

VALEUR RENVOYÉE

mprotect() renvoie 0 s'il réussit, ou -1 s'il échoue, auquel cas errno contient le code d'erreur.  

ERREURS

EACCES
L'accès spécifié n'est pas possible sur ce type de mémoire. Ceci se produit par exemple si vous utilisez mmap(2) pour représenter un fichier en lecture seule en mémoire, et si vous demandez de marquer cette zone avec PROT_WRITE.
EINVAL
addr n'est pas un pointeur valide, ou ce n'est pas un multiple de la taille de page du système.
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).
 

CONFORMITÉ

SVr4, POSIX.1-2001. POSIX précise que le comportement de mprotect() n'est pas spécifié s'il est appliqué sur des zones de mémoire non obtenues avec mmap(2).  

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 et de la version du noyau. Sur certaines architectures matérielles (par exemple, i386), PROT_WRITE implique PROT_READ.

POSIX.1-2001 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é.  

EXEMPLE

Le programme ci-dessous 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)
{
    printf("Reçu SIGSEGV à l'adresse : 0x%lx\n",
            (long) si->si_addr);
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    char *p;
    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 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 :       0x%lx\n", (long) buffer);

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

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

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

VOIR AUSSI

mmap(2), sysconf(3)  

COLOPHON

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

TRADUCTION

Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a <http://po4a.alioth.debian.org/> par l'équipe de traduction francophone au sein du projet perkamon <http://perkamon.alioth.debian.org/>.

Christophe Blaess <http://www.blaess.fr/christophe/> (1996-2003), Alain Portal <http://manpagesfr.free.fr/> (2003-2006). Julien Cristau et l'équipe francophone de traduction de Debian (2006-2009).

Veuillez signaler toute erreur de traduction en écrivant à <perkamon-fr@traduc.org>.

Vous pouvez toujours avoir accès à la version anglaise de ce document en utilisant la commande « LC_ALL=C man <section> <page_de_man> ».


 

Index

NOM
SYNOPSIS
DESCRIPTION
VALEUR RENVOYÉE
ERREURS
CONFORMITÉ
NOTES
EXEMPLE
Source du programme
VOIR AUSSI
COLOPHON
TRADUCTION

This document was created by man2html, using the manual pages.
Time: 21:52:35 GMT, July 12, 2014