现代Linux内核能否关闭段执行保护或使堆/数据段可执行?
关于现代Linux中段执行权限与缓冲区溢出的问题解答
1. 能否不修改程序代码关闭段执行保护?
不行。现代Linux的NX/DEP这类内存保护机制是内核层面的安全特性,不修改目标程序文件或内核配置的前提下,无法全局关闭段执行保护。NX标记是程序ELF文件的固有属性(由PT_GNU_STACK段的权限设置决定),内核加载程序时会严格遵循该属性分配内存权限。即便用工具修改ELF头的权限标记,本质也属于修改程序文件,不符合“不修改程序代码”的要求。
2. 能否让堆/数据段可执行?
在现代Linux内核(5.4及以上版本)中,仅通过gcc -z execstack编译无法让堆或数据段变为可执行。这个编译选项如今仅会修改ELF文件的PT_GNU_STACK段标记,内核加载程序时只会将栈页面设为可执行,堆和数据段(.data/.bss)仍会保持默认的不可执行属性,受NX保护。
若要让堆/数据段可执行,有两种途径,但都需要对程序或环境做修改:
- 在程序代码中调用
mprotect系统调用,将目标内存页的权限改为PROT_READ | PROT_WRITE | PROT_EXEC; - 以root权限修改内核配置或使用内核级工具关闭全局NX保护,但这会影响系统所有程序,属于极端操作,不适用于常规测试场景。
3. 是否仅栈可被设为可执行?
不是,但仅通过gcc -z execstack编译的话,确实只有栈会被设为可执行。其他内存区域(堆、数据段)要变为可执行,要么在程序内部通过mprotect主动修改权限,要么手动修改ELF文件的段权限(比如把.data段的p_flags属性改为PF_X),让内核加载时应用这些权限。
另外补充execstack行为变化的原因:Linux内核5.4版本后调整该逻辑,核心是强化内存安全——过去让堆也可执行会放大堆溢出的攻击风险,现在仅开放栈可执行,既满足部分老旧程序的兼容性需求,又大幅缩小了攻击面。
内容的提问来源于stack exchange,提问作者R. Hahnemann
相关产品推荐
相关产品推荐

