linux 内核如何知道在系统调用中作为参数传递的地址无效?

How linux kernel knows the address passed as argument in syscall is invalid?

目前我正在阅读理解linux内核系统调用一章,但我无法理解[= =25=] 内核知道通过 syscall() 传递的地址参数是无效的。

书中提到地址检查会延迟到它被使用时,当 linux 使用这个地址时它会产生页面错误。 它进一步提到在内核模式下三种情况下可能会发生故障

• The kernel attempts to address a page belonging to the process address space, but either the corresponding page frame does not exist, or the kernel is trying to write a read-only page.

• Some kernel function includes a programming bug that causes the exception to be raised when that program is executed; alternatively, the exception might be caused by a transient hardware error.

• A system call service routine attempts to read or write into a memory area whose address has been passed as a system call parameter, but that address does not belong to the process address space.

页面错误处理程序必须区分这些情况,因为要采取的操作相当different.The页面错误处理程序可以通过确定错误的线性地址是否包含在其中一个中来轻松识别第一种情况进程拥有的内存区域。

但是内核如何区分剩下的两种情况。虽然教科书上有解释,但我觉得很陌生。请帮忙解释一下。

页面错误处理程序__do_page_fault包括这段代码:

if (!(error_code & X86_PF_USER) &&
            !search_exception_tables(regs->ip)) {
            bad_area_nosemaphore(regs, error_code, address, NULL);
            return;
        }

当系统调用源自内核模式而非用户模式时,此条件 !(error_code & X86_PF_USER) 为真。当执行使用传递给系统调用的线性的指令之一时未发生页面错误时,此条件 !search_exception_tables(regs->ip) 为真。请注意,regs->ip 保存导致页面错误的指令的指令指针。当这两个条件都为真时,这意味着要么在某些内核函数中存在错误,要么存在硬件错误(第二种情况)。

regs 包含页面错误时所有体系结构寄存器的快照。在 x86 上,这包括 CS 段寄存器。该寄存器中的 RPL 可用于确定系统调用是来自用户模式还是内核模式。

search_exception_tables 对编译内核时在编译时构建的已排序指令地址数组执行二进制搜索。这些基本上是访问传递给系统调用的地址的指令。

对于您列出的其他两种情况,条件 !(error_code & X86_PF_USER) 为假。