Un mot canari est une séquence de bits placés à la frontière entre un tampon (comme une pile) et des données de contrôle dans un programme, comme un moyen de détecter et de réagir aux débordements de tampon.
Combien de bits sont généralement ces canaris sous Linux?
Essayons! Voici un exemple de programme très simple.
int test(int a)
{
return a;
}
Compilez-le avec GCC et interceptez la compilation au stade de l'assemblage. (Le -S
flag le fera.) Renommez le fichier Assembly (pour qu'il ne soit pas écrasé) et compilez à nouveau, cette fois en ajoutant également -fstack-protector-all
et -mstack-protector-guard=global
drapeaux. Le premier drapeau active les canaris de pile pour toutes les fonctions, le second sélectionne un canari global au lieu d'un filaire local. (La valeur par défaut du thread local est probablement plus utile dans la pratique, mais l'assembly de la version globale est plus facile à comprendre.)
En comparant les deux fichiers d'assemblage générés, nous repérons l'ajout suivant (les commentaires sont les miens).
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
Nous pouvons voir que le canari est géré dans les registres RAX, RCX et RDX qui ont tous une largeur de 64 bits. (Leurs homologues 32 bits seraient nommés EAX, EBX et EDX. Les versions 16 bits sont nommées AX, BX et CX. Les variantes 8 bits AL, BL et CL.) Un autre indice est que les opérations pour stocker, charger et comparer les canary (MOVQ et CMPQ) ont un suffixe "Q" qui identifie une instruction 64 bits. (Les instructions 32 bits ont un suffixe "L", les instructions 16 bits un "W" et les versions 8 bits un "B".)
Par conséquent, nous concluons que le canari est une valeur 64 bits, ce qui est logique sur une architecture 64 bits (x86_64 GNU/Linux dans mon cas). Je m'attends à ce qu'ils utilisent toujours la taille native de Word car cela a le plus de sens pour moi. Vous pouvez essayer la même expérience sur vos machines et voir ce que vous obtiendrez.
Comme je peux le lire sur cette page: Stack Smashing Protector
Le canari de pile est de taille Word native et s'il est choisi au hasard, un attaquant devra deviner la bonne valeur parmi 2 ^ 32 ou 2 ^ 64 combinaisons
Le nombre de bits utilisés doit être égal à la taille Word du processeur. Donc, si vous avez un processeur 32 bits, sa taille de mot est de 32, donc le mot canari est de 32 bits.