Ich gehe davon aus, dass es eine Geschichte gibt, aber warum wächst der Stapel nach unten?
Es scheint mir, dass Pufferüberläufe viel schwerer auszunutzen wären, wenn der Stack nach oben wächst ...
Ich gehe davon aus, dass es eine Geschichte gibt, aber warum wächst der Stapel nach unten?
Es scheint mir, dass Pufferüberläufe viel schwerer auszunutzen wären, wenn der Stack nach oben wächst ...
Antworten:
Ich glaube, es stammt aus den Anfängen des Computerbetriebs, als der Arbeitsspeicher sehr begrenzt war, und es war nicht ratsam, einen großen Teil des Arbeitsspeichers für die ausschließliche Verwendung durch den Stapel vorab zuzuweisen. Wenn Sie also Heap-Speicher ab Adresse Null und Stapelspeicher ab Ende des Speichers zuweisen, können sich Heap und Stapel denselben Speicherbereich teilen.
Wenn Sie etwas mehr Heap benötigen, können Sie vorsichtig mit der Stapelverwendung umgehen. Wenn Sie mehr Stack benötigen, können Sie versuchen, etwas Heap-Speicher freizugeben. Das Ergebnis waren natürlich meist spektakuläre Abstürze, da der Stapel gelegentlich den Haufen überschrieb und umgekehrt.
Damals gab es kein Interwebz, daher gab es kein Problem mit Pufferüberlauf-Ausnutzungen. (Zumindest in dem Maße, in dem das Interwebz existierte, befand sich alles in Hochsicherheitseinrichtungen des Verteidigungsministeriums der Vereinigten Staaten, so dass die Möglichkeit böswilliger Daten nicht sonderlich berücksichtigt werden musste.)
Danach galt es bei den meisten Architekturen, die Kompatibilität mit früheren Versionen derselben Architektur aufrechtzuerhalten. Aus diesem Grund sind die Upside-Down-Stacks heute noch bei uns.
Der Programmspeicher ist traditionell eingerichtet als
code
constants
heap (growing up)
...
stack (growing down)
Haufen und Stapel können ausgetauscht werden
Pufferüberläufe können jedoch weiterhin ausgenutzt werden, wenn der Stapel in die andere Richtung geht
wobei die klassischen strcpy
als Beispiel
foo(char* in){
char[100] buff;
strcpy(buff,in);
}
mit Stapelspeicher als
ret foo
arg in
buff array
ret strcpy
buf pointer
in
Dies würde bedeuten, dass beim Kopieren die Rücksprungadresse für strcpy
nach dem Puffer steht (anstelle der foo
Rücksprungadresse) und von allem, was sich in diesem befindet, überschrieben werden kannin
Bei einigen Hardware-Systemen beginnt der Heap bei hohem Arbeitsspeicher und wächst nach unten, während der Stack bei niedrigem Arbeitsspeicher beginnt.
Dies geschieht unter anderem mit der PA-RISC-Hardware von HP: http://www.embeddedrelated.com/usenet/embedded/show/68749-1.php
Das ehrwürdige Multics-Betriebssystem lief auf Hardware, auf der (einer von möglicherweise mehreren) Stacks aufwuchs: siehe http://www.acsac.org/2002/papers/classic-multics.pdf , Ende von Abschnitt 2.3.2:
Drittens wuchsen die Stapel auf den Multics-Prozessoren eher in die positive als in die negative Richtung. Wenn Sie also tatsächlich einen Pufferüberlauf durchführen würden, würden Sie nicht verwendete Stapelrahmen und nicht Ihren eigenen Rückgabezeiger überschreiben, was die Ausnutzung erheblich erschwert.
Das ist eine ziemlich interessante Aussage. Wurden Pufferüberläufe nur aufgrund der "üblichen" Prozedur-Aufruf-Stapel-Rahmen-Anordnung zu einem so großen Problem? Wie viel von Multics Ruf als Totally Invulnerable war nur ein Zufall für das Hardware-Design?