Linux 可执行文件 .data 部分的默认行为在 5.4 和 5.9 之间发生了变化? [英] Linux default behavior of executable .data section changed between 5.4 and 5.9?

查看:29
本文介绍了Linux 可执行文件 .data 部分的默认行为在 5.4 和 5.9 之间发生了变化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不小心在 .data 部分编写了我的汇编代码.我编译并执行了它.程序在 Linux 5.4.0-53-generic 下正常运行,即使我没有指定像 execstack 这样的标志.

I accidentally wrote my Assembly code in the .data section. I compiled it and executed it. The program ran normally under Linux 5.4.0-53-generic even though I didn't specify a flag like execstack.

之后,我在Linux5.9.0-050900rc5-generic下执行了程序.程序得到SIGSEGV.我通过阅读 /proc/$pid/maps 检查了虚拟内存权限.结果发现该部分不可执行.

After that, I executed the program under Linux 5.9.0-050900rc5-generic. The program got SIGSEGV. I inspected the virtual memory permission by reading /proc/$pid/maps. It turned out that the section is not executable.

我认为 Linux 上有一个配置可以管理该权限.但我不知道在哪里可以找到.

I think there is a configuration on Linux that manages that permission. But I don't know where to find.

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]

运行(段错误)

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-

问题

  1. Linux 上管理默认 ELF 部分权限的配置在哪里?
  2. 我对权限的观察是否正确?

总结

  • Linux 5.4.0-53-generic.data 部分的默认权限是可执行的.
  • Linux 5.9.0-050900rc5-generic.data 部分的默认权限 不可 可执行.
  • Summary

    • Default permission for .data section on Linux 5.4.0-53-generic is executable.
    • Default permission for .data section on Linux 5.9.0-050900rc5-generic is NOT executable.
    • 推荐答案

      这只是一个猜测:我认为罪魁祸首是自动设置的 READ_IMPLIES_EXEC 个性在没有 PT_GNU_STACK 段的情况下.

      This is only a guess: I think the culprit is the READ_IMPLIES_EXEC personality that was being set automatically in the absence of a PT_GNU_STACK segment.

      5.4 内核源代码中我们可以找到这个一段代码:

      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 的任何其他用途似乎都没有改变或与这个问题相关.

      That's the only thing that can transform an RW section into an RWX one. Any other use of PROC_EXEC didn't seem to be changed or relevant to this question, to me.

      executable_stack 设置 这里:

      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 段不存在,该变量将保留 其默认值:

      But if the PT_GNU_STACK segment is not present, that variable retains its default value:

      int executable_stack = EXSTACK_DEFAULT;
      

      现在这个工作流程在 5.4 和最新的内核源代码中相同,改变的是elf_read_implies_exec的定义:

      Now this workflow is identical in both 5.4 and the latest kernel source, what changed is the definition of 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)
      

      最新 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段).

      Note how in the 5.4 version the elf_read_implies_exec returned a true value if the stack was not explicitly marked as not executable (via the PT_GNU_STACK segment).

      在最新的源代码中,检查现在更具防御性:elf_read_implies_exec 仅在 32 位可执行文件上为真,在没有 PT_GNU_STACK 段的情况下ELF 二进制文件.

      In the latest source, the check is now more defensive: the elf_read_implies_exec is true only on 32-bit executable, in the case where no PT_GNU_STACK segment was found in the ELF binary.

      我组装了你的程序,链接了它,但没有发现PT_GNU_STACK段,所以这可能是原因.如果这确实是问题并且我正确地遵循了代码,如果您在二进制文件中将堆栈设置为不可执行,则不应再将其数据部分映射为可执行文件(即使在 Linux 5.4 上也不应).

      I assembled your program, linked it, and found no PT_GNU_STACK segment, so this may be the reason.
      If this is indeed the issue and if I followed the code correctly, if you set the stack as not executable in the binary, its data section should not be mapped executable anymore (not even on Linux 5.4).

      这篇关于Linux 可执行文件 .data 部分的默认行为在 5.4 和 5.9 之间发生了变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