2010-04-24 5 views
4

Je suis en train de construire un programme qui utilise mprotect() pour empêcher l'accès à un bloc de mémoire. Quand la mémoire est demandée, un SIGSEGV est lancé que j'écoute en utilisant un appel de signal().C SIGSEGV Handler & Mprotect

Une fois que le SIGSEGV a été détecté, j'ai besoin d'accéder d'une manière ou d'une autre au pointeur de la mémoire demandée (qui a jeté le défaut) et à la taille du segment demandé. Est-ce possible?

void fifoSigHandler(){ 

    // Needs to only remove protection from requested block of virtual memory 
    mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE); 
    printf("Caught Seg Fault"); 
} 

void fifo_init(void* vm, int vm_size, int n_frames, int page_size) 
{ 
    fifoVm = vm; 
    fifoVm_size = vm_size; 
    fifoFrames = n_frames; 
    fifoPageSize = page_size; 

    mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE); 

    signal(SIGSEGV, fifoSigHandler); 
} 

De plus, est-il un moyen de déterminer le niveau de mprotect() un bloc de mémoire est actuellement affecté (PROT_NONE, PROT_READ, etc ..)?

Répondre

5

Vous devez utiliser sigaction avec SA_SIGINFO au lieu de signal pour établir votre gestionnaire, et vous obtiendrez rappelé des informations utiles dans un siginfo_t, y compris si_addr.

si_addr, comme expliqué dans sigaction (2), contiendra l'adresse. En ce qui concerne la longueur, eh bien, vous n'avez pas de chance à moins que vous ne soyez prêt à analyser les instructions. Le mieux que vous pouvez faire est de prendre des mesures pour la page signalée dans si_addr, et si cela ne suffit pas, vous recevrez un autre signal assez tôt. Au moins, c'est comme ça que nous avons fait les choses dans ObjectStore.

+2

Comment référencer cette information utile? Plus précisément, le pointeur et la taille de la mémoire demandée – pws5068

1

Vous recherchez libsigsegv http://libsigsegv.sourceforge.net/

Mais méfiez-vous que l'appel mprotect est uniquement le signal de sécurité sous Linux, les systèmes POSIX ne supportent pas cela.

Je crains que dans Linux la seule façon d'obtenir des bits de protection de la mémoire est à lire dans /proc/$pid/meminfo

Sur une note latérale (Linux uniquement): Si vous êtes inquiet au sujet de la consommation de mémoire et l'intention de permettre aux pages d'un une plus grande cartographie un par un alors je vous conseillerais de créer votre cartographie en utilisant mmap avec MAP_NORESERVE auquel cas vous obtiendrez un mappage vers des pages de copie en écriture remplies de zéros qui alloueront de la RAM physique à la première écriture. MAP_NORESERVE indique au noyau de ne pas sauvegarder votre mémoire avec de l'espace de permutation, ce qui vous permet d'allouer jusqu'à 64 To d'espace d'adressage virtuel. Le seul inconvénient est que si vous n'avez plus de mémoire, des choses terribles peuvent arriver (oom-killer).

0

Etape 1: Init un sigaction:

struct sigaction act; 
memset(&act, 0, sizeof(struct sigaction)); 
sigemptyset(&act.sa_mask); 
act.sa_sigaction = handler; 
act.sa_flags = SA_SIGINFO | SA_ONSTACK; 

Etape 2: Choisir sigaction poignée SIGSEGV:

sigaction(SIGSEGV, &act, NULL); 

(Facultatif) Etape 3: Faire il traiter d'autres Signaux de mémoire aussi:

sigaction(SIGBUS, &act, NULL); 
sigaction(SIGTRAP, &act, NULL); 

erreur Ajouter manipulation nécessaire

Étape 4: Définir la fonction de gestionnaire:

void handler(int signal, siginfo_t* siginfo, void* uap) { 
    printf("Attempt to access memory at address %p\n", 
      siginfo->si_addr); 
    #ifdef LINUX_64BIT 
    printf("Instruction pointer: %p\n", 
      (((ucontext_t*)uap)->uc_mcontext.gregs[16])); 
    #elif LINUX_32BIT 
    printf("Instruction pointer: %p\n", 
      (((ucontext_t*)uap)->uc_mcontext.gregs[14])); 
    #endif 
} 

Vous pouvez consulter les pages de manuel pour ucontext_t et siginfo_t pour les données les plus intéressantes de votre de gestionnaire peut extraire.