C和C++安全编码(原书第2版)
上QQ阅读APP看书,第一时间看更新

2.6.6 栈溢出保护器

在4.1版本中,GCC引入了栈溢出保护(SSP)的功能,它实现了来自StackGuard的探测仪[Etoh 2000]。SSP也被称为ProPolice,它是GCC的一个扩展,用以保护用C编写的应用程序免遭大多数常见形式的栈缓冲区溢出的漏洞利用,它以GCC的中间语言翻译器的形式实现。SSP提供了缓冲区溢出检测和变量重排序技术来防止对指针的破坏。特别是,SSP对局部变量重排序,将缓冲区放到指针后面,并且将函数参数中的指针复制到局部变量缓冲区之前的区域,从而防止了对指针的破坏(这些指针可被用于进一步破坏任意内存位置)。

SSP特性通过GCC的命令行参数启用,-fstack-protector和-fno-stack-protector选项可以为带有易受攻击的对象(如数组)的函数打开或关闭栈溢出保护。-fstack-protector-all和-fno-stack-protector-all选项可以打开或关闭对每一个函数的保护,而不仅仅局限于对具有字符数组的函数的保护。最后,使用-fstack-protector时,-Wstack-protector option选项对没有获得栈保护的函数发出警告。

SSP的工作原理是引入一个探测仪变量,以检测对栈上的参数、返回地址和前面的帧指针的改变。SSP用如下步骤将代码片段插入到合适的位置:在应用程序初始化期间,产生一个随机数作为哨位值,以防止未授权用户的窥探。遗憾的是,这个动作很容易耗尽系统的熵。

SSP还提供了一种更安全的栈结构,如图2.18所示。

图2.18 栈溢出保护(SSP)栈结构

此结构建立了以下限制:

·位置(A)没有数组或指针变量。

·位置(B)有数组或包含数组的结构。

·位置(C)没有数组。

将哨位放到包含数组的数据区(B)后面可以阻止对参数、返回地址、前帧指针(previous frame pointer)或局部变量(不包括其他数组)进行覆盖的缓冲区溢出攻击。例如,编译器不能重新排列struct成员,所以如下类型的栈对象仍未得到保护。


1  struct S {
2      char buffer[40];
3      void (*f)(struct S*);
4  };