canary words 如何允许 gcc 检测缓冲区溢出?

How do canary words allow gcc to detect buffer overflows?

我可以使用 strncpy() 进行测试,源字符串比目标字符串大:

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

使用标志 -fstack-protector 编译并使用 -S 选项我得到:

.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    , %rsp
movl    %edi, -20(%rbp)
movq    %rsi, -32(%rbp)
movq    %fs:40, %rax
movq    %rax, -8(%rbp)
xorl    %eax, %eax
movq    [=11=], -16(%rbp)
movl    , %edi
call    malloc
movq    %rax, -16(%rbp)
movq    -16(%rbp), %rax
movabsq 22916924116329800, %rdx
movq    %rdx, (%rax)
movl    0229490, 8(%rax)
movb    [=11=], 12(%rax)
movl    [=11=], %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

有人可以向我解释一下这是如何工作的吗?为什么 "canary word" 也没有被 hello world! 字符串的 [=15=] 覆盖?

Could someone explain to me how does this work ?

fs:40 读取 Canary 词并存储在此处的帧顶部:

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

它位于 return 地址之下,因此如果您的代码恰好溢出缓冲区(将 低于 -8(%rbp)),它将首先覆盖-8(%rbp) 位置。这将在此处发布 ret 之前由 GCC 检测到:

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

因为 -8(%rbp) 的覆盖内容可能与正确的值(从 fs:40 安装)不同。

And why is not the canary word also overwritten by the [=19=] of the hello world!?

您的代码存在堆溢出,而不是缓冲区溢出,因此 SSP 无能为力...