gcc金丝雀:未定义对_堆栈_chk_守卫的引用
我试图启用gcc的Canaris生成,但是我得到了一个未定义的对uu stack_chk_guard的引用 来自gcc的《关于金丝雀的人》: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
-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。从编译器选项禁用(注释掉)“堆栈保护”
有关更多详细信息,请参阅编译器手册。对于使用自定义链接器脚本在裸机软件开发中出现此错误的用户,请确保传递选项
-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
atGCC/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