【问题标题】: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 构建的程序的数据、堆栈和堆是不可执行的,那么为什么用汇编编写的程序的行为方式不同呢?

【问题讨论】:

    标签: linux assembly nasm memory-mapping


    【解决方案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
    猜你喜欢
    • 1970-01-01
    • 2013-03-21
    • 2015-12-09
    • 2011-08-15
    • 2010-09-30
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    相关资源
    最近更新 更多