stack-protector-strong

Improve protection against stack buffer overflowsubuntu

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-strongless

-fstack-protector 的缺點

僅對使用>=8字節(–param=ssp-buffer-size=N, 默認N=8)的char數組的函數提供保護,所以其保護能力有限。ide

-fstack-protector-all 的缺點

全部函數都會加入檢測,1)會增長程序體積,2)佔用棧空間,尤爲內核棧空間固定的狀況;能夠認爲這都不是好的設計。函數

-fstack-protector-strong

再來看一下 stack-protector-strong 選項,它對是否在函數中加入canary有其篩選原則,總結起來有幾條:性能

  1. 當本地變量的***地址***,做爲賦值表達式右值 的一部分,或做爲函數參數
  2. 當本地變量是數組(或包含數組的union 類型),無論數組大小與類型
  3. 使用 register 類型的本地變量(*)(uses register local variables)

第3點未能驗證,可能理解有誤?.net

經過彙編代碼,對比一下:設計

zzhiyuan@ubuntu:~/exploits/test$ cat register.c 
#include <stdio.h>

void c (long a)
{
        printf ("%ld\n", 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/

本站公眾號
   歡迎關注本站公眾號,獲取更多信息