Estou assumindo que há um histórico, mas por que a pilha cresce para baixo?
Parece-me que estouros de buffer seriam muito mais difíceis de explorar se a pilha crescesse para cima ...
Estou assumindo que há um histórico, mas por que a pilha cresce para baixo?
Parece-me que estouros de buffer seriam muito mais difíceis de explorar se a pilha crescesse para cima ...
Respostas:
Eu acredito que se trata desde os primórdios da computação, quando a memória era muito limitado, e não era sábio para pré-alocar um grande pedaço de memória para uso exclusivo pela pilha. Portanto, alocando a memória heap do endereço zero para cima e empilhe a memória do final da memória para baixo, é possível que o heap e a pilha compartilhem a mesma área de memória.
Se você precisasse de um pouco mais de pilha, poderia tomar cuidado com o uso da pilha; se você precisar de mais pilha, tente liberar um pouco de memória heap. O resultado foi, é claro, principalmente, falhas espetaculares, pois a pilha substituía ocasionalmente a pilha e vice-versa.
Naqueles dias, não havia interwebz, portanto não havia problema de exploração de saturação de buffer. (Ou pelo menos na medida em que existia a interwebz, era tudo dentro das instalações de alta segurança do departamento de defesa dos estados unidos, de modo que a possibilidade de dados mal-intencionados não precisou de muita atenção.)
Depois disso, na maioria das arquiteturas, era tudo uma questão de manter a compatibilidade com versões anteriores da mesma arquitetura. É por isso que as pilhas invertidas ainda estão conosco hoje.
a memória do programa é tradicionalmente configurada como
code
constants
heap (growing up)
...
stack (growing down)
pilha e pilha podem ser trocadas
mas os estouros de buffer ainda poderão ser explorados se a pilha for para o outro lado
tomando o clássico strcpy
como exemplo
foo(char* in){
char[100] buff;
strcpy(buff,in);
}
com pilha de memória como
ret foo
arg in
buff array
ret strcpy
buf pointer
in
isso significa que, quando a cópia é concluída, o endereço de retorno strcpy
é após o buffer (em vez do foo
endereço de retorno) e pode ser substituído pelo que estiverin
Alguns hardwares têm o heap começando na memória alta, diminuindo, enquanto a pilha começa na memória baixa crescendo.
O hardware PA-RISC da HP, entre outros, faz isso: http://www.embeddedrelated.com/usenet/embedded/show/68749-1.php
O venerável Sistema Operacional Multics rodava em hardware que tinha (possivelmente um de muitos) pilhas crescendo: veja http://www.acsac.org/2002/papers/classic-multics.pdf , final da seção 2.3.2:
Terceiro, as pilhas nos processadores Multics cresceram na direção positiva, e não na direção negativa. Isso significava que, se você realmente realizasse um estouro de buffer, substituiria quadros de pilha não utilizados, em vez de seu próprio ponteiro de retorno, tornando a exploração muito mais difícil.
Essa é uma afirmação bastante interessante. Os estouros de buffer se tornaram um problema tão grande apenas devido ao arranjo "habitual" de procedimento-chamada-pilha-quadro? Além disso, quanto da reputação de Multics como Totalmente Invulnerável era apenas um acaso de design de hardware?