问题 海湾合作委员会是否会产生金丝雀?


我的gcc版本是4.8.2,操作系统是ubuntu 14.04(64位)。 我发现有时gcc自动生成金丝雀有时候不做缓冲区溢出保护,为什么?

生成金丝雀的情况:当SIZE是四的倍数时

#include<stdio.h>
#define SIZE 4

int main()
{
    char s[SIZE];
    scanf("%s", s);
    return 0;
}

asm在gcc -c -g -Wa,-a,-ad之后

...
   4:a.c           **** int main()
   5:a.c           **** {
  13                    .loc 1 5 0
  14                    .cfi_startproc
  15 0000 55            pushq   %rbp
  16                    .cfi_def_cfa_offset 16
  17                    .cfi_offset 6, -16
  18 0001 4889E5        movq    %rsp, %rbp
  19                    .cfi_def_cfa_register 6
  20 0004 4883EC10      subq    $16, %rsp
  21                    .loc 1 5 0
  22 0008 64488B04      movq    %fs:40, %rax
  22      25280000 
  22      00
  23 0011 488945F8      movq    %rax, -8(%rbp)
  24 0015 31C0          xorl    %eax, %eax
   6:a.c           ****     char s[SIZE];
   7:a.c           ****     scanf("%s", s);
...

不生成金丝雀的情况:不是四个的倍数

#include<stdio.h>
#define SIZE 2

int main()
{
    char s[SIZE];
    scanf("%s", s);
    return 0;
}

asm在gcc -c -g -Wa,-a,-ad之后

...
   4:a.c           **** int main()
   5:a.c           **** {
  13                    .loc 1 5 0
  14                    .cfi_startproc
  15 0000 55            pushq   %rbp
  16                    .cfi_def_cfa_offset 16
  17                    .cfi_offset 6, -16
  18 0001 4889E5        movq    %rsp, %rbp
  19                    .cfi_def_cfa_register 6
  20 0004 4883EC10      subq    $16, %rsp
   6:a.c           ****     char s[SIZE];
   7:a.c           ****     scanf("%s", s);
...

12922
2018-06-28 08:20


起源

您的操作系统是什么(名称和版本)?这很重要,因为不同的发行版包括不同的补丁和默认标志(看到)。例如,除非我指定,否则不会为我生成金丝雀 -fstack-protector。 - xaizek
我的操作系统是Ubuntu 14.04 64bit - zongyuwu
然后 -fstack-protector 很可能会被使用,但是man page表示为缓冲区大于8字节的所有函数生成了canary,编译器为这两个缓冲区分配了16个字节(在你的机器上和我的相同),所以两个版本都应该有它。我在同一版本的GCC上得到了不同的行为。您尝试过更大的数字,例如17和20? - xaizek
@xaizek:文档。说 缓冲区大于8不是 堆栈帧大于8。也许Ubuntu已将此限制修补为4? - rodrigo
@rodrigo,可能是。这就是为什么我对缓冲区大小更大的行为感兴趣。最好的方法是查看其他补丁列表,但我不知道它在哪里可以找到(似乎没有在launchpad.net上列出)。 - xaizek


答案:


好的,我想我们知道评论的答案,所以我会在这里发布它以明确说明。

将金丝雀放在许多功能中会导致性能下降。这就是为什么有几种方法告诉GCC我们想要使用它们,这些都很好地描述了 这里。主要观点:

  1. 默认情况下不使用Canaries,需要传递启用它们的标志之一。
  2. 为了节省执行时间,GCC使用简单的启发式方法 -fstack-protector flag:为使用的函数添加canaries alloca 或大于的本地缓冲区 8 bytes(默认情况下)。
  3. 启发式可以调整 ssp-buffer-size 参数: --param ssp-buffer-size=4

显然Ubuntu发布了缓冲区大小改为的GCC版本 4,所以缓冲不到那个不会触发金丝雀的生成。我通过编译两个例子来确认(以及其他任何人都应该能够重复) --param ssp-buffer-size=4,只为其中一个产生金丝雀组装。


10
2018-06-28 14:39