GCC插入__strcpy_chk校验致崩溃 如何定向关闭指定缓冲区越界检查
柔性数组动态缓冲区触发
__strcpy_chk误判崩溃的解决方案 问题根因
- 开发者基于柔性数组实现运行时可变长度缓冲区,通过
malloc申请足量内存、人工严格管控写入边界,从业务逻辑上保证缓冲区无溢出风险 - 程序在GCC 4.8.5、
-O2优化等级下编译后运行崩溃,通过objdump -d反汇编发现,编译器自动插入了__strcpy_chk@plt的调用逻辑 - 该fortify检查逻辑仅静态识别柔性数组成员的声明长度为1,将固定值1作为缓冲区长度参数传入校验函数,直接触发运行时安全检查异常中断程序
- 核心需求:仅针对该已知安全的特定缓冲区跳过
strcpy类的越界检查逻辑,保留其余代码位置的全局安全检查能力,避免全局关闭校验引入不必要的安全风险
可落地实现方案
- 替换写入操作的底层函数实现,绕开编译器对字符串函数的检查逻辑
- 对该柔性数组的
strcpy写入操作,改用显式长度的内存拷贝完成(比如手写字节拷贝循环、memcpy) - 原理:
memcpy类函数的长度参数为用户显式传入的运行时值,编译器不会触发__strcpy_chk类的静态检查逻辑,也不会将柔性数组的1字节声明长度误判为校验长度
- 对该柔性数组的
- 通过GCC函数属性精准关闭单代码块的fortify检查
- GCC 4.8.5支持
__attribute__((optimize("_FORTIFY_SOURCE=0")))属性,将该属性挂载到包含目标缓冲区写入操作的函数上,仅关闭该函数内部的编译期fortify检查,不影响全局其他位置的安全校验能力 - 示例写法:
__attribute__((optimize("_FORTIFY_SOURCE=0"))) void write_to_flexbuf(struct flex_buffer *buf, const char *content) { strcpy(buf->data, content); }
- GCC 4.8.5支持
- 通过指针类型中转打断编译器的静态推导链路
- 调用
strcpy前,将柔性数组的成员指针先强制转换为void*类型,再转回char*作为函数参数传入 - 原理:编译器的fortify检查依赖静态类型关联推导目标缓冲区的声明长度,经过
void*中转后,编译器无法将传入的char*参数关联到柔性数组的1字节静态声明,也就不会触发误判的长度校验 - 示例写法:
char *target = (char *)(void *)buf->data; strcpy(target, content);
- 调用
注意事项
- 所有方案均不涉及全局关闭fortify安全检查,其余代码位置的越界检查逻辑会保持正常生效
- 所有方案完全适配GCC 4.8.5版本的编译行为,不需要升级编译器版本
- 操作过程中需保留原有的人工边界校验逻辑,不能因为跳过了编译器的误判检查就放松实际写入的长度管控
内容的提问来源于stack exchange,提问作者Pan Ruochen
相关产品推荐
相关产品推荐

