Un canary è un valore nello stack il cui valore viene verificato prima del ritorno.
void funzione(...) {
int canary;
char buf[MAX_SIZE]; // seguono altre dichiarazioni
canary = VALORE_CANARY;
gets(buf); // o qualche altra operazione pericolosa
...
if(canary != VALORE_CANARY)
exit;
return;
}
Ruolo del canary: Il canary funge da segnaposto. Prima del ritorno dalla funzione, viene verificato se il valore del canary è rimasto invariato. Se il canary è stato alterato, può indicare un overflow di buffer. In tal caso, il programma può decidere di terminare l'esecuzione (exit).
Un canary è un valore casuale (difficile da indovinare per l'attaccante) o un valore composto da diversi terminatori di stringa (CR, LF, Null, -1). L'obiettivo è rendere difficile per un attaccante indovinare il valore del canary durante un attacco.
Implementazioni per i compilatori GCC e Microsoft Visual C++ Esistono attacchi noti (vedi Pincus/Baker)
strcpy(dst, src) con strncpy(dst, src, dimensione_dst-1).BUG
Non utilizzare mai gets(). Poiché è impossibile stabilire senza conoscere i dati in anticipo quanti caratteri gets() leggerà e poiché gets() continuerà a memorizzare caratteri oltre la fine del buffer, è estremamente pericoloso usarlo. È stato utilizzato per violare la sicurezza informatica. Utilizzare invece fgets().
— Dalla pagina del manuale di gets(3)
Approccio: il compilatore aggiunge automaticamente un controllo esplicito ad ogni accesso a un array
I controlli vengono inseriti durante la generazione del codice. Esempio: miglioramenti di GCC di Jones&Kelly.
Svantaggi