2010-08-09 10 views
5

Ich frage mich, ob es eine Möglichkeit gibt, jede Seite in einem Linux Prozess-Adressraum schreibgeschützt (von innerhalb des Prozesses selbst, über mprotect()). Mit "jede Seite" meine ich wirklich jede Seite des Adressraums des Prozesses , in die ein normales Programm im Benutzermodus geschrieben werden könnte - also der Programmtext, die Konstanten, die Globals und der Heap - - Aber ich wäre glücklich mit nur Konstanten, Globals und Heap. Ich möchte den Stack nicht schreibschützen - dass eine schlechte Idee zu sein scheint.Kann ich jede Seite im Adressraum eines Linux-Prozesses schreibgeschützt haben?

Ein Problem ist, dass ich nicht weiß, wo ich Schreibschutz Speicher starten soll. Mit Blick auf /proc/pid/maps, die die Abschnitte des Speichers im Einsatz für eine gegebene PID zeigt, scheinen sie immer mit der Adresse 0x08048000, mit dem Programmtext zu beginnen. (In Linux, soweit ich das beurteilen kann, ist der Speicher eines Prozesses mit dem Programmtext bei Boden ausgelegt, dann Konstanten darüber, dann Globals, dann der Haufen, dann ein leerer Raum unterschiedlicher Größe abhängig auf der Größe des Heap oder Stapel, und dann der Stapel wächst von der Spitze des Speichers um virtuelle Adresse 0xffffffff.) Es gibt eine Möglichkeit, zu sagen, wo die Spitze von der Haufen ist (durch Aufruf sbrk(0), die einfach eine zurückgibt Zeiger auf die aktuelle "Pause", dh, die Spitze des Heaps), aber nicht wirklich einen Weg zu sagen, wo der Haufen beginnt. Wenn ich versuche, alle Seiten von 0x08048000 bis zum Bruch zu schützen, bekomme ich schließlich einen mprotect: Cannot allocate memory Fehler. Ich weiß nicht, warum mprotect wäre Zuteilung Speicher sowieso - und Google ist nicht sehr hilfreich. Irgendwelche Ideen?

By the way, der Grund, warum ich dies tun möchte, ist, weil ich eine Liste aller Seiten erstellen möchten, die während eines Laufs des Programms geschrieben werden, und die Art und Weise, die ich mir vorstellen kann, dies zu tun Schützen aller Seiten, Schreibgeschützte Schreibvorgänge verursachen einen Schreibfehler, dann implementieren Sie einen Schreibfehlerhandler , der die Seite der Liste hinzufügt und dann den Schreibschutz entfernt. Ich denke, ich weiß, wie man den Handler implementiert, wenn ich nur herausfinden könnte, welche Seiten zu schützen und wie es geht.

Danke!

+1

Ich habe tatsächlich bereits Code, der genau das tut, was Sie versuchen zu tun. Ihre Idee funktioniert, aber Sie können nicht die Seiten schützen, auf denen Ihre "diese-Seiten-geschriebenen" Listen liegen, oder Ihr SEGV-Handler wird ein SEGV verursachen! – Borealid

+0

@Borealid, danke, und das ist jetzt das Problem, das ich zu lösen versuche (ich habe den segfault Handler und das/proc/self/maps Parsing funktioniert jetzt). Wie vermeide ich es, die Seite (n) zu schützen, die diese Liste enthalten? Das Zuweisen der Liste auf dem Stapel würde funktionieren, aber ich sehe keine Möglichkeit, es an den Handler weiterzugeben. Alternativ könnte ich es als global zuweisen, aber ich würde gerne eine schickere Datenstruktur als ein Array fester Länge (wie ein STL-Container) verwenden, und ich könnte nicht immer wissen, wo die Liste, die ich schreibe, ist in Erinnerung. –

+0

@borealid: Du hast gesagt, dass du Code hast, der genau das tut - würdest du deinen Code teilen? Ich bin neu hier und ich konnte keinen Weg finden, dich direkt zu kontaktieren (Back-Channel). Ich versuche genau das zu tun, was Linsey macht, daher wären Codebeispiele sehr hilfreich. –

Antwort

5

Sie erhalten ENOMEM von mprotect(), wenn Sie versuchen, es auf Seiten aufzurufen, die nicht zugeordnet sind.

Ihre beste Wette ist es, /proc/self/maps zu öffnen, und lesen Sie es Zeile für Zeile mit fgets(), um alle Zuordnungen in Ihrem Prozess zu finden.Für jedes beschreibbare Mapping (im zweiten Feld angegeben), das nicht der Stack ist (im letzten Feld angegeben), rufen Sie mprotect() mit der richtigen Basisadresse und Länge auf (berechnet aus den Start- und Endadressen im ersten Feld).

Beachten Sie, dass Ihr Fehlerbehandlungsprogramm bereits zu diesem Zeitpunkt eingerichtet sein muss, da das Lesen der Datei maps wahrscheinlich Schreibvorgänge in Ihrem Adressbereich verursacht.

+0

Danke - Ich hatte gehofft, dass es ein bisschen herumkommen würde, um/proc/self/maps zu analysieren, aber es scheint, dass es nicht (aus der Diskussion bei http://stackoverflow.com/questions/269314)/is-there-a-better-way-als-parsing-proc-self-maps-um-out-memory-protectio). –

0

Starten Sie einfach. Schreib ein paar Seiten schreibgeschützt und vergewissere dich, dass dein Signalhandler für diese Seiten funktioniert. Dann machen Sie sich Sorgen darüber, den Umfang des Schutzes zu erweitern. Zum Beispiel brauchen Sie wahrscheinlich nicht den Code-Abschnitt zu einem Schreibschutz: Betriebssysteme implementieren Schutz Semantik auf Speicherschreib-oder-ausführen, die Codeabschnitte von je geschrieben werden verhindert:

+0

Ja, für dieses Problem können wir vorerst keinen selbstmodifizierenden Code annehmen. Ich wäre in Ordnung mit entweder Schreib-Schutz der Code-Abschnitt oder nicht, was immer einfacher ist. –

+0

Eigentlich wollte ich sagen, dass Ihre Code-Abschnitte höchstwahrscheinlich bereits schreibgeschützt sind. –