【问题标题】:Sending user-mode interrupts on x86在 x86 上发送用户模式中断
【发布时间】:2020-01-14 21:13:23
【问题描述】:

在 Linux x86 上,我可以发送中断(例如,由计时器或其他机制触发),这些中断将由在用户模式下运行的代码处理吗?

假设答案是肯定的(几乎可以肯定是肯定的,参见例如timer_create),是否仅在用户模式下发生此中断,或者是否涉及一些内核转换(例如,中断最初由内核处理,然后将信号发送给用户进程)。

【问题讨论】:

  • 您总是可以编写无效代码,即尝试执行会产生某种类型异常的无效操作的代码,然后您可以在用户模式下以 Linux 信号的形式捕获这些异常。我不确定这是否是您所说的“发送中断”。在调用信号处理程序之前,将执行大量代码。 AFAIK,Linux 中没有内置机制允许直接连接您自己的(用户模式)中断处理程序或在 IDT 中定义您自己的条目,但我认为可以通过一些手动操作来完成。
  • 在 Linux 中,中断处理程序都在 ring 0 中运行。内核会在用户模式内发出一个信号,以便可以调用适当的用户模式处理程序。

标签: linux x86 signals interrupt


【解决方案1】:

所有内核定时器接口通过在内核内部处理定时器中断(或以其他方式注意到或等到截止日期已到)后向用户空间进程传递信号来工作。

在环 3 中运行中断处理程序或从仅由一个特定进程映射的用户空间虚拟地址运行中断处理程序存在许多障碍。 (即使您固定该内存以使其无法分页,它仍然仅在将 CR3 设置为该进程的页表时才被映射。x86 在 IDT(中断描述符表)中使用虚拟地址,并且必须映射页面当中断触发时(或者你得到一个页面错误,我猜,你真的不希望完全异步发生)。这对于普通的内核中断处理程序来说不是问题;它总是保持内核代码映射到同一个虚拟所有用户空间页表的地址。)

允许将用户空间函数指针注册为 ring 0 中断处理程序的内核 API 会将王国的密钥交给该用户空间进程,实际上是以内核权限运行,所以这非常不合理。


从技术上讲,x86 有一个在 ring 3 中运行的中断处理程序,但如果在 ring 0 中触发中断,iret 将出错,而不是返回到被中断的内核代码。

必须专门编写中断处理程序以返回iret,并保留所有寄存器。例如__attribute__((interrupt_handler))https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html。同一核心上的任何其他进程都将受制于该进程; 其中的任何错误(例如破坏某些架构状态,或弄脏 SSE/AVX regs)都可能影响其他进程。(如果您能弄清楚如何在一个进程中获取代码在可能为另一个进程设置 CR3 时运行...)

避免死锁也是一个大问题;在内核中,您可以在中断处理程序(“上半部分”)中执行的操作有很多限制,因为它可以在任何其他指令之间异步运行(除非您禁用该内核上的中断)。


我认为 Linux 让你这样做是不合理的。即使你以某种方式解决了所有(非常困难的)问题,甚至让处理程序在 ring 3 中运行,内核仍然必须相信它不会影响任何其他进程的架构状态。

X 服务器获得运行in/out 指令(通过iopl)和/或访问/dev/mem 的权限(理论上这会让它从其他进程窃取信息)之类的事情有先例。但这会更糟,并且让您可以轻松访问其他进程的寄存器状态快照。

【讨论】:

  • 哦,您可以让一个中断处理程序以非 0 的特权级别运行,但您只能将 IRET 从该处理程序退回到相同或更低特权的环而不会出错。因此,如果您在 IDT 中有一个中断处理程序,其 CS 为 ring 3,您将永远无法 IRET 到 Interrupt 0,1,2,这意味着您将仅限于运行 ring 3 代码,因为您永远不会能够从中断处理程序返回到任何其他特权级别。当然,如果您的中断处理程序在 3 中运行,那么在不使用某种调用门的情况下它可以做的事情将受到限制。
  • 呼叫门可以允许较低特权的环访问以更高特权级别运行的代码。
  • @MichaelPetch:谢谢,已修复。还有一些我第一次没有想到的其他惊人的错误(比如虚拟内存);添加了这些。
猜你喜欢
  • 2016-04-06
  • 2011-06-28
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 2015-09-18
相关资源
最近更新 更多