GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum stürzt dieser Code bei aktivierter Adress-Randomisierung ab?

sub rsp, <size> Stack-Platz zu reservieren, bevor Sie ihn berühren, wenn Sie mehr als 128 Bytes unter RSP verwenden.

Wenn es abstürzt, sehen Sie sich Ihre Prozessspeicherkarte an. Möglicherweise verwenden Sie Speicher so weit unterhalb von RSP, dass der Kernel das Stack-Mapping nicht erweitert und es sich daher nur um einen gewöhnlichen Zugriff auf eine nicht zugeordnete Seite handelt =Fehler durch ungültige Seite => Kernel liefert SIGSEGV.

(Die ABI definiert nur eine 128-Byte-rote Zone, aber in der Praxis ist das Einzige, was diesen Speicher beschädigen kann, ein Signal-Handler (den Sie nicht installiert haben) oder GDB, auf dem print some_func() ausgeführt wird Verwendung des Stacks Ihres Programms, um eine Funktion in Ihrem Programm aufzurufen.)

Normalerweise ist Linux ziemlich bereit, das Stack-Mapping zu erweitern, ohne dazwischenliegende Seiten zu berühren, aber anscheinend überprüft es den Wert von RSP. Normalerweise verschieben Sie RSP, anstatt nur Speicher weit unterhalb des Stapelzeigers zu verwenden (weil es keine Garantie dafür gibt, dass es sicher ist). Siehe Wie wird Stack-Speicher zugewiesen, wenn x86-Anweisungen „push“ oder „sub“ verwendet werden?

Ein weiteres Duplikat:Welche Ausnahme kann beim Subtrahieren von ESP- oder RSP-Register generiert werden? (Stapel wächst) bei Verwendung von sub rsp, 5555555 vor dem Berühren des neuen Stapelspeichers war ausreichend.

Stack ASLR startet RSP möglicherweise an verschiedenen Stellen relativ zu einer Seitengrenze , also kommst du vielleicht manchmal nur knapp damit durch. Linux ordnet anfangs 132 KB Stack-Speicherplatz zu , und das beinhaltet Platz für die Umgebung und Argumente auf dem Stapel beim Eintritt in _start . Ihre 128 KB sind dem sehr nahe, daher ist es absolut plausibel, dass es manchmal zufällig funktioniert.

Und übrigens, es gibt keinen Grund, Speicher tatsächlich in den Benutzerbereich zu kopieren, insbesondere nicht 1 Byte auf einmal. Geben Sie einfach dieselbe Adresse an write weiter .

Oder filtern Sie zumindest, wenn möglich, direkt vor Ort, damit Ihr Cache-Fußabdruck kleiner ist.

Außerdem ist die normale Art, ein Byte zu laden, movzx eax, byte [mem] . Verwenden Sie nur mov al, [mem] wenn Sie ausdrücklich zusammenführen möchten mit dem alten Wert von RAX. Auf einigen CPUs mov bis al hat eine falsche Abhängigkeit vom alten Wert, die Sie aufheben können, indem Sie das vollständige Register schreiben.

Und übrigens, wenn Ihr Programm immer diesen Speicherplatz verwendet, können Sie ihn genauso gut statisch im BSS zuweisen. Dies ermöglicht eine effizientere indizierte Adressierung, wenn Sie sich dafür entscheiden, eine positionsabhängige (nicht-PIE) ausführbare Datei zusammenzustellen.


Die rote Zone in AMD64 ist nur 128 Bytes lang, aber Sie verwenden 131072 Bytes unter rsp. Bewegen Sie den Stapelzeiger nach unten, um die Puffer einzuschließen, die Sie auf dem Stapel speichern möchten.


Linux
  1. Warum funktioniert Tomcat mit Port 8080, aber nicht mit 80?

  2. C++-Anwendung wird mit Exit-Code 143 beendet – was bedeutet das?

  3. Warum beginnt diese Verzögerungsschleife nach mehreren Iterationen ohne Schlaf schneller zu laufen?

  4. Warum benötigt Clang immer noch libgcc.a, um meinen Code zu kompilieren?

  5. Warum wird mein $LD_LIBRARY_PATH zurückgesetzt, wenn ich screen mit bash verwende?

Warum bricht das Hinzufügen eines Doppelpunkts dieses Grep-Muster?

Warum verhält sich Ping -f so?

Warum stürzt dieser Code bei aktivierter Adress-Randomisierung ab?

Warum funktioniert diese Regex nicht unter Linux?

Warum kann ich mein System nicht mit einer Gabelbombe zum Absturz bringen?

Warum erscheint mein Hostname mit der Adresse 127.0.1.1 statt 127.0.0.1 in /etc/hosts?