了解收到用于空取消引用的 SIGSEGV 后的内核流程

问题描述 投票:0回答:1

我试图弄清楚当我们编写这两个代码时 Linux 内核(x86_64,v6.9)内部发生的事情的顺序:

// Null-dereference + writing to page zero
*(char *)0 = 0;
// Null-dereference + only reading from page zero
char c = *(char *)0;

我尝试用 Ftrace 对其进行分析,这就是我得到的结果:

handle_mm_fault <-- do_user_addr_fault
sanitize_fault_flags <-- handle_mm_fault
arch_vma_access_permitted <-- handle_mm_fault
bad_area_nosemaphore <-- do_user_addr_fault
__bad_area_nosemaphore <-- do_user_addr_fault
force_sig_fault <-- __bad_area_nosemaphore

因此,根据我的理解,我们导致了页面错误,并且以某种方式

arch_vma_access_permitted()
sanitize_fault_flags()
决定返回
VM_FAULT_SIGSEGV
,并且
__bad_area_nosemaphore()
使用它向带有
SIGSEGV
的进程发送
force_sig_fault()
。我的问题是,第 0 页的权限是什么?它是否首先被映射?如果没有,那么我认为
vma_is_foreign()
应该涵盖这种情况并导致分段错误。我还在
load_elf_binary()
中发现了一些有趣的东西,用于模拟以前 Linux 版本的 ABI 行为:

if (current->personality & MMAP_PAGE_ZERO) {
        /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
           and some applications "depend" upon this behavior.
           Since we do not have the power to recompile these, we
           emulate the SVr4 behavior. Sigh. */
        error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
                        MAP_FIXED | MAP_PRIVATE, 0);
}

其中最令人困惑的部分是

PROT_EXEC
为什么我们需要将指令存储在第 0 页内? 如果它也有
PROT_READ
,那么当
current->personality
MMAP_PAGE_ZERO
时,从第 0 页读取应该不会导致分段错误,对吗?找不到 SVr4 规范,所以我不确定详细信息。我也不确定这个
personality
何时适用于任务,但我们可以得出结论,在某些情况下,页面零 GETS 被映射(当然,如果
mmap()
为零,我们可以使用
mmap_min_addr
重新映射它,但我是现在谈论默认行为,而不是重新映射)。我找不到任何其他映射零页的
vm_mmap()
do_mmap()

c linux-kernel x86 segmentation-fault
1个回答
0
投票

零页的权限是什么?它一开始就被映射了吗?

事实并非如此。除了您显示的这段奇怪的代码,或其他异常(例如用户空间在

vm.mmap_min_addr = 0
时明确请求映射它),那么零页面永远不会自动映射。

这与任何其他页面相同,虚拟地址为零的事实并没有真正使它变得特别。当故障发生时,您将准确地结束于here,因为该进程没有对应的映射(

vma
)。

不知道为什么你要提到

vma_is_foreign()
,但如果你一开始就没有
vma
,那么就不能真正调用它。
__bad_area_nosemaphore()
将负责
SIGSEGV
传递,调用
force_sig_fault()
,然后调用另一系列函数来传递信号。


其中最令人困惑的部分是PROT_EXEC。为什么我们需要将指令存储在第 0 页内?

旧软件期望读取意味着执行行为,因为这就是硬件过去的工作方式。事实上,对于较旧的 x86 32 位 CPU,甚至对于在 x86_64 上运行的某些 32 位软件,情况仍然如此。 看看这个评论例如。

如果它也有 PROT_READ,那么当 current->personality 有 MMAP_PAGE_ZERO 时,从第 0 页读取不应该导致分段错误,对吗?

对。

我也不确定这种性格何时适用于某项任务

主要取决于底层架构。特定于 Arch 的代码选择要在新执行人员上切换哪些个性位。

SET_PERSONALITY
SET_PERSONALITY2
宏由每个拱门定义,您可以在 herehere 看到不同的定义。

© www.soinside.com 2019 - 2024. All rights reserved.