【问题标题】:ASLR and memory layout on 64 bits: Is it limited to the canonical part (128 TiB)?64 位上的 ASLR 和内存布局:是否仅限于规范部分 (128 TiB)?
【发布时间】:2022-01-05 07:03:49
【问题描述】:

当加载启用了 ASLR 的 PIE 可执行文件时,Linux 会限制程序段映射到规范部分(最多 0000_7fff_ffff_ffff)还是会使用完整的较低部分(起始位 0)?

【问题讨论】:

  • 它可能是特定于处理器的。在 AMD Ryzen Thunderbird 台式机和一些便宜的笔记本电脑上不一样。多试几次cat /proc/self/mapscat /proc/$$/maps
  • 你所说的“全下段”是什么意思? 0 – 7ffffffffffff 不是完整的下部吗?
  • @prl 问题是是只到 7fffffffffff,还是一直到 7fffffffffffffff。
  • 您似乎知道什么是规范地址...那么您为什么认为“随机化”非规范地址并将它们提供给用户空间程序是有意义的?它们无法使用,您根本无法用它们来寻址内存,CPU只会引发一般保护错误。另见:Why does Linux favor 0x7f mappings?
  • 硬件不会忽略高 16 位。它会检查它们是否匹配第 47 位,如果不匹配则引发 #GP。

标签: linux security x86-64 memory-address aslr


【解决方案1】:

显然,Linux 不会为您的进程提供不可用的地址,这会使它在尝试执行来自_start 的代码时引发#GP(0) 异常(并因此引发段错误)。 (或者如果接近截止,当它尝试加载或存储 .data 或 .bss 时)

这实际上会发生在最初尝试将 RIP 设置为非规范值的指令上,可能是 iretsysret1


在具有 48 位虚拟地址的系统上,零到0000_7fff_ffff_ffff 当表示为符号扩展的 64 位值时,虚拟地址空间的完整下半部分。

在支持 PML5(并由内核使用)的系统上,虚拟地址为 57 位宽,因此
零到00ff_ffff_ffff_ffff 是规范范围的下半部分。

参见https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt - 第一行是用户空间范围。 (它谈论“56 位”虚拟地址。这是不正确或具有误导性的,PML5 是 57 位,一个额外的完整级别的页表,每级 9 位。所以低半部分是 56 位,第 57 位为 0,而高半部分为 56 位,第 57 位为 1。)

========================================================================================================================
    Start addr    |   Offset   |     End addr     |  Size   | VM area description
========================================================================================================================
                  |            |                  |         |
 0000000000000000 |    0       | 00007fffffffffff |  128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
                  |            |                  |         |
 0000800000000000 | +128    TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
                  |            |                  |         |     virtual memory addresses up to the -128 TB
                  |            |                  |         |     starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
                                                            |
                                                            | Kernel-space virtual memory, shared between all processes:
...

或者对于 PML5:

 0000000000000000 |    0       | 00ffffffffffffff |   64 PB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
                  |            |                  |         |
 0000800000000000 |  +64    PB | ffff7fffffffffff | ~16K PB | ... huge, still almost 64 bits wide hole of non-canonical
                  |            |                  |         |     virtual memory addresses up to the -64 PB
                  |            |                  |         |     starting offset of kernel mappings.

脚注 1:
正如 prl 所指出的,这种设计允许实现实际上只有 48 个实际位来存储管道中任何位置的 RIP 值,除了跳转和检测有符号溢出以防执行运行到非规范区域的末端。 (也许在必须存储uop的每个地方都保存晶体管,它需要知道自己的地址。)不像你可以跳转/ iret到任意RIP,然后#GP(0)异常必须推送正确的64 位非规范地址,这意味着 CPU 必须暂时记住它。

调试查看您从哪里跳转也更有用,因此以这种方式设计规则是有意义的,因为没有故意跳转到非规范地址的用例。 (与跳转到未映射的页面不同,#PF 异常处理程序可以修复这种情况,例如通过请求分页,因此您希望故障地址是新的 RIP。)

有趣的事实:在 Intel CPU 上使用带有非规范 RIP 的 sysret 将在环 0 (CPL=0) 中使用 #GP(0),因此 RSP 不会切换并且仍然 = 用户堆栈。如果存在任何其他线程,这会让它们弄乱内核用作堆栈的内存。这是 IA-32e 中的设计缺陷,英特尔的 x86-64 实现。这就是为什么 Linux 使用iret 从 syscall 入口点返回到用户空间的原因,如果在此期间在此进程上使用了 ptrace。内核知道一个新进程会有一个安全的 RIP,所以它实际上可能会使用sysret 更快地跳转到用户空间。

【讨论】:

  • 我明白了,我很困惑,因为我忘了翻译是硬件(见我的评论)。事实上,我是从安全的角度提出这个问题:如果我没记错的话,一条指令地址的低 12 位(偏移量)将始终保持不变,无论 aslr 选择哪个页面,这样就只剩下“ " 36 位随机性很高,但不是“那么”高,因此可能会被暴力破解
  • @AaaBbb:是的,这是 ASLR 的理论最大熵。但 Linux 并没有那么极端:ASLR bits of Entropy of mmap() 是一个古老的问答。不过,想想暴力破解所涉及的内容:通常是受到攻击的程序崩溃。这个想法是要有足够的熵,以便在第一次尝试或几次尝试时猜对的可能性非常低,大概是通过监控/入侵检测注意到重复崩溃。
  • Re "这将是内核通过 IRET 使用非规范 RIP 进入用户空间后发生的第一件事。" #GP 出现在 IRET 指令的内核中,而不是在尝试使用非规范地址读取内存时出现在用户空间中。我认为它是这样定义的,这样处理器就不必存储所有 64 位 RIP。
  • @prl:谢谢,关于永远不需要存储超过 virt 地址宽度的有趣点。可能很多地方需要存储微控制器,而且每个地方可能都需要自己的地址,这样可以很好地节省晶体管。
猜你喜欢
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 2023-04-07
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
相关资源
最近更新 更多