gcc金丝雀:未定义对_堆栈_chk_守卫的引用

gcc金丝雀:未定义对_堆栈_chk_守卫的引用,c,gcc,compilation,C,Gcc,Compilation,我试图启用gcc的Canaris生成,但是我得到了一个未定义的对uu stack_chk_guard的引用 来自gcc的《关于金丝雀的人》: -mstack-protector-guard=guard Generate stack protection code using canary at guard. Supported locations are global for global canary or tls for per-thread canary in

我试图启用gcc的Canaris生成,但是我得到了一个未定义的对uu stack_chk_guard的引用

来自gcc的《关于金丝雀的人》:

-mstack-protector-guard=guard
       Generate stack protection code using canary at guard.  Supported locations are global for
       global canary or tls for per-thread canary in the TLS block (the default).  This option
       has effect only when -fstack-protector or -fstack-protector-all is specified.

   These -m switches are supported in addition to the above on x86-64 processors in 64-bit
   environments.
我已经完成了这个测试程序:

#define VALUE 2048
int    main()
{
  char arr[VALUE];
  int  i;

  for (i = 0; i < VALUE + 15; i++) // "i < VALUE + 15" is to test if canaries works but the code doesn't compile anymore with "i < 10" 
    arr[i] = '0';
  return 0;
}
但我得到了以下错误:

/tmp/ccXxxxVd.o: In function `main':
main.c:(.text+0xe): undefined reference to `__stack_chk_guard'
main.c:(.text+0x51): undefined reference to `__stack_chk_guard'
collect2: error: ld returned 1 exit status
如何删除此错误

编辑:

  • 操作系统:Ubuntu14.10Utopic
  • 架构:x86-64
  • 环境:64位

看起来
-mstack protector-guard
选项仅用于向后兼容堆栈保护器过去的工作方式。过去金丝雀是一个全球变量。后来它被切换到TLS。您使用的操作系统/libc似乎已删除或从未支持全局变量canary,因此只有TLS起作用


不要触摸
-mstack protector-guard
选项,一切正常。当您使用
-fstack protector all

时,默认值应该可以。有两种方法可以删除此错误:1。从编译器选项禁用(注释掉)“堆栈保护”

  • 在c文件中定义uu堆栈u chk_u保护 定义uuu stack_chk_guard时,请确保为其提供随机值。要提供随机值,需要将其作为参数传递给随机函数


    有关更多详细信息,请参阅编译器手册。

    对于使用自定义链接器脚本在裸机软件开发中出现此错误的用户,请确保传递选项
    -nostlib
    选项:

    gcc -nostdlib
    
    例如,由于Ubuntu 16.04在编译器上默认启用堆栈保护<代码>曼恩gcc说:

    NOTE: In Ubuntu 14.10 and later versions, -fstack-protector-strong is enabled by default for C, C++, ObjC, ObjC++, if none of -fno-stack-protector, -nostdlib, nor -ffreestanding are found.
    
    -fno stack protector
    也为我解决了这个问题,但是你应该告诉你可怜的编译器,你正在做一些纯金属的事情来防止其他类似的问题

    我猜这是因为该特性依赖于符号,而这些符号通常是在没有给出链接器脚本的情况下定义的?但是TODO我在转储默认链接器脚本时没有发现这些符号:

    aarch64-linux-gnu-gcc -Wl,-verbose main.c
    
    所以我不确定

    我浏览了GCC6.4.0源代码,它表明符号来自
    libgcc2.c
    at
    GCC/doc/tm.texi

    这个钩子的默认版本创建了一个名为 @samp{{uuuuu stack\u chk_guard},通常在@file{libgcc2.c}中定义


    在c文件中为
    \uuuuu stack\uchk\uguard
    提供一个随机值,避免使用常规值,如所有零或FF,因为堆栈在任何内存操作期间都可以轻松获取这些值。关于提供幻数实现。此
    \uuuuuuu堆栈\uchk\u防护装置将放置在堆栈的顶部和底部,在每次访问堆栈时都将对其进行检查。值中的任何更改都意味着堆栈已损坏,并返回提供堆栈保护的错误

    unsigned long __stack_chk_guard;
    void __stack_chk_guard_setup(void)
    {
         __stack_chk_guard = 0xBAAAAAAD;//provide some magic numbers
    }
    
    void __stack_chk_fail(void)                         
    {
     /* Error message */                                 
    }// will be called when guard variable is corrupted 
    

    我接受你的回答,即使我发现ubuntu没有这个功能这一事实很奇怪functionality@JérémyPouyet我怀疑他们不认为添加此功能有任何意义,因为将金丝雀保留在TLS中而不是全局变量在任何可能的方面都是优越的;这很容易被缓冲区溢出所克服。(特别是在32位构建中,
    long
    是32位的,因此没有一个字节是
    00
    ,因此整个32位常量可以只是strcpy缓冲区溢出漏洞字符串的一部分。其他类型的缓冲区溢出有其他需要避免的字节。)您希望每次运行时都将其初始化为不同的随机值,因此攻击者即使具有相同的二进制版本,也不会提前知道它是什么。绝对不是一个可识别的魔法数字!这就是为什么会有一个setup函数,而不仅仅是提供一个静态初始值设定项,比如
    long foo=0x1234。我认为,
    \uuuuu stack\uchk\uguard\u setup
    在主运行之前会被init函数调用,所以在任何函数将其用作堆栈cookie之前,您不需要使用静态初始值设定项对其进行初始化。(如果您在函数使用它之后更改了它,返回时它将检测到堆栈崩溃的假阳性。)
    unsigned long __stack_chk_guard;
    void __stack_chk_guard_setup(void)
    {
         __stack_chk_guard = 0xBAAAAAAD;//provide some magic numbers
    }
    
    void __stack_chk_fail(void)                         
    {
     /* Error message */                                 
    }// will be called when guard variable is corrupted