污染的Linux内核
1. 概述
可以使用可加载内核模块修改内核,因此也可以将内核置于未知或不可靠状态。当这种情况发生时,我们说内核被污染了。当一个内核标记自己被污染时,大多数时候运行它是没有问题的;只有当有人想要调查某个问题或错误时,这些信息才会变得相关。
在这个阶段,社区不能保证它会按预期运行。
2. 污染状态
**污染状态是一组标志,用于标识内核开发人员无法调查内核问题的特定情况。**例如,如果专有内核模块导致问题,则无法对其进行可靠调试,因为其源代码不可用,并且无法确定其影响。
同样,如果之前发生过严重的内核或硬件故障,内核空间的完整性可能会受到损害,这意味着内核生成的任何后续调试消息可能都不可靠。
2.1. 内核错误中的解码状态
每个内核错误、oops 或 panic 错误报告的顶部都包含一个受污染的标志。
这是“未受污染”内核中的一个错误 :
BUG: unable to handle kernel paging request at ffffc90012a9c418
Oops: 0000 [#1] SMP
Modules linked in: parport_pc ppdev bnep rfcomm bluetooth libahci ...
CPU: 6 PID: 2925 Comm: ryzom_client Not tainted 3.10.0-031000rc5-generic #201306082135
Hardware name: Gigabyte Technology Co., Ltd.
task: ffff880414908000 ti: ffff880403afc000 task.ti: ffff880403afc000
RIP: 0010:[<ffffffffa03a2ace>] [<ffffffffa03a2ace>] radeon_fence_process+0x8e/0x160 [radeon]
[...]
我们可以在以*“CPU:”开头的行中找到一个“Not tainted:”*,这意味着内核没有被污染。
让我们看看另一个错误,这次是在受污染的内核中:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
Oops: 0002 [#1] SMP PTI
CPU: 0 PID: 4424 Comm: insmod Tainted: P W O 4.20.0-0.rc6.fc30 #1
Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
RIP: 0010:my_oops_init+0x13/0x1000 [kpanic]
[...]
在这里,我们找到了*“Tainted: P WO”。“Tainted:”*之后的标志字符可以是字母或空格。我们可以用这些字母解码状态。一些常见的标志是:
- P:这意味着内核中加载了专有许可模块。它可能是一个不在 GNU 通用公共许可证 (GPL) 或兼容许可证下的模块。
- G:所有加载的模块都是在 GPL 或与 GPL 兼容的许可证下获得许可的,但是其他东西已经污染了内核;一个不同的标志将表明这一点。
- F:这是使用insmod或modprobe的强制选项*-f*加载的模块,因此无法检查版本控制信息。
- M:这是一个由硬件触发的Machine Check Exception (MCE),表示硬件相关的问题。
有关更多标志,请查看内核文档 。
2.2. 运行时的解码状态
我们可以在运行时检查系统的污染状态:
$ cat /proc/sys/kernel/tainted
例如,如果命令返回0,则内核未被污染。同样,如果命令返回4609,我们可以用它来解码原因。不同的内核工具为此提供了脚本。
我们这里有一个简单的脚本来进行解码:
$ for i in $(seq 18); do echo $(($i-1)) $((4609>>($i-1)&1));done
0 1
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 1
10 0
11 0
12 1
13 0
14 0
15 0
16 0
17 0
现在,我们可以在上述文档中检查这些数字以找出原因。在我们的案例中,原因是:
- 0:专有模块已加载
- 9:内核发出警告
- 12:加载了外部构建的模块
2.3. 消除污染
让我们像前面的示例一样查看错误报告,并使用类似于以下内容的行检查该部分:
Oops: 0000 [#1] SMP
这是自启动以来的第一个Oops ,如括号中的*#1所示。在该点之后发生的每个Oops和任何其他问题都可能是第一个Oops* 的后续问题,即使两者看起来无关。通过消除第一个*Oops *的原因并在之后重现问题来排除这种情况。
重新配置或更新内核也可能对这种情况有所帮助。即使在我们消除污染原因后,状态也是永久的。例如,如果我们卸载专有内核模块或修复硬件错误,内核仍然会被污染。我们必须重新启动系统以重置污染标志。
此外,当我们的系统使用安装其内核模块的软件(如 Nvidia 的专有图形驱动程序、VirtualBox 或任何外部源)时,内核会污染自身。在这里,我们通常在重新创建实际问题之前暂时卸载模块。
但是,如果污染的原因是驻留在内核源代码的暂存树中的模块,我们可以报告该问题,但我们必须确保该模块是造成污染的唯一原因。