Ist es möglich, Speicher aus einem anderen Programm zu lesen, indem der gesamte leere Speicherplatz auf einem System zugewiesen wird?

26

Theoretisch wäre es möglich, kürzlich freigegebenen Speicher von anderen Anwendungen zu lesen, wenn ich ein Programm erstellen würde, das den gesamten ungenutzten Speicher eines Systems belegt und weiterhin immer mehr Speicher anfordert, wenn andere Anwendungen Speicher freigeben, den sie nicht mehr benötigen ? Oder ist das irgendwie durch ein modernes Betriebssystem geschützt?

Ich habe keine praktische Anwendung dafür, ich bin nur neugierig. Mir ist klar, dass es einige Probleme mit der Zuweisung des gesamten verfügbaren Speichers im wirklichen Leben gibt.

Bearbeiten: Um dies zu verdeutlichen, frage ich speziell nach "Freigegebenem" Speicher und greife nicht auf Speicher zu, der derzeit von einer anderen Anwendung zugewiesen wird.

ConditionRacer
quelle

Antworten:

23

Nein, da ein guter Kernel den Inhalt des Speichers löscht, bevor er an einen Prozess ausgegeben wird, um genau die Art von Angriff zu verhindern, die Sie vorschlagen.

Auf Unixy-Systemen wird den Prozessen Speicher zugewiesen, indem die so genannte Programmunterbrechung erweitert wird. Hierbei handelt es sich um die Grenze des virtuell adressierbaren Speicherplatzes, den ein Prozess verwenden kann. Ein Prozess teilt dem Kernel mit, dass er seinen adressierbaren Speicherplatz erweitern möchte, und der Kernel lässt dies zu, wenn Speicher verfügbar ist, oder der Aufruf schlägt fehl, wenn dies nicht der Fall ist. (Der Name des brk()Systemaufrufs stammt von diesem Konzept.)

In der Praxis stoßen große Blöcke des freigegebenen Speichers nicht oft an die Programmunterbrechung. Dies ist erforderlich, damit ein Prozess durch Verkleinern der Programmunterbrechung Speicher an den Kernel zurückgibt. Dies hängt natürlich alles von der Implementierung von malloc()und durch Ihr System ab free(). Wenn Sie Quellen zur Verfügung haben, werden Sie darüber informiert, ob jemals Speicher zurückgegeben wird oder nicht.

Es gibt keine Auswirkungen auf die Sicherheit , wenn der malloc()Speicher nicht initialisiert wird, da alles, was über brk()ihn eingegangen ist, gesäubert und alles, was zuvor free()geschrieben wurde, auf dieselbe Weise bearbeitet wurde.

Blrfl
quelle
19

Ja, es ist theoretisch möglich, den freigegebenen Speicher eines anderen Prozesses zu lesen. Es war die Quelle einer Reihe von Privilegien-Eskalationsangriffen damals. Aus diesem Grund setzen Betriebssysteme den Arbeitsspeicher heutzutage praktisch auf Null, wenn er zuvor von einem anderen Prozess zugewiesen wurde. Der Grund, warum Sie nicht immer sehen, dass der Speicher auf Null gesetzt ist, ist, dass es effizienter ist, den Speicher nicht auf Null zu setzen, wenn er zuvor durch denselben Prozess zugewiesen wurde. Das Betriebssystem versucht, Speicherseiten an denselben Prozess zurückzugeben, wenn dies möglich ist.

