污点内核¶
当发生一些可能与以后调查问题相关的事情时,内核会将自己标记为“污点”。不要太担心这一点,大多数时候运行污点内核没有问题;一旦有人想要调查某些问题,这些信息主要是有意义的,因为它的真正原因可能是导致内核污点的事件。这就是为什么来自污点内核的错误报告通常会被开发人员忽略,因此请尝试用未污点的内核重现问题。
请注意,即使在您撤消导致污点的原因(即卸载专有内核模块)后,内核仍将保持污点状态,以表明内核仍然不可信。这也是为什么当内核注意到内部问题(“内核错误”)、可恢复错误(“内核 oops”)或不可恢复错误(“内核 panic”)时,会打印污点状态并将有关此问题的调试信息写入日志 dmesg
输出。也可以通过/proc/
中的文件在运行时检查污点状态。
错误、oops或panic消息中的污点标志¶
您可以在以“CPU:”开头的一行的顶部附近找到污点状态;如果在进程ID (“PID:”) 和触发该事件的命令的缩写名称 (“Comm:”) 之后显示内核被污点的原因
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]
[...]
如果内核在事件发生时未被污点,您会在此处找到“Not tainted: ”;如果被污点,则将打印“Tainted: ”以及字母或空格。在上面的例子中,它看起来像这样
Tainted: P W O
这些字符的含义在下表中进行了解释。在这种情况下,内核早期被污染是因为加载了专有模块 (P
),发生了警告 (W
),并且加载了外部构建的模块 (O
)。要解码其他字母,请使用下表。
在运行时解码污点状态¶
在运行时,您可以通过读取cat /proc/sys/kernel/tainted
来查询污点状态。如果返回0
,则内核未被污点;任何其他数字都表示被污点的原因。解码该数字的最简单方法是脚本tools/debugging/kernel-chktaint
,您的发行版可能会将其作为名为linux-tools
或kernel-tools
的软件包的一部分;如果没有,您可以从git.kernel.org下载该脚本,并使用sh kernel-chktaint
执行它,这将在先前引用的日志中包含语句的机器上打印如下内容
Kernel is Tainted for following reasons:
* Proprietary module was loaded (#0)
* Kernel issued warning (#9)
* Externally-built ('out-of-tree') module was loaded (#12)
See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or
https://linuxkernel.org.cn/doc/html/latest/admin-guide/tainted-kernels.html for
a more details explanation of the various taint flags.
Raw taint value as int/string: 4609/'P W O '
您可以尝试自己解码该数字。如果只有一种原因导致您的内核被污点,那么这很容易,在这种情况下,您可以在下表中找到该数字。如果有多个原因,您需要解码该数字,因为它是一个位域,其中每个位表示是否存在特定类型的污点。最好将此留给前面提到的脚本,但如果您需要快速的东西,可以使用此shell命令来检查设置了哪些位
$ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done
解码污点状态的表¶
位 |
日志 |
编号 |
导致内核被污染的原因 |
---|---|---|---|
0 |
G/P |
1 |
已加载专有模块 |
1 |
_/F |
2 |
强制加载模块 |
2 |
_/S |
4 |
内核在不符合规范的系统上运行 |
3 |
_/R |
8 |
强制卸载模块 |
4 |
_/M |
16 |
处理器报告了机器检查异常 (MCE) |
5 |
_/B |
32 |
引用了错误的页面或一些意外的页面标志 |
6 |
_/U |
64 |
用户空间应用程序请求污点 |
7 |
_/D |
128 |
内核最近已死亡,即存在 OOPS 或 BUG |
8 |
_/A |
256 |
ACPI表被用户覆盖 |
9 |
_/W |
512 |
内核发出警告 |
10 |
_/C |
1024 |
已加载暂存驱动程序 |
11 |
_/I |
2048 |
应用了针对平台固件中错误的解决方法 |
12 |
_/O |
4096 |
已加载外部构建(“树外”)模块 |
13 |
_/E |
8192 |
已加载未签名的模块 |
14 |
_/L |
16384 |
发生软锁死 |
15 |
_/K |
32768 |
内核已进行实时修补 |
16 |
_/X |
65536 |
辅助污点,为发行版定义和使用 |
17 |
_/T |
131072 |
内核使用结构随机化插件构建 |
18 |
_/N |
262144 |
已运行内核测试 |
19 |
_/J |
524288 |
用户空间在fwctl中使用了改变调试操作 |
注意:字符_
在此表中表示空格,以方便阅读。
污点的更详细说明¶
如果加载的所有模块都具有GPL或兼容许可证,则为
G
;如果已加载任何专有模块,则为P
。没有MODULE_LICENSE或MODULE_LICENSE未被insmod识别为GPL兼容的模块被假定为专有模块。如果任何模块被
insmod -f
强制加载,则为F
;如果所有模块都正常加载,则为' '
。如果内核在不符合规范的处理器或系统上运行,则为
S
:硬件已置于不受支持的配置中,因此无法保证正确的执行。例如,如果内核被污染
在x86上:在不报告PAE但可能具有功能实现的intel CPU(例如Pentium M)上,通过forcepae强制使用PAE,SMP内核在非官方支持SMP的Athlon CPU上运行,MSR正在从用户空间被探测。
在arm上:内核在某些CPU(例如Keystone 2)上运行,而没有启用某些内核功能。
在arm64上:CPU之间的硬件功能不匹配,引导加载程序以不同的模式启动CPU。
某些驱动程序在不受支持的体系结构上使用(例如,x86_64以外的scsi/snic,非x86/x86_64/itanium上的scsi/ips,为arm64上的irqchip/irq-gic具有损坏的固件设置......)。
x86/x86_64:微代码延迟加载是危险的,会导致内核污染。它要求所有CPU汇合以确保在系统尽可能静止时进行更新。但是,更高优先级的MCE/SMI/NMI可以使控制流远离该汇合并中断更新,这对机器可能有害。
如果模块被
rmmod -f
强制卸载,则为R
;如果所有模块都正常卸载,则为' '
。如果任何处理器报告了机器检查异常,则为
M
;如果未发生机器检查异常,则为' '
。如果页面释放函数找到错误的页面引用或一些意外的页面标志。这表示硬件问题或内核错误;日志中应该有其他信息指示发生此污点的原因。
如果用户或用户应用程序专门请求设置Tainted标志,则为
U
;否则为' '
。如果内核最近已死亡,即存在OOPS或BUG,则为
D
。如果ACPI表已被覆盖,则为
A
。如果内核先前已发出警告,则为
W
。(尽管某些警告可能会设置更具体的污点标志。)如果已加载暂存驱动程序,则为
C
。如果内核正在解决平台固件(BIOS或类似固件)中的严重错误,则为
I
。如果已加载外部构建(“树外”)模块,则为
O
。如果在支持模块签名的内核中加载了未签名的模块,则为
E
。如果系统先前发生了软锁死,则为
L
。如果内核已进行实时修补,则为
K
。
X
辅助污点,为Linux发行商定义和使用。
T
内核使用 randstruct 插件构建,该插件可能会有意产生极其不寻常的内核结构布局(甚至是性能病态的布局),这在调试时非常重要。 在构建时设置。
N
如果已运行内核测试,例如 KUnit 测试。
J
如果用户空间打开了 /dev/fwctl/* 并执行了 FWTCL_RPC_DEBUG_WRITE 来使用该设备的调试功能。 设备调试功能可能会导致设备以未定义的方式发生故障。