为什么内核不能优雅地处理崩溃

Why Kernel Can't Handle Crash Gracefully

对于用户态应用程序,不正确的页面访问除了应用程序崩溃之外不会造成很多麻烦,应用程序崩溃可以通过异常处理优雅地完成。为什么我们不能对内核崩溃做同样的事情。所以当内核模块试图访问一些无效地址时,就会出现页面错误和内核崩溃。为什么不能像卸载故障模块那样优雅的处理

更具体地说,我想知道这是否完全不可能或可能。我不想知道它在使用该系统时可能带来的困难。我知道驱动程序崩溃会导致设备无法使用,对此我没有意见。唯一的问题是是否可以优雅地卸载有故障的驱动程序。

这有点像在说 "if you wrap all your Java code in a try/catch block, you've eliminated all bugs!"

有许多 "errors" 被捕获,例如kalloc returns NULL如果内存不足,USB代码returns错误如果没有USB等。但是没有try/catch整个操作系统,因为不是所有的bug都能修复。

如前所述,如果您的文件系统模块崩溃会怎样?保留 运行 没有文件?你的以太网驱动程序怎么样?现在你的盒子与互联网断开了,你甚至不能再通过 ssh 进入它,但甚至没有重新启动的体面。

因此,即使模块崩溃时内核可能不会"crash",内核的状态也可能被任意破坏。内核可以在没有屏幕、文件系统或互联网连接的情况下存活,但那是一种什么样的存在?

由于其他答案很好地解释了为什么从内核崩溃中恢复是不可行的,我将尝试讲述其他内容。

在这方面有很多研究,最著名的是教授。安迪·塔南鲍姆 (Andy Tanenbaum) 和他的 MINIX。虽然内核崩溃对 MINIX 来说仍然是致命的,但 MINIX 内核非常简单 (micro-kernel) 缩小了 space 的错误范围,并且在其中大多数其他东西 (包括 drivers) 是 运行 作为一个 user-mode 进程。因此,如果网络 driver 出现故障,因为它们在单独的地址 space 中是 运行,所有内核需要做的就是尝试重新启动 driver.

当然,有些地方你无法恢复(或仍然无法恢复),比如文件系统崩溃的情况(见最近的讨论here)。

有几篇关于这个主题的好论文,例如 http://pages.cs.wisc.edu/~swami/papers/thesis.pdf and I would highly recommend watching Tanenbaum's videos such this one(标题是 "MINIX 3: A Reliable and Secure Operating System" 以防它掉线)。

我认为这解决了您的评论:

We should be able to unload the faulty module. Why can't we? That is my question. Is it a design choice for security or its not possible at all. If it is a design choice, what factors forced us to make that choice

如果图形 driver 模块崩溃,您可以在没有屏幕的情况下生活。但是,我们不能卸载有故障的模块并继续,因为如果它崩溃并且它在与内核相同的地址 space 中运行,您不知道它是否毒化了内核内存 - 安全是这里的主要因素。

内核模块和内核本身共享同一个地址space。如果一个模块开始行为不端并覆盖来自另一个子系统的内存,则根本没有保护。 因此,当驱动程序崩溃时,它可能会或可能不会保留在该驱动程序的本地。如果幸运的话,您还有一个有点功能的内核,可以继续工作。 userspace 不会发生这种情况,因为每个进程的地址 space 都是独立的,因此可以捕获错误的内存访问并停止进程(这是一个 SEGFAULT)。