zoukankan      html  css  js  c++  java
  • stack-protector-strong

    Improve protection against stack buffer overflows

    Much like its predecessor, stack-protector, stack-protector-strong protects against stack buffer overflows, but additionally provides coverage for more array types, as the original only protected character arrays. Stack-protector-strong was implemented by Han Shen and added to the gcc 4.9 compiler.

    Android 7.0 的内核安全更新中,引入了 stack-protector-strong

    更早的是 -fstack-protector 与 -fstack-protector-all选项,但它们各自都有缺点,Chrome OS 的编译器团队目测有强迫症,设计了 stack-protector-strong

    -fstack-protector 的缺点

    仅对使用>=8字节(–param=ssp-buffer-size=N, 默认N=8)的char数组的函数提供保护,因此其保护能力有限。

    -fstack-protector-all 的缺点

    所有函数都会加入检测,1)会增加程序体积,2)占用栈空间,尤其内核栈空间固定的情况;可以认为这都不是好的设计。

    -fstack-protector-strong

    再来看一下 stack-protector-strong 选项,它对是否在函数中加入canary有其筛选原则,总结起来有几条:

    1. 当本地变量的***地址***,作为赋值表达式右值 的一部分,或作为函数参数
    2. 当本地变量是数组(或包含数组的union 类型),不管数组大小与类型
    3. 使用 register 类型的本地变量(*)(uses register local variables)

    第3点未能验证,可能理解有误?

    通过汇编代码,对比一下:

    zzhiyuan@ubuntu:~/exploits/test$ cat register.c 
    #include <stdio.h>
    
    void c (long a)
    {
            printf ("%ld
    ", a);
    }
    /* local variable’s address used as part of function argument */
    int a () 
    {
            int a = 10;
            c((long)&a);
    }
    
    int b () 
    {
            register int *foo asm ("r12");
    }
    
    /* regardless of array length */
    void d () 
    {
            char str[2] = {'A'};
    }
    
    /* regardless of array type */
    void e () 
    {
            int a[10];
            int i;
            for (i = 0; i < 10; i++)
                    a[i] = 'A';
    }
    
    /* local variable’s address used as part of the right hand side of an assignment */
    void f (int *b) 
    {
            int a = 10;
            b = &a;
    }
    
    int main ()
    {
    }
    

    stack-protector-strong选项编译结果如下:

    00000000004005ca <a>:    #本地变量地址作为函数参数
      4005ca:       55                      push   %rbp
      4005cb:       48 89 e5                mov    %rsp,%rbp
      4005ce:       48 83 ec 10             sub    $0x10,%rsp
      4005d2:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
      4005d9:       00 00 
      4005db:       48 89 45 f8             mov    %rax,-0x8(%rbp)
      4005df:       31 c0                   xor    %eax,%eax
      4005e1:       c7 45 f4 0a 00 00 00    movl   $0xa,-0xc(%rbp)
      4005e8:       48 8d 45 f4             lea    -0xc(%rbp),%rax
      4005ec:       48 89 c7                mov    %rax,%rdi
      4005ef:       e8 b2 ff ff ff          callq  4005a6 <c>
      4005f4:       48 8b 55 f8             mov    -0x8(%rbp),%rdx
      4005f8:       64 48 33 14 25 28 00    xor    %fs:0x28,%rdx
      4005ff:       00 00 
      400601:       74 05                   je     400608 <a+0x3e>
      400603:       e8 68 fe ff ff          callq  400470 <__stack_chk_fail@plt>
      400608:       c9                      leaveq 
      400609:       c3                      retq   
    
    000000000040060a <b>:    #使用register类型变量,Why未印证?
      40060a:       55                      push   %rbp
      40060b:       48 89 e5                mov    %rsp,%rbp
      40060e:       5d                      pop    %rbp
      40060f:       c3                      retq   
    
    0000000000400610 <d>:    #数组长度为2
      400610:       55                      push   %rbp
      400611:       48 89 e5                mov    %rsp,%rbp
      400614:       48 83 ec 10             sub    $0x10,%rsp
      400618:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
      40061f:       00 00 
      400621:       48 89 45 f8             mov    %rax,-0x8(%rbp)
      400625:       31 c0                   xor    %eax,%eax
      400627:       66 c7 45 f0 00 00       movw   $0x0,-0x10(%rbp)
      40062d:       c6 45 f0 41             movb   $0x41,-0x10(%rbp)
      400631:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      400635:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
      40063c:       00 00 
      40063e:       74 05                   je     400645 <d+0x35>
      400640:       e8 2b fe ff ff          callq  400470 <__stack_chk_fail@plt>
      400645:       c9                      leaveq 
      400646:       c3                      retq   
    
    0000000000400647 <e>:    #数组类型为int
      400647:       55                      push   %rbp
      400648:       48 89 e5                mov    %rsp,%rbp
      40064b:       48 83 ec 40             sub    $0x40,%rsp
      40064f:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
      400656:       00 00 
      400658:       48 89 45 f8             mov    %rax,-0x8(%rbp)
      40065c:       31 c0                   xor    %eax,%eax
      40065e:       c7 45 cc 00 00 00 00    movl   $0x0,-0x34(%rbp)
      400665:       eb 11                   jmp    400678 <e+0x31>
      400667:       8b 45 cc                mov    -0x34(%rbp),%eax
      40066a:       48 98                   cltq   
      40066c:       c7 44 85 d0 41 00 00    movl   $0x41,-0x30(%rbp,%rax,4)
      400673:       00 
      400674:       83 45 cc 01             addl   $0x1,-0x34(%rbp)
      400678:       83 7d cc 09             cmpl   $0x9,-0x34(%rbp)
      40067c:       7e e9                   jle    400667 <e+0x20>
      40067e:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      400682:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
      400689:       00 00 
      40068b:       74 05                   je     400692 <e+0x4b>
      40068d:       e8 de fd ff ff          callq  400470 <__stack_chk_fail@plt>
      400692:       c9                      leaveq 
      400693:       c3                      retq   
    
    0000000000400694 <f>:    #本地变量作为赋值表达式左值的一部分
      400694:       55                      push   %rbp
      400695:       48 89 e5                mov    %rsp,%rbp
      400698:       48 83 ec 20             sub    $0x20,%rsp
      40069c:       48 89 7d e8             mov    %rdi,-0x18(%rbp)
      4006a0:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
      4006a7:       00 00 
      4006a9:       48 89 45 f8             mov    %rax,-0x8(%rbp)
      4006ad:       31 c0                   xor    %eax,%eax
      4006af:       c7 45 f4 0a 00 00 00    movl   $0xa,-0xc(%rbp)
      4006b6:       48 8d 45 f4             lea    -0xc(%rbp),%rax
      4006ba:       48 89 45 e8             mov    %rax,-0x18(%rbp)
      4006be:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      4006c2:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
      4006c9:       00 00 
      4006cb:       74 05                   je     4006d2 <f+0x3e>
      4006cd:       e8 9e fd ff ff          callq  400470 <__stack_chk_fail@plt>
      4006d2:       c9                      leaveq 
      4006d3:       c3                      retq   
    

    默认编译时,使用的是-fstack-protector选项,其结果如下:

    000000000040055a <a>:
      40055a:       55                      push   %rbp
      40055b:       48 89 e5                mov    %rsp,%rbp
      40055e:       48 83 ec 10             sub    $0x10,%rsp
      400562:       c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
      400569:       48 8d 45 fc             lea    -0x4(%rbp),%rax
      40056d:       48 89 c7                mov    %rax,%rdi
      400570:       e8 c1 ff ff ff          callq  400536 <c>
      400575:       c9                      leaveq 
      400576:       c3                      retq   
    
    0000000000400577 <b>:
      400577:       55                      push   %rbp
      400578:       48 89 e5                mov    %rsp,%rbp
      40057b:       5d                      pop    %rbp
      40057c:       c3                      retq   
    
    000000000040057d <d>:
      40057d:       55                      push   %rbp
      40057e:       48 89 e5                mov    %rsp,%rbp
      400581:       66 c7 45 f0 00 00       movw   $0x0,-0x10(%rbp)
      400587:       c6 45 f0 41             movb   $0x41,-0x10(%rbp)
      40058b:       5d                      pop    %rbp
      40058c:       c3                      retq   
    
    000000000040058d <e>:
      40058d:       55                      push   %rbp
      40058e:       48 89 e5                mov    %rsp,%rbp
      400591:       c7 45 cc 00 00 00 00    movl   $0x0,-0x34(%rbp)
      400598:       eb 11                   jmp    4005ab <e+0x1e>
      40059a:       8b 45 cc                mov    -0x34(%rbp),%eax
      40059d:       48 98                   cltq   
      40059f:       c7 44 85 d0 41 00 00    movl   $0x41,-0x30(%rbp,%rax,4)
      4005a6:       00 
      4005a7:       83 45 cc 01             addl   $0x1,-0x34(%rbp)
      4005ab:       83 7d cc 09             cmpl   $0x9,-0x34(%rbp)
      4005af:       7e e9                   jle    40059a <e+0xd>
      4005b1:       5d                      pop    %rbp
      4005b2:       c3                      retq   
    
    00000000004005b3 <f>:
      4005b3:       55                      push   %rbp
      4005b4:       48 89 e5                mov    %rsp,%rbp
      4005b7:       48 89 7d e8             mov    %rdi,-0x18(%rbp)
      4005bb:       c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
      4005c2:       48 8d 45 fc             lea    -0x4(%rbp),%rax
      4005c6:       48 89 45 e8             mov    %rax,-0x18(%rbp)
      4005ca:       5d                      pop    %rbp
      4005cb:       c3                      retq   
    

    以上几种情况,函数内均未插入canary。仔细观察 -fstack-protector-stong 保护的对象,其实都是有可能被利用来执行任意代码的,比如若被赋值对象,或函数参数是一个函数指针,则修改其值会执行任意代码。

    canary 对系统影响

    Linux 从3.14内核开始,为-fstack-protector-strong增加了一个新的编译选项CONFIG_CC_STACKPROTECTOR_STRONG,并且原有选项CONFIG_CC_STACKPROTECTOR(对应-fstack-protector)修改为CONFIG_CC_STACKPROTECTOR_REGULAR。

    以下是x86_64平台默认选项编译的内核对比数据。

    编译选项代码段大小(字节)被保护函数个数 / 函数总数
    no stack protector 11430641 0 / 36110
    CONFIG_CC_STACKPROTECTOR_REGULAR 11468490 (+0.33%) 1015 / 36110 (2.81%)
    CONFIG_CC_STACKPROTECTOR_STRONG 11692790 (+2.24%) 7401 / 36110 (20.5%)

    可以看出比起-fstack-protector-all,20.5%已经不错,在性能与安全之间找到了很好的折衷。

    参考 :https://outflux.net/blog/archives/2014/01/27/fstack-protector-strong/

  • 相关阅读:
    Vue实现树形下拉框
    设置tomcat开机自启和后台运行
    PS 怎么去掉图片上的文字
    iPhone系列设备媒体查询:
    Tomcat不需要输入项目名便可访问项目(直接用域名或者ip)
    在写php项目时 修改外部css或js文件没有效果
    Vue中Vuex的详解与使用(简洁易懂的入门小实例)
    解决刷新页面vuex store中数据丢失的问题
    2.12 综合运用 使用
    2.11 DataBinding 简单使用
  • 原文地址:https://www.cnblogs.com/gm-201705/p/9863958.html
Copyright © 2011-2022 走看看