【问题标题】:GCC isn't enabling D_FORTIFY_SOURCE, even with optimisation flag set (-O2)GCC 没有启用 D_FORTIFY_SOURCE,即使设置了优化标志 (-O2)
【发布时间】:2021-02-03 02:22:50
【问题描述】:

我最近阅读了 D_FORTIFY_SOURCE 以及它对易受攻击的函数所做的更改。我想弄乱它,因此制作了一个小的测试二进制文件。

测试二进制源代码为:

  #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();
          }
  }

它不是为了做任何事情,只是为了尝试对 printf 的保护。

但是,当我编译程序时,它似乎并没有被“强化”

确切的 gcc 命令是:

gcc fsFORTIFIED.c -o fsFORTIFIED -m32 -no-pie -D_FORITFY_SOURCE=2 -O2

我确保设置了优化标志,但标准的 printf 函数仍然存在。 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>

在这里,我希望调用 printf_chk@plt,但它却调用了 printf@plt。 为了确保这一点,我运行了程序,并给它输入了 %3$x,它运行良好而不是停止。

我的问题是,为什么 GCC 没有正确实现 D_FORITFY_SOURCE,即使设置了优化标志?

感谢您的帮助

【问题讨论】:

  • D_FORITFY_SOURCE --> D_FORTIFY_SOURCE
  • 先尝试gcc -v,但请阅读GCC的文档;也许也可以问gcc-help@gcc.gnu.orgmailing list
  • 您在未编辑代码的情况下编辑了问题中的命令。您是否复制/粘贴了两次,或者您实际运行的内容仍然存在拼写错误?
  • @PeterCordes 啊,我很抱歉。经过检查,原来的命令似乎确实有拼写错误(我以为只是在这篇文章中),这就是它无法通过检查编译的原因。我没有意识到 gcc 没有错误拼写标志的错误。问题解决了。感谢您的宝贵时间
  • -Dfoo=bar 只是定义了一个预处理器宏,与文件顶部的#D_FORTIFY_SOURCE 2 完全相同。只有少数特殊的宏名称会影响像 stdio.h 这样的头文件。对于-march=skylake 之类的选项,GCC 只接受它识别的有效选项。但当然-Dfoo=bar 对任何foo 都有效,它只是不做任何事情,因为它不是glibc 标头在其#ifdefs 中使用的宏。

标签: c assembly gcc glibc fortify-source


【解决方案1】:

确保-D_FORTIFY_SOURCE=2 拼写正确。
(在这种情况下,不是:-D_FORITFY_SOURCE=2 是问题所在。)

与普通选项不同,GCC 无法为您捕捉其中的拼写错误。

-Dfoo=bar 只是定义了一个预处理器宏(GCC manual),与文件顶部的#D_FORTIFY_SOURCE 2 完全相同。 (-D 是所有编译器都接受的标准编译器选项,而不仅仅是 GCC。)只有少数特殊的宏名称会影响像 stdio.h 这样的头文件。

对于-fstack-protector-strong-march=skylake-fno-math-errno 等选项,GCC 只接受valid options it recognizes。当然-Dfoo=bar 对任何 foo 都有效,它只是不做任何事情,因为它不是 glibc 标头在其#ifdefs 中使用的宏。

-D 拼写正确;选项的其余部分就是正在定义的内容。


在 ISO C 中,以 _1 开头的全局范围名称保留供实现使用,这就是为什么允许定义 _FORTIFY_SOURCE 是特殊的。但 GCC 本身并不拒绝这样的名称。要让 GCC 做到这一点,它必须知道 glibc、MUSL 和“C 实现”的其他部分碰巧使用的所有名称,这会使处理这些头文件变得很痛苦。

脚注 1:reserved-names 规则没有那么宽泛,我正在简化。

【讨论】:

  • 通常拼写错误的问题没有兴趣回答;我之所以回答是因为 OP 很惊讶 GCC 没有发现这个错字,这可能是其他未来读者可能做出的假设。
猜你喜欢
  • 2015-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多