最后编辑于: 2022-01-26 10:55 | 分类: 嵌入式软件开发 | 标签: GCC | 浏览数: 1566 | 评论数: 0
而上文又是对 Using GCC's Stack Smashing Protector on microcontrollers 一文的翻译
GCC编译器提供了栈溢出保护功能(Stack Smashing Protection, 简称SSP)。
要理解SSP首先要知道什么是栈溢出。
C语言中, 需要开发人员自己管理内存, 不可避免的会引入一系列内存相关的BUG, 比如: 内存重复释放、野指针、栈溢出等。这些问题通常都比较难定位, 因为出问题的地方一般都不是案发现场(比如A处发生内存越界写操作, 可能在B处程序才异常)。
引用维基百科的说法: 缓冲区溢出是指往内存中写数据时, 越过了对应的内存边界, 写到了相邻的内存中。
如果发生溢出的缓冲区位于栈空间, 这就是栈溢出, 也就是说栈溢出是缓冲区溢出的一种情况。
黑客可以利用栈溢出修改函数的返回地址, 从而改变程序的执行逻辑。如果你的产品具有联网功能, 就特别需要注意这一点, 以免被攻击。
以下面的代码为例:
void my_buggy_function(const char *user_provided_message)
{
char Buffer[16];
strcpy(Buffer, user_provided_message);
}
如果用户提供的信息长度超过16字节, 将会导致Buffer发生缓冲区溢出, 多出来的数据将会被写到Buffer紧邻的内存区域。如果栈帧中函数的返回地址被修改, 将会导致不可预见的异常。
GCC栈溢出保护(SSP)是在函数中插入一个额外的变量(stack canary), 该变量位于函数返回地址所在内存的后面, 函数进入的时候该变量被赋为特定的值, 函数返回前判断该变量的值有没有改变。如果变化了, 说明出现了栈溢出, 这时候返回地址可能已经被修改了。
下图结合第一部分的代码片段展示SSP的工作原理:
当然, SSP并不能检测所有的栈溢出, 但有胜于无。不过, SSP会增加运行期消耗, 表现为使用的栈内存增加, CPU执行的指令增多。可以考虑在debug版本中开启该功能, release版本中关闭该功能。