2010-08-09 34 views
5

Je me demande s'il existe un moyen d'écrire-protéger chaque page dans un espace d'adressage de processus de Linux (de l'intérieur du processus lui-même, par l'intermédiaire de mprotect()). Par "chaque page", je veux dire vraiment toutes les pages de l'espace adresse du processus qui pourrait être écrit par un programme ordinaire fonctionnant en mode utilisateur - donc, le texte du programme, les constantes, les globals, et le tas - - mais je serais heureux avec juste des constantes, globals, et tas. Je ne veux pas écrire-protéger la pile - que semble être une mauvaise idée.Puis-je protéger en écriture chaque page de l'espace d'adressage d'un processus Linux?

Un problème est que je ne sais pas par où commencer à protéger en écriture la mémoire . En regardant /proc/pid/maps, qui montre les sections de la mémoire en cours d'utilisation pour un pid donné, ils semblent toujours commencer par l'adresse 0x08048000, avec le texte du programme. (Dans Linux, pour autant que je peux dire, la mémoire d'un processus est présentée avec le texte du programme au fond , puis les constantes ci-dessus, puis globales, puis le tas, puis un espace vide de taille variable en fonction sur la taille de la pile tas ou , puis la pile qui descend du haut de la mémoire à adresse virtuelle 0xffffffff.) Il y a un moyen de dire où est le sommet de le tas (en appelant sbrk(0), qui renvoie simplement un pointeur vers le "pause" actuelle, à savoir, le sommet du tas), mais pas vraiment un moyen de dire où le tas commence.

Si j'essaie de protéger toutes les pages de 0x08048000 jusqu'à la coupure, I finit par obtenir une erreur mprotect: Cannot allocate memory. Je ne sais pas pourquoi mprotect serait allouer de la mémoire de toute façon - et Google n'est pas très utile. Des idées?

Par ailleurs, la raison pour laquelle je veux faire est parce que je veux créer une liste de toutes les pages qui sont écrites au cours d'une exécution du programme, et la manière que je peux penser à faire est d'écrire-protéger toutes les pages, laisser toute tentative d'écriture provoque une faute d'écriture, puis implémenter un gestionnaire d'erreur d'écriture qui va ajouter la page à la liste, puis supprimer la protection d'écriture . Je pense que je sais comment implémenter le gestionnaire, si seulement je pouvais déterminer quelles pages protéger et comment le faire.

Merci!

+1

En fait, j'ai déjà du code qui fait exactement ce que vous essayez de faire. Votre idée fonctionnera, mais vous ne pourrez pas protéger les pages sur lesquelles résideront vos listes "ces pages" ou votre SEGV provoquera un SEGV! – Borealid

+0

@Borealid, merci, et c'est maintenant le problème que j'essaie de résoudre (j'ai le gestionnaire de segfault et l'analyse de/proc/self/maps qui fonctionne maintenant). Comment éviter de protéger les pages qui contiennent cette liste? Allouer la liste sur la pile fonctionnerait, mais je ne vois aucun moyen de le passer au gestionnaire. Sinon, je pourrais l'allouer globalement, mais j'aimerais utiliser une structure de données plus sophistiquée qu'un tableau de taille fixe (comme un conteneur STL), et je ne saurais pas toujours où se trouve la liste à laquelle j'écris. en mémoire. –

+0

@borealid: Vous avez dit que vous avez du code qui fait exactement cela - cela vous dérangerait-il de partager votre code? Je suis nouveau ici, et je n'ai pas trouvé de moyen de vous contacter directement (back-channel). J'essaie de faire exactement ce que fait Linsey, donc tous les exemples de code seraient très utiles. –

Répondre

5

Vous recevez ENOMEM de mprotect() si vous essayez de l'appeler sur des pages qui ne sont pas mappées.

Votre meilleur pari est d'ouvrir /proc/self/maps, et lisez-le ligne par ligne avec fgets() pour trouver tous les mappings dans votre processus.Pour chaque mappage inscriptible (indiqué dans le deuxième champ) qui n'est pas la pile (indiqué dans le dernier champ), appelez mprotect() avec l'adresse de base et la longueur correctes (calculées à partir des adresses de début et de fin dans le premier champ). Notez que votre gestionnaire d'erreurs doit déjà être configuré à ce stade, car la lecture du fichier maps lui-même provoquera probablement des écritures dans votre espace d'adressage.

+0

Merci - J'espérais qu'il y aurait un moyen d'avoir à main-parse/proc/self/maps, mais il semble qu'il n'y en ait pas (de la discussion à http://stackoverflow.com/questions/269314/est-il-un-meilleur-moyen-que-parsing-proc-self-maps-to-figure-out-memory-protectio). –

0

Démarrage simple. Protégez en écriture quelques pages et assurez-vous que votre gestionnaire de signal fonctionne pour ces pages. Ensuite, s'inquiéter de l'élargissement de la portée de la protection. Par exemple, vous n'avez pas besoin probablement protéger en écriture le code section: les systèmes d'exploitation peuvent mettre en œuvre en écriture ou exécuter la sémantique de protection sur la mémoire qui empêchera les sections de code jamais d'être écrit à:

+0

Oui, pour ce problème, nous ne pouvons pas supposer de code auto-modifiable pour le moment. Je serais d'accord soit avec la protection de l'écriture de la section de code ou non, selon ce qui est le plus facile. –

+0

En fait, ce que j'essayais de dire, c'est que vos sections de code sont très probablement déjà protégées en écriture. –