Una parola canaria è una sequenza di bit posizionata al confine tra un buffer (come una pila) e controllare i dati in un programma, come un modo per rilevare e reagire ai buffer overflow.
Quanti bit lunghi sono questi canarini su Linux, di solito?
Una parola canaria è una sequenza di bit posizionata al confine tra un buffer (come una pila) e controllare i dati in un programma, come un modo per rilevare e reagire ai buffer overflow.
Quanti bit lunghi sono questi canarini su Linux, di solito?
Proviamo! Ecco un programma di esempio molto semplice.
int test(int a)
{
return a;
}
Compilarlo con GCC e intercettare la compilazione in fase di assemblaggio. (Il flag -S
lo farà). Rinominare il file assembly (quindi non verrà sovrascritto) e ricompilare nuovamente, questa volta aggiungendo anche -fstack-protector-all
e -mstack-protector-guard=global
flags. Il primo flag abilita i canarini dello stack per tutte le funzioni, il secondo seleziona un canarino globale invece di uno locale thread-locale. (L'impostazione predefinita locale del thread è probabilmente più utile in pratica, ma l'assembly per la versione globale è più facile da capire.)
Confrontando i due file assembly generati, individuiamo la seguente aggiunta (i commenti sono miei).
movl %edi, -20(%rbp) ; save function parameter onto stack (unrelated to canary)
movq __stack_chk_guard(%rip), %rax ; load magic value into RAX register
movq %rax, -8(%rbp) ; save RAX register onto stack (place the canary)
movl -20(%rbp), %eax ; load function parameter into EAX register for return (unrelated to canary)
movq -8(%rbp), %rcx ; load canary value into RCX register
movq __stack_chk_guard(%rip), %rdx ; load magic value into RDX register
cmpq %rdx, %rcx ; compare canary value to expected value
je .L3 ; if they are the same, jump to label .L3 (continue)
call __stack_chk_fail ; otherwise (stack corruption detected), call the handler
.L3:
leave
Possiamo vedere che il canarino è gestito nei registri RAX, RCX e RDX che sono tutti a 64 bit di larghezza. (Le loro controparti a 32 bit sarebbero denominate EAX, EBX ed EDX Le versioni a 16 bit sono denominate AX, BX e CX. Le varianti a 8 bit AL, BL e CL.) Un altro indizio è che le operazioni per archiviare, caricare e confrontare canarino (MOVQ e CMPQ) hanno un suffisso 'Q' che identifica un'istruzione a 64 bit. (Le istruzioni a 32 bit hanno un suffisso "L", istruzioni a 16 bit a "W" e versioni a 8 bit a "B".)
Quindi, concludiamo che il canarino è un valore a 64 bit, il che ha senso su un'architettura a 64 bit (x86_64 GNU / Linux nel mio caso). Mi aspetto che usino sempre la dimensione della parola nativa come ha più senso per me. Puoi provare lo stesso esperimento sulle tue macchine e vedere cosa otterrai.
Come posso leggere in questa pagina: Stack Smashing Protector
The stack canary is native word sized and if chosen randomly, an attacker will have to guess the right value among 2^32 or 2^64 combinations
Il numero di bit utilizzati deve essere uguale alla dimensione di Word del processore. Quindi se hai un processore a 32 bit, la sua dimensione in Word è 32, quindi la parola canary è lunga 32 bit.
Leggi altre domande sui tag buffer-overflow stack-overflow