内核栈溢出防护必须在编译期启用config_stackprotector=y等配置,运行时sysctl或启动参数无效;需检查/boot/config-$(uname -r)确认配置状态,而非依赖文档或猜测。

内核栈溢出不能靠运行时开关“修好”,必须在编译阶段启用对应 CONFIG 项,否则 sysctl 或启动参数完全无效。
确认当前内核是否启用了栈保护机制
直接检查 /boot/config-$(uname -r) 中关键配置项的状态,而不是查文档或猜:
-
CONFIG_STACKPROTECTOR=y:必须为y(编译进内核),=m对栈保护无意义 -
CONFIG_VMAP_STACK=y:开启独立映射的内核栈,防止跨页覆写;x86_64 上需同时满足CONFIG_RELOCATABLE=y -
CONFIG_DEBUG_STACKOVERFLOW=y:仅用于开发调试,会在栈底插入 canary 并检测溢出,但会增加开销,生产环境一般关掉 -
CONFIG_DEBUG_STACK_USAGE=y:配合 SysRq +u键可查看各 CPU 栈使用峰值,不防溢出,只辅助定位
为什么 sysctl 和 boot param 对栈溢出防护基本没用
因为栈保护是编译期决定的内存布局与指令插入行为:
-
stack_protector需要编译器(如 GCC)在函数 prologue/epilogue 插入__stack_chk_fail调用和 canary 读写,内核未启用该 CONFIG,就根本不会生成这些代码 -
vmap_stack改变的是内核初始化时的页表映射方式,不是运行时能切换的内存策略 - 试图用
sysctl -w kernel.kptr_restrict=2或mitigations=on启动参数来“打开栈防护”,只会让你误以为已生效——实际grep CONFIG_STACKPROTECTOR /boot/config-$(uname -r)仍为is not set
真正起效的加固组合与典型错误现象
以下组合才能实质性提升栈溢出利用门槛:
- 必须开启:
CONFIG_STACKPROTECTOR=y+CONFIG_VMAP_STACK=y+CONFIG_STRICT_KERNEL_RWX=y(后者防止攻击者篡改 canary 检查逻辑) - 推荐开启:
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y(避免未初始化栈变量泄露内核地址) - 常见错误现象:
Kernel panic - not syncing: stack-protector: Kernel stack is corrupted—— 这说明 canary 已触发,但若你没开CONFIG_STACKPROTECTOR,连这行 panic 都不会出现,而是静默跳转到非法地址 - 注意兼容性:
CONFIG_VMAP_STACK在某些老旧驱动(尤其是闭源显卡模块)中可能引发问题,需实测;而CONFIG_SLAB_FREELIST_HARDENED主要防堆 UAF,对栈溢出无直接作用
最常被忽略的一点:即使所有 CONFIG 都正确,如果内核是第三方预编译包(比如 Ubuntu 的 linux-image-generic),它大概率没开 VMAP_STACK 或只开了弱 canary(CONFIG_STACKPROTECTOR_REGULAR=y 而非 CONFIG_STACKPROTECTOR_STRONG=y)。真要防御,得自己配 config、重编译、替换内核镜像。











