È compito del software (sistema operativo) rilevare overflow dello stack o viene rilevato un overflow dello stack nell'hardware, causando un'eccezione nella CPU?
È compito del software (sistema operativo) rilevare overflow dello stack o viene rilevato un overflow dello stack nell'hardware, causando un'eccezione nella CPU?
Risposte:
Può essere software, hardware o entrambi o nessuno.
Esistono due tipi di overflow: overflow quando si cresce lo stack (quando si immette una funzione) e overflow quando si accede a un array nello stack. Gli overflow durante la crescita dello stack possono essere rilevati effettuando un controllo dei limiti sull'ingresso della funzione, per verificare che vi sia spazio sufficiente (e segnalare un errore o aumentare lo stack se non lo è). Gli overflow quando si accede a un array nello stack sono solo un problema in linguaggi di basso livello che non verificano i limiti dell'array; la soluzione è quella di verificare i limiti dell'array.
Questi approcci software hanno il vantaggio di funzionare in modo completamente affidabile: si può essere certi che verrà rilevato qualsiasi overflow dello stack. Il loro aspetto negativo è che aumentano la dimensione del codice e il tempo di esecuzione. L'hardware può aiutare fornendo un metodo per rilevare la maggior parte degli overflow senza alcun costo, purché non si verifichino overflow. Su un'architettura con una MMU ¹, l'ambiente di runtime può disporre di mappare lo stack su un limite di pagina, con la pagina successiva non mappata.
+---------------+---------------+---------------+---------------+
| stack | unmapped | other stuff |
| ----> direction of growth | | |
+---------------+---------------+---------------+---------------+
^ ^ ^ ^ ^ page boundaries
In questo modo, se il software tenta di accedere ai dati oltre il limite della pagina (sia perché il puntatore dello stack si è spostato oltre il limite o perché l'accesso dell'array è fuori dai limiti e oltre il limite), causerà un errore accedendo ad un'area non mappata . Questo succede solo se l'overflow è abbastanza piccolo: se la quantità di overflow è troppo grande, il programma potrebbe finire per accedere ad altre cose dall'altra parte del gap nello spazio degli indirizzi.
Gli aspetti negativi dell'approccio hardware sono che non è completamente affidabile poiché un overflow di una grande quantità potrebbe non essere rilevato e che non rileva overflow dell'array che rimangono all'interno dello spazio indirizzabile.
Per rilevare overflow di array, un'altra tecnica software è un canarino : inserire un valore speciale nella parte superiore dello stack o tra i frame e verificare che il valore canary non sia cambiato al ritorno della funzione. Questa è anche una tecnica imperfetta poiché l'overflow potrebbe evitare del tutto il canarino o potrebbe non essere rilevato perché il valore del canarino è stato ripristinato al momento della verifica. Tuttavia, è utile rendere più difficile lo sfruttamento di alcune vulnerabilità di sicurezza.
Il modo più sicuro ed economico per evitare overflow dello stack è calcolare la quantità di stack di cui il programma avrà bisogno prima di iniziare a eseguirlo, mediante analisi statica. Tuttavia, ciò non è sempre pratico: la quantità di stack necessaria a un programma è in generale non determinabile e dipende dai dati manipolati dal programma.
¹ Lo stesso principio può essere applicato anche con una sola MPU o senza protezione della memoria se esiste un singolo thread il cui stack si trova ai margini delle mappature fisiche esistenti.