侧边栏切换

关于GCC的SSP栈溢出保护功能

最后编辑于: 2022-01-26 10:55  |  分类: 嵌入式软件开发  |  标签: GCC   |  浏览数: 1567  |  评论数: 0


本文摘自: 如何在实时操作系统(RTOS)中使用GCC的栈溢出保护(SSP)功能

而上文又是对 Using GCC's Stack Smashing Protector on microcontrollers 一文的翻译

GCC编译器提供了栈溢出保护功能(Stack Smashing Protection, 简称SSP)

要理解SSP首先要知道什么是栈溢出

1. 什么是栈溢出

C语言中, 需要开发人员自己管理内存, 不可避免的会引入一系列内存相关的BUG, 比如: 内存重复释放、野指针、栈溢出等。这些问题通常都比较难定位, 因为出问题的地方一般都不是案发现场(比如A处发生内存越界写操作, 可能在B处程序才异常)。

引用维基百科的说法: 缓冲区溢出是指往内存中写数据时, 越过了对应的内存边界, 写到了相邻的内存中。

如果发生溢出的缓冲区位于栈空间, 这就是栈溢出, 也就是说栈溢出是缓冲区溢出的一种情况。

黑客可以利用栈溢出修改函数的返回地址, 从而改变程序的执行逻辑。如果你的产品具有联网功能, 就特别需要注意这一点, 以免被攻击。

以下面的代码为例:

void my_buggy_function(const char *user_provided_message)
{
    char Buffer[16];
    strcpy(Buffer, user_provided_message);
}

如果用户提供的信息长度超过16字节, 将会导致Buffer发生缓冲区溢出, 多出来的数据将会被写到Buffer紧邻的内存区域。如果栈帧中函数的返回地址被修改, 将会导致不可预见的异常。

2. GCC栈溢出保护的工作原理

GCC栈溢出保护(SSP)是在函数中插入一个额外的变量(stack canary), 该变量位于函数返回地址所在内存的后面, 函数进入的时候该变量被赋为特定的值, 函数返回前判断该变量的值有没有改变。如果变化了, 说明出现了栈溢出, 这时候返回地址可能已经被修改了。

下图结合第一部分的代码片段展示SSP的工作原理:

当然, SSP并不能检测所有的栈溢出, 但有胜于无。不过, SSP会增加运行期消耗, 表现为使用的栈内存增加, CPU执行的指令增多。可以考虑在debug版本中开启该功能, release版本中关闭该功能。


上一篇: 关于命令行参数main(int argc,...)

下一篇: gnu __attribute详解