为啥数据和堆栈段是可执行的?
Posted
技术标签:
【中文标题】为啥数据和堆栈段是可执行的?【英文标题】:Why data and stack segments are executable?为什么数据和堆栈段是可执行的? 【发布时间】:2011-12-13 08:58:48 【问题描述】:我刚刚注意到我的简单程序的数据和堆栈段是可执行的。 我在/proc/[pid]/maps中看到了,简单的代码就确认了。
例如:
; prog.asm
section .data
code: db 0xCC ;int3
section .text
global _start
_start:
jmp code
mov rax, 60 ; sys_exit
mov rdi, 0
syscall
然后
nasm -f elf64 prog.asm
ld -o prog prog.o
./prog
使 prog 执行 int3 指令。
用 C 编写并用 gcc 构建的程序的数据、堆栈和堆是不可执行的,那么为什么用汇编编写的程序的行为方式不同呢?
【问题讨论】:
【参考方案1】:在现代 Linux 系统上,链接器会将堆栈/数据标记为不可执行IFF所有参与链接的对象都有一个特殊的“标记”部分.note.GNU-stack
。
如果你编译例如int foo() return 1;
进入汇编(与gcc -S foo.c
),你会看到这个:
.section .note.GNU-stack,"",@progbits
对于nasm
,语法见section 8.9.2 of the manual;你想要这样的东西:
section .note.GNU-stack noalloc noexec nowrite progbits
注意
这必须为进入可执行文件的每个 .o
文件完成。如果任何目标文件需要可执行堆栈或数据,则为整个段设置。
【讨论】:
它有效,谢谢。顺便说一句,我发现了这个:link,并且在第 7.9.2 节“对 SECTION 指令的 elf 扩展”中声明了节 .data 默认情况下具有 noexec 标志。但是,即使在带有 .data 部分的代码中显式编写 noexec 也是行不通的。奇怪。 您能否提供任何记录GNU_STACK
行为的来源?我已经看到您可以将-z noexecstack
传递给ld
以使其具有相同的行为...但这不是加载程序问题吗?当 .data 部分被明确标记为 noexec 时,加载器将其映射为可执行文件。
@Marco:Unexpected exec permission from mmap when assembly files included in the project 的更多信息,包括 Linux 内核源代码的链接。
谢谢。这提供了一些清晰度。我想我理解它的基本原理:旧精灵(在现代拱门中的 NX 位之前)可能取决于拥有可执行数据,因为没有办法禁用它。因此,为了检测“较新”的精灵,加载程序使用可执行堆栈功能。很遗憾nasm
没有自动添加的标志。
注意 linux 内核的行为 recently changed。对于较新的内核,使用nasm
编译的部分将不再默认在 x86_64 中可执行。 See commit以上是关于为啥数据和堆栈段是可执行的?的主要内容,如果未能解决你的问题,请参考以下文章