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\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/

stack-protector-strong的更多相关文章

  1. 编译驱动模块时,出现“stack protector enabled but no compiler support”[解决办法]【转】

    转自:http://blog.chinaunix.net/uid-26847859-id-3297170.html 原文地址:编译驱动模块时,出现“stack protector enabled bu ...

  2. Android: protecting the kernel

    Linux内置安全机制 Address space separation/process isolation unix permissions DAC capabilities SELinux sec ...

  3. linux提权辅助工具(一):linux-exploit-suggester.sh

    来自:https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh ...

  4. 深入linux kernel内核配置选项

    ============================================================================== 深入linux kernel内核配置选项 ...

  5. 一步一步学ROP之linux_x86篇

    一步一步学ROP之linux_x86篇 作者:蒸米@阿里聚安全 ​ 一.序 ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过 ...

  6. CC_STACKPROTECTOR防内核堆栈溢出补丁分析【转】

    转自:https://yq.aliyun.com/articles/1723 摘要: 作者:王智通   CC_STACKPROTECT补丁是Tejun Heo在09年给主线kernel提交的一个用来防 ...

  7. lfs遇到的一些问题--准备阶段

    本机宿主系统archlinux,lfs SVN-20130711,参考文档 1.在离开或重新进入当前工作环境 (比如 su 成为 root 或者其他用户) 时不要忘记检查 $LFS 是否设置好. ec ...

  8. 转:一步一步学ROP之linux_x86篇 - 蒸米

    原文地址:http://drops.wooyun.org/tips/6597 0×00 序 ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击 ...

  9. CSAPP 缓冲区溢出试验

    缓冲区溢出试验是CSAPP课后试验之一,目的是: 更好的理解什么是缓冲区溢出 如何攻击带有缓冲区溢出漏洞的程序 如何编写出更加安全的代码 了解并理解编译器和操作系统为了让程序更加安全而提供的几种特性 ...

随机推荐

  1. Oracle11g版本中未归档隐藏参数

    In this post, I will give a list of all undocumented parameters in Oracle 11g. Here is a query to se ...

  2. Google Protocol Buffers 反序列化 转

    http://www.cnblogs.com/royenhome/archive/2010/10/30/1865256.html   本文作为结束篇,会稍微介绍下怎么反序列化GoogleBuffer数 ...

  3. 机器学习---笔记----Python基础

    一. python简介 1. python 具有丰富强大的库,常被称为胶水语言,能够把用其他语言制作的各种模块很轻松地联结在一起 2. python强制使用空白符(white space)作为语句缩进 ...

  4. Python Django 之 直接执行自定义SQL语句(二)

    转载自:https://my.oschina.net/liuyuantao/blog/712189 一般来说,最好用 Django 自带的模型来实现这些操作.这里仅仅只是为了学习使用原始 SQL 而做 ...

  5. xml解析与生成的学习资料

    xml解析与生成的学习资料:http://blog.csdn.net/u012325167/article/category/6129813 ----------------------------- ...

  6. RabbitMQ 设置队列的过期时间

    设置队列的过期时间非常简单,在声明队列时,设置x-expires参数即可.当队列的生存周期超时后,RabbitMQ server会自动将该队列删除. 代码如下: channel.QueueDeclar ...

  7. 每天CSS学习之border-collapse

    border-collapse是CSS2的一个属性,其作用是折叠表格(table)的边框.collapse翻译过来又折叠的意思. border-collapse有三个值: collapse:将表格和单 ...

  8. Observer,观察者模式,C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. Cracking The Coding Interview 1.5

    //原文: // // Write a method to replace all spaces in a string with '%20'. // #include <iostream> ...

  10. MicroBlaze核的串行接口实验:SPI UART

    reference : https://blog.csdn.net/weixin_42413559/article/details/80720566 串行接口:SPI UART XPS->SDK ...