標籤:art 編譯器 length can cat buffer 設計 like pop
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有其篩選原則,總結起來有幾條:
- 當本地變數的***地址***,作為賦值運算式右值 的一部分,或作為函數參數
- 當本地變數是數組(或包含數組的union 類型),不管數組大小與類型
- 使用 register 類型的本地變數(*)(uses register local variables)
第3點未能驗證,可能理解有誤?
通過彙編代碼,對比一下:
[email protected]:~/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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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/
stack-protector-strong