Karl Bielefeldt
quelle
1
"Ja aber nein" ist "nein". @Blrfl hat es richtig.
Ross Patterson
4
@ RossPatterson: In theoretischer Hinsicht hat Karl eigentlich mehr Recht als ich. Die praktische Realität ist, dass Mainstream-Betriebssysteme dieses Loch vor Jahren geschlossen haben.
Blrfl
@Blrfl Verstanden. Aber "vor Jahren" war in den späten 1960er Jahren, als Paging-Systeme und virtueller Speicher zum ersten Mal eingeführt wurden. Sicherlich zur Zeit von Multics, VM / 370 und OS / VS. Bei den meisten Programmierern war dies ohne Bugs nicht möglich.
Ross Patterson
The reason you don't always see zeroed out memory is because it is more efficient not to zero out the memory if it was previously allocated by the same process Ich sehe hier einige Inkonsistenzen. Meinten Sie "same executable"? Wie wird überprüft, ob keine Null erreicht werden soll - anhand des Plattenpfads?
Jakub.g
1
Ich glaube, ich vermisse etwas. Warum sind dann, wenn ich ein C ++ - Programm mit beispielsweise nicht initialisierten Ganzzahlen kompiliere und ausführe, diese nicht gleich 0, wenn ich diese Variablen lese?
Jakub.g
2

Hier sind mehrere Ebenen beteiligt, die sich auf die Antwort auswirken.

Wenn Sie von einem modernen Betriebssystem für virtuellen Speicher ausgehen, können Sie die Überreste anderer Prozessdaten auf den von Ihnen zugewiesenen Seiten nicht sehen.

Wenn ein Prozess zum ersten Mal geladen wird, wird die Seitentabelle geladen, und diesen Seiten werden möglicherweise Frames des realen Speichers zugewiesen. Die Seitentabelle oder ihre Ergänzungstabelle enthält mindestens eine Karte des gesamten Speichers, den der Prozess zuordnen kann. Hier wird auch die oben erwähnte anfängliche Prozessunterbrechung festgelegt.

Während malloc (), wenn der Prozess zulässig ist, eine Änderung des Prozessabbruchs verursachen kann und einer Tabelle mit Prozessseiten (ergänzenden Seiten) weitere Seiten hinzufügt, um die Anforderung zu erfüllen, befindet sich der Ort, an dem ein Prozess möglicherweise andere Prozessdaten abruft die untere reale Speicherschicht.

In beiden Szenarien weist ein modernes Betriebssystem, das Demand Paging oder Lazy Allocation verwendet, noch keinen physischen Speicher (Frames) zu. Das Betriebssystem "macht nur Notizen" darüber, welcher virtuelle Speicher für diesen Prozess als gültig angesehen wird. Der tatsächliche Speicher wird nur bei Bedarf zugewiesen.

Physischer Speicher oder Frames werden einem Prozess zugewiesen, wenn die virtuelle Seite realisiert und in eine Prozessseitentabelle abgebildet wird. Hier besteht das Potenzial für die Offenlegung von Daten. Dies geschieht während eines Seitenfehlers. Dies liegt daran, dass ein vorheriger Prozess möglicherweise denselben Frame verwendet hat und seine Daten entweder aufgegeben oder ausgetauscht wurden, um Platz für die aktuelle physische Speicheranforderung zu schaffen. Das Betriebssystem muss darauf achten, dass die anfragenden Prozessdaten ordnungsgemäß ausgetauscht werden oder der Frame gelöscht (auf Null gesetzt) ​​wird, bevor der Prozess fortgesetzt wird. Dies wird auch oben als ein "altes, aber gelöstes" Problem erwähnt.

Dies macht es etwas irrelevant, ob der Speicher der anderen Prozesse "freigegeben" wurde oder nicht. Der "freigegebene" Speicher eines anderen Prozesses befindet sich immer noch auf Seiten, die diesem Prozess zugewiesen sind, und wird normalerweise erst nach Beendigung des Prozesses freigegeben, da sie nur ausgelagert werden, wenn der Speicher knapp wird oder wenn sie anderweitig entfernt werden. malloc () und free () verwalten den dem Prozess zugewiesenen virtuellen Speicher auf (Benutzer-) Ebene.

In Ihrer Frage fordert Ihr Prozess theoretisch immer mehr Speicher an und verdrängt alle anderen Prozesse aus dem Speicher. In der Realität gibt es Rahmenzuweisungsstrategien - global und lokal -, die sich ebenfalls auf die Antwort auswirken können. Es ist ebenso wahrscheinlich, dass der Prozess seine eigenen Seiten aus dem Speicher zwingt, bevor er das Betriebssystem und alle anderen Prozesse übersteuern kann. Dies geht jedoch über Ihre ursprüngliche Frage hinaus.

All dies ist in einem System wie MS-DOS umstritten. MS-DOS (und andere, einfachere Systeme) verwenden keinen virtuellen Speicher (für sich), und Sie könnten leicht andere "Prozess" -Daten anstoßen und anstoßen.

Einige gute Referenzen, die einfacher zu verstehen sind als der Linux-Quellcode, sind ein gutes Lehrbuch für Betriebssysteme, Betriebssystemkonzepte von Silberscatz, Gavin und Gange oder Betriebssystemdesign von Andrew Tanenbaum. Auch so etwas wie Nachos von Berkeley oder Pintos von Stanford sind kleine Betriebssysteme, die zum Lernen gebaut wurden und die gleichen Ideen enthalten.

0xACE
quelle
0

Ich habe das vor 16.04 Monaten auf Ubuntu ausprobiert. Genau wie 0xACE sagte, weist das moderne Betriebssystem eine virtuelle Seite mit Nullen zu, sobald Sie malloc () aufgerufen haben. Wenn Sie jedoch nichts in den zugewiesenen Puffer schreiben, wird dieser nicht in den physischen Speicher abgebildet (dh nach dem Copy-on-Write-Prinzip), sodass Sie immer Nullen aus einem "nicht initialisierten" Block lesen. Möglicherweise gibt es einige eingebettete Betriebssysteme, die mit der Option "CONFIG_MMAP_ALLOW_UNITIALIZED" für eine bessere Leistung kompiliert wurden. In diesem Fall könnten Sie das bekommen, wofür Sie es erwartet haben.

weir007
quelle
-1

Nein, dank der Magie des Paging kann kein anderes Programm die Erinnerung eines anderen lesen . Auf diese Weise kann die Gesamtspeicherbelegung den physischen RAM überschreiten, indem Teile davon auf die Festplatte ausgelagert werden.

Außerdem wird der maximale Speicher, den ein Prozess zuweisen kann, vom Betriebssystem willkürlich begrenzt (bis zu 4 Gigs für eine 32-Bit-Architektur). Danach gibt der nächste allocAufruf einen Fehler wegen unzureichendem Speicher zurück.

Ratschenfreak
quelle
Gibt es keine plattformspezifischen APIs, die dies umgehen können? Ich weiß es ehrlich gesagt nicht, aber ich wäre nicht überrascht (zum Beispiel erlaubt Linux, zu verhindern, dass das Betriebssystem eine Seite über aus dem physischen Speicher verschiebt mlock).
Wenn 4 GB RAM vorhanden sind und der Paging-Speicher auf 8 GB begrenzt ist, fordert die Anwendung dann 12 GB an (auf einem x64)?
Arseni Mourzenko
dann sollten die Systemaufrufe einen Fehler zurückgeben, wenn zu wenig freier Speicher verbleibt, oder der Computer einfach zum Stillstand kommt, wenn keine mehr vorhanden sind ...
Ratschenfreak
4
Er fragt nicht nach dem Lesen des Gedächtnisses eines anderen, sondern nach dessen FREIGEGEBENEM Gedächtnis. Dieser Abschnitt des RAM ist derzeit frei und ... ich glaube nicht ... dass Paging-Schemata den Speicher auf Null setzen, nachdem er freigegeben wurde. Das Programm würde also einen Speicherblock zuweisen und die nicht initialisierten Daten analysieren, die bereits vorhanden sind.
Philip
@philip richtig, ich frage speziell nach freigegebenem Speicher.
ConditionRacer