Search code examples
securitygccx86-64buffer-overflowcallstack

How do canary words allow gcc to detect buffer overflows?


I could test using strncpy() with larger source string then the destination:

int main() {
  char *ptr = malloc(12);
  strcpy(ptr,"hello world!");
  return 0;
}

Compiling with the flag -fstack-protector and using the -S option I got:

.file   "malloc.c"
.text
.globl  main
.type   main, @function
main:
.LFB2:
.cfi_startproc
pushq   %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq    %rsp, %rbp
.cfi_def_cfa_register 6
subq    $32, %rsp
movl    %edi, -20(%rbp)
movq    %rsi, -32(%rbp)
movq    %fs:40, %rax
movq    %rax, -8(%rbp)
xorl    %eax, %eax
movq    $0, -16(%rbp)
movl    $12, %edi
call    malloc
movq    %rax, -16(%rbp)
movq    -16(%rbp), %rax
movabsq $8022916924116329800, %rdx
movq    %rdx, (%rax)
movl    $560229490, 8(%rax)
movb    $0, 12(%rax)
movl    $0, %eax
movq    -8(%rbp), %rcx
xorq    %fs:40, %rcx
je  .L3
call    __stack_chk_fail
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size   main, .-main

Could someone explain to me how this works? And why isn't the "canary word" also overwritten by the \0 of the hello world! string?


Solution

  • Could someone explain to me how does this work ?

    Canary word is read from fs:40 and store at top of frame here:

    movq    %fs:40, %rax
    movq    %rax, -8(%rbp)
    

    It's below the return address so if your code happens to overflow the buffer (which will be below -8(%rbp)), it'll first overwrite the -8(%rbp) location. This will be detected by GCC prior to issuing ret here:

    movq    -8(%rbp), %rcx
    xorq    %fs:40, %rcx      ; Checks that %fs:40 == -8(%rbp)
    je  .L3                   ; Ok, return
    call    __stack_chk_fail  ; Die
    

    as overwritten contents of -8(%rbp) will likely to be different from proper value (installed from fs:40).

    And why is not the canary word also overwritten by the \0 of the hello world!?

    Your code has heap overflow, not buffer overflow so SSP can't help...