[英]GCC isn't enabling D_FORTIFY_SOURCE, even with optimisation flag set (-O2)
I've recently read about D_FORTIFY_SOURCE and the changes it makes to vulnerable functions.我最近阅读了有关 D_FORTIFY_SOURCE 以及它对易受攻击的函数所做的更改。 I wished to mess around with it, and as such made a small test binary.
我想弄乱它,因此制作了一个小的测试二进制文件。
The test binaries source code is:测试二进制文件源代码是:
#include <stdio.h>
#include <stdlib.h>
//No ASLR/PIE
//Enable FORTIFY
//
//
//
void shell()
{
system("sh");
}
int flag = 0;
int main(int argc, char * argv[])
{
char buf [256];
fgets(buf, sizeof(buf), stdin);
printf(buf);
if(flag)
{
shell();
}
}
It wasn't meant to do anything, just to try out the protections on printf.它并不打算做任何事情,只是为了尝试对 printf 的保护。
However, when I compiled the program, it didn't seem to be 'fortified'但是,当我编译程序时,它似乎没有“强化”
The exact gcc command was:确切的 gcc 命令是:
gcc fsFORTIFIED.c -o fsFORTIFIED -m32 -no-pie -D_FORITFY_SOURCE=2 -O2
I made sure that the optimisation flag was set, yet the standard printf function remained.我确保设置了优化标志,但标准的 printf 函数仍然存在。 GDB gave the assembly of main:
GDB给出了main的汇编:
0x080491c6 <+0>: lea ecx,[esp+0x4]
0x080491ca <+4>: and esp,0xfffffff0
0x080491cd <+7>: push DWORD PTR [ecx-0x4]
0x080491d0 <+10>: push ebp
0x080491d1 <+11>: mov ebp,esp
0x080491d3 <+13>: push esi
0x080491d4 <+14>: push ebx
0x080491d5 <+15>: push ecx
0x080491d6 <+16>: sub esp,0x120
0x080491dc <+22>: call 0x80490e0 <__x86.get_pc_thunk.bx>
0x080491e1 <+27>: add ebx,0x2e1f
0x080491e7 <+33>: mov eax,gs:0x14
0x080491ed <+39>: mov DWORD PTR [ebp-0x1c],eax
0x080491f0 <+42>: xor eax,eax
0x080491f2 <+44>: mov eax,DWORD PTR [ebx-0x8]
0x080491f8 <+50>: push DWORD PTR [eax]
0x080491fa <+52>: push 0x100
0x080491ff <+57>: lea esi,[ebp-0x11c]
0x08049205 <+63>: push esi
0x08049206 <+64>: call 0x8049050 <fgets@plt>
0x0804920b <+69>: mov DWORD PTR [esp],esi
0x0804920e <+72>: call 0x8049040 <printf@plt>
0x08049213 <+77>: add esp,0x10
0x08049216 <+80>: cmp DWORD PTR [ebx+0x2c],0x0
0x0804921d <+87>: jne 0x804923b <main+117>
0x0804921f <+89>: mov eax,DWORD PTR [ebp-0x1c]
0x08049222 <+92>: sub eax,DWORD PTR gs:0x14
0x08049229 <+99>: jne 0x8049242 <main+124>
0x0804922b <+101>: mov eax,0x0
0x08049230 <+106>: lea esp,[ebp-0xc]
0x08049233 <+109>: pop ecx
0x08049234 <+110>: pop ebx
0x08049235 <+111>: pop esi
0x08049236 <+112>: pop ebp
0x08049237 <+113>: lea esp,[ecx-0x4]
0x0804923a <+116>: ret
0x0804923b <+117>: call 0x80491a6 <shell>
0x08049240 <+122>: jmp 0x804921f <main+89>
0x08049242 <+124>: call 0x80492d0 <__stack_chk_fail_local>
Here, I expected a call to printf_chk@plt, but instead it had printf@plt.在这里,我希望调用 printf_chk@plt,但它却调用了 printf@plt。 To make sure, I ran the program, and gave it the input %3$x,and it ran fine instead of halting.
为了确保,我运行了程序,并给了它输入 %3$x,它运行良好而不是停止。
My question is, why isn't GCC properly implementing D_FORITFY_SOURCE, even after the optimisation flag is set?我的问题是,即使设置了优化标志,为什么 GCC 没有正确实现 D_FORITFY_SOURCE?
Help is appreciated帮助表示赞赏
Make sure -D_FORTIFY_SOURCE=2
is spelled correctly.确保
-D_FORTIFY_SOURCE=2
拼写正确。
(In this case, it wasn't: -D_FORITFY_SOURCE=2
was the problem.) (在这种情况下,不是:
-D_FORITFY_SOURCE=2
是问题所在。)
Unlike normal options, GCC can't catch typos in this for you.与普通选项不同,GCC 无法为您捕获其中的拼写错误。
-Dfoo=bar
simply defines a preprocessor macro ( GCC manual ), exactly the same as #D_FORTIFY_SOURCE 2
at the top of your file. -Dfoo=bar
只是定义了一个预处理器宏( GCC 手册),与文件顶部的#D_FORTIFY_SOURCE 2
完全相同。 ( -D
is a standard compiler option that all compilers accept, not just GCC.) Only a few special macro names affect headers like stdio.h. (
-D
是所有编译器都接受的标准编译器选项,而不仅仅是 GCC。)只有少数特殊的宏名称会影响像 stdio.h 这样的头文件。
For options like -fstack-protector-strong
, -march=skylake
or -fno-math-errno
or whatever, GCC does only accept valid options it recognizes .对于
-fstack-protector-strong
、 -march=skylake
或-fno-math-errno
选项,GCC 只接受它识别的有效选项。 But of course -Dfoo=bar
is valid for any foo, it just doesn't do anything because it's not the macro that glibc headers use in their #ifdef
s.但当然
-Dfoo=bar
对任何 foo 都有效,它只是不做任何事情,因为它不是 glibc 标头在其#ifdef
使用的宏。
The -D
is spelled correctly; -D
拼写正确; the rest of the option is just what's being defined.选项的其余部分就是正在定义的内容。
In ISO C, global-scope names that begin with an _
1 are reserved for use by the implementation, which is why defining _FORTIFY_SOURCE
is allowed to be special.在 ISO C 中,以
_
1开头的全局范围名称保留供实现使用,这就是为什么允许定义_FORTIFY_SOURCE
是特殊的。 But GCC itself doesn't reject names like that.但是 GCC 本身并不拒绝这样的名称。 For GCC to do that, it would have to know all the names that the internals of glibc, MUSL, and other parts of "the C implementation" happen to use, and that would make it a pain to work on those headers.
为了让 GCC 做到这一点,它必须知道 glibc、MUSL 和“C 实现”的其他部分的内部结构碰巧使用的所有名称,这将使处理这些头文件变得很痛苦。
Footnote 1: the reserved-names rules are somewhat less broad than that, I'm simplifying.脚注 1:保留名称规则比这更宽泛,我正在简化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.