Linux可执行文件.data节的默认行为在5.4和5.9之间更改?

标签 linux assembly x86-64 nasm elf

故事
情况1
我不小心在.data部分中编写了我的汇编代码。我编译并执行它。即使我没有指定5.4.0-53-generic这样的标志,该程序也可以在Linux execstack下正常运行。
情况2:
之后,我在Linux 5.9.0-050900rc5-generic下执行了该程序。程序得到了SIGSEGV。我通过阅读/proc/$pid/maps检查了虚拟内存权限。原来,该部分不可执行。
我认为Linux上有一个配置可以管理该权限。但是我不知道在哪里可以找到。
代码
[Linux 5.4.0-53-通用]
运行(正常)

ammarfaizi2@integral:/tmp$ uname -r
5.4.0-53-generic
ammarfaizi2@integral:/tmp$ cat test.asm
[section .data]
global _start
_start:
  mov eax, 60
  xor edi, edi
  syscall
ammarfaizi2@integral:/tmp$ nasm --version
NASM version 2.14.02
ammarfaizi2@integral:/tmp$ nasm -felf64 test.asm -o test.o
ammarfaizi2@integral:/tmp$ ld test.o -o test
ammarfaizi2@integral:/tmp$ ./test
ammarfaizi2@integral:/tmp$ echo $?
0
ammarfaizi2@integral:/tmp$ md5sum test
7ffff5fd44e6ff0a278e881732fba525  test
ammarfaizi2@integral:/tmp$ 
检查权限(00400000-00402000 rwxp),因此它是可执行的。
## Debug
gef➤  shell cat /proc/`pgrep test`/maps
00400000-00402000 rwxp 00000000 08:03 7471589                            /tmp/test
7ffff7ffb000-7ffff7ffe000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffe000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
gef➤
[Linux 5.9.0-050900rc5-generic]
运行(Segfault)
root@esteh:/tmp# uname -r
5.9.0-050900rc5-generic
root@esteh:/tmp# cat test.asm
[section .data]
global _start
_start:
  mov eax, 60
  xor edi, edi
  syscall
root@esteh:/tmp# nasm --version
NASM version 2.14.02
root@esteh:/tmp# nasm -felf64 test.asm -o test.o
root@esteh:/tmp# ld test.o -o test
root@esteh:/tmp# ./test
Segmentation fault (core dumped)
root@esteh:/tmp# echo $?
139
root@esteh:/tmp# md5sum test
7ffff5fd44e6ff0a278e881732fba525  test
root@esteh:/tmp# 
检查权限(00400000-00402000 rw-p),因此它不可执行。
## Debug
gef➤  shell cat /proc/`pgrep test`/maps
00400000-00402000 rw-p 00000000 fc:01 2412                               /tmp/test
7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0                          [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
gef➤  
objdump -p
root@esteh:/tmp# objdump -p test

test:     file format elf64-x86-64

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12
         filesz 0x0000000000001009 memsz 0x0000000000001009 flags rw-

问题
  • 在Linux上用于管理默认ELF节权限的配置在哪里?
  • 我对权限的观察正确吗?

  • 概括
  • Linux上.data5.4.0-53-generic部分的默认权限是可执行的。
  • Linux上.data5.9.0-050900rc5-generic部分的默认权限是而不是可执行文件。
  • 最佳答案

    这只是一个猜测:我认为罪魁祸首是在没有READ_IMPLIES_EXEC段的情况下自动设置的PT_GNU_STACK个性。
    5.4 kernel source we can find this piece of code中:

    SET_PERSONALITY2(loc->elf_ex, &arch_state);
    if (elf_read_implies_exec(loc->elf_ex, executable_stack))
        current->personality |= READ_IMPLIES_EXEC;
    
    那是唯一可以将RW部分转换为RWX部分的东西。对我来说,对PROC_EXEC的任何其他使用似乎都没有改变或与此问题相关。executable_stack设置为here:
    for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
        switch (elf_ppnt->p_type) {
        case PT_GNU_STACK:
            if (elf_ppnt->p_flags & PF_X)
                executable_stack = EXSTACK_ENABLE_X;
            else
                executable_stack = EXSTACK_DISABLE_X;
            break;
    
    但是,如果不存在PT_GNU_STACK段,则该变量将保留its default value:
    int executable_stack = EXSTACK_DEFAULT;
    
    现在,此工作流程在5.4和最新的内核源代码中都是相同的,更改的是elf_read_implies_exec的定义:
    Linux 5.4:
    /*
     * An executable for which elf_read_implies_exec() returns TRUE will
     * have the READ_IMPLIES_EXEC personality flag set automatically.
     */
    #define elf_read_implies_exec(ex, executable_stack) \
        (executable_stack != EXSTACK_DISABLE_X)
    
    Latest Linux:
    /*
     * An executable for which elf_read_implies_exec() returns TRUE will
     * have the READ_IMPLIES_EXEC personality flag set automatically.
     *
     * The decision process for determining the results are:
     *
     *                 CPU: | lacks NX*  | has NX, ia32     | has NX, x86_64 |
     * ELF:                 |            |                  |                |
     * ---------------------|------------|------------------|----------------|
     * missing PT_GNU_STACK | exec-all   | exec-all         | exec-none      |
     * PT_GNU_STACK == RWX  | exec-stack | exec-stack       | exec-stack     |
     * PT_GNU_STACK == RW   | exec-none  | exec-none        | exec-none      |
     *
     *  exec-all  : all PROT_READ user mappings are executable, except when
     *              backed by files on a noexec-filesystem.
     *  exec-none : only PROT_EXEC user mappings are executable.
     *  exec-stack: only the stack and PROT_EXEC user mappings are executable.
     *
     *  *this column has no architectural effect: NX markings are ignored by
     *   hardware, but may have behavioral effects when "wants X" collides with
     *   "cannot be X" constraints in memory permission flags, as in
     *   https://lkml.kernel.org/r/20190418055759.GA3155@mellanox.com
     *
     */
    #define elf_read_implies_exec(ex, executable_stack) \
        (mmap_is_ia32() && executable_stack == EXSTACK_DEFAULT)
    
    请注意,在5.4版本中,如果未将堆栈显式标记为不可执行(通过elf_read_implies_exec段),则PT_GNU_STACK如何返回true值。
    在最新的资料中,现在的检查更具防御性:在ELF二进制文件中未找到elf_read_implies_exec段的情况下,PT_GNU_STACK仅在32位可执行文件上为true。
    我汇编了程序,将其链接起来,没有找到PT_GNU_STACK段,所以这可能是原因。
    如果这确实是问题所在,并且如果我正确地遵循了代码,那么如果您将堆栈设置为二进制文件中的不可执行文件,则其数据部分将不再被映射为可执行文件(即使在Linux 5.4上也是如此)。

    关于Linux可执行文件.data节的默认行为在5.4和5.9之间更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64833715/

    相关文章:

    c - 在 x86_64 linux 中重定位超过 2GB 的程序时出现链接器错误?

    java - 当进程达到一定内存大小时在 Linux 中重新启动服务

    linux - splice() 用于匿名内存——有什么性能优势吗?

    linux - 来自 Linux 用户空间的 PEBS 的 x86-64 "linear address"?

    assembly - 是否需要为 X64 快速调用叶函数保留 RCX?

    linux - 如何测试STDIN读取错误

    regex - 在 bash 中查找 2 个字符串中的指定字符串

    mysql - 如何从 linux 文件中删除特定符号?

    c - 从 C 调用 Intel 8086 汇编程序

    c - 查找哪条指令在 Cortex M3 上导致了陷阱