简体   繁体   English

GCC 不启用 D_FORTIFY_SOURCE,即使设置了优化标志 (-O2)

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM