前言
module verification failed: signature and/or required key missing - tainting kernel
signature 或者 required key missing是导致内核受到污染的事件,不过这对于模块的运行没啥影响。因此我们一般都忽略掉这个问题。
dmesg --follow
-w, --follow
Wait for new messages. This feature is supported on systems with readable /dev/kmsg only (since kernel 3.5.0).
CPU: 0 PID: 31024 Comm: ... Kdump: loaded Tainted: G W OE ----V------- 3.10.0-&version.x86_64 #1
一、简介
大多数情况下,运行受污染的内核没有什么问题,来自受污染内核的错误报告通常会被开发人员忽略。
即使撤消导致污染的原因(即卸载专有内核模块),内核仍将保持污染,这表明内核仍然不可信。 这也是为什么内核在发现内部问题(‘kernel bug’)、可恢复错误(‘kernel oops’)或不可恢复错误(‘kernel panic’)时会打印污染状态,并将有关此的调试信息写入日志 dmesg 输出。 也可以通过 /proc/ 中的文件在运行时检查污染状态。
在以“CPU:”开头的行中的顶部附近找到受污染的状态; 内核是否或为什么被污染显示在进程 ID (‘PID:’) 和触发事件的command的缩写名称 (‘Comm:’) 之后:
CPU: 0 PID: 31024 Comm: ... Kdump: loaded Tainted: G W OE ----V------- 3.10.0-&version.x86_64 #1
如果内核在事件发生时没有被污染,将会显示 Not tainted: 如果污染了,那么将打印“Tainted:和字符,无论是字母还是空白。 在上面的示例中:
Tainted: G W OE
G :表示所有加载的模块都有一个GPL或兼容的许可,P表示加载了任何专有模块。
没有MODULE_LICENSE或具有MODULE_LICENSE但不被insmod认可为兼容GPL的模块被认为是专有的。
O :表示如果已加载外部构建(out–of-tree)模块。
二、Decoding tainted state at runtime
在运行时,您可以通过读取 cat /proc/sys/kernel/tainted 来查询污染状态。
如果返回 0,则内核没有被污染; 任何其他数字都表明了它的原因。 解码该数字的最简单方法是脚本 tools/debugging/kernel–chktaint。
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Randy Dunlap <rdunlap@infradead.org>, 2018
# Thorsten Leemhuis <linux@leemhuis.info>, 2018
usage()
{
cat <<EOF
usage: ${0##*/}
${0##*/} <int>
Call without parameters to decode /proc/sys/kernel/tainted.
Call with a positive integer as parameter to decode a value you
retrieved from /proc/sys/kernel/tainted on another system.
EOF
}
if [ "$1"x != "x" ]; then
if [ "$1"x == "--helpx" ] || [ "$1"x == "-hx" ] ; then
usage
exit 1
elif [ $1 -ge 0 ] 2>/dev/null ; then
taint=$1
else
echo "Error: Parameter '$1' not a positive integer. Aborting." >&2
exit 1
fi
else
TAINTFILE="/proc/sys/kernel/tainted"
if [ ! -r $TAINTFILE ]; then
echo "No file: $TAINTFILE"
exit
fi
taint=`cat $TAINTFILE`
fi
if [ $taint -eq 0 ]; then
echo "Kernel not Tainted"
exit
else
echo "Kernel is "tainted" for the following reasons:"
fi
T=$taint
out=
addout() {
out=$out$1
}
if [ `expr $T % 2` -eq 0 ]; then
addout "G"
else
addout "P"
echo " * proprietary module was loaded (#0)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "F"
echo " * module was force loaded (#1)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "S"
echo " * kernel running on an out of specification system (#2)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "R"
echo " * module was force unloaded (#3)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "M"
echo " * processor reported a Machine Check Exception (MCE) (#4)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "B"
echo " * bad page referenced or some unexpected page flags (#5)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "U"
echo " * taint requested by userspace application (#6)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "D"
echo " * kernel died recently, i.e. there was an OOPS or BUG (#7)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "A"
echo " * an ACPI table was overridden by user (#8)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "W"
echo " * kernel issued warning (#9)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "C"
echo " * staging driver was loaded (#10)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "I"
echo " * workaround for bug in platform firmware applied (#11)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "O"
echo " * externally-built ('out-of-tree') module was loaded (#12)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "E"
echo " * unsigned module was loaded (#13)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "L"
echo " * soft lockup occurred (#14)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "K"
echo " * kernel has been live patched (#15)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "X"
echo " * auxiliary taint, defined for and used by distros (#16)"
fi
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "T"
echo " * kernel was built with the struct randomization plugin (#17)"
fi
echo "Raw taint value as int/string: $taint/'$out'"
#EOF#
可以通过上述数字解码该号码。 如果只有一个原因导致内核受到污染,这很容易,因为在这种情况下,可以在下表中找到数字。 如果有多种原因,您需要解码该数字,因为它是一个位域,其中每个位表示特定类型的污点的缺失或存在。 最好用之前提到的脚本进行解码 tools/debugging/kernel-chktaint。
for i in $(seq 18)
do
echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));
done
注:为方便阅读,本表中字符_代表空白。
上面显示:
bit9=1,kernel issued warning。
bit12=1,externally–built (“out-of-tree”) module was loaded。
执行 tools/debugging/kernel-chktaint脚本:
加载一个自定义模块后:
上面显示
bit9=1,kernel issued warning。
bit12=1,externally-built (“out-of-tree”) module was loaded。
bit13=1,unsigned module was loaded。
执行 tools/debugging/kernel-chktaint脚本:
卸载掉加载的模块后:
污染event仍然存在:即使撤消导致污染的原因(即卸载专有内核模块),内核仍将保持污染,这表明内核仍然不可信。
三、源码分析
struct module结构中的成员taints表示内核模块是否会污染内核,如果模块会污染内核,便调用add_taint_module函数 设置 struct module的taints成员。
// linux-5.13/include/linux/module.h
struct module {
......
unsigned long taints; /* same bits as kernel:taint_flags */
......
}
// linux-5.13/kernel/module.c
static inline void add_taint_module(struct module *mod, unsigned flag,
enum lockdep_ok lockdep_ok)
{
add_taint(flag, lockdep_ok);
set_bit(flag, &mod->taints);
}
// linux-5.13/kernel/panic.c
/**
* add_taint: add a taint flag if not already set.
* @flag: one of the TAINT_* constants.
* @lockdep_ok: whether lock debugging is still OK.
*
* If something bad has gone wrong, you'll want @lockdebug_ok = false, but for
* some notewortht-but-not-corrupting cases, it can be set to true.
*/
void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
{
if (lockdep_ok == LOCKDEP_NOW_UNRELIABLE && __debug_locks_off())
pr_warn("Disabling lock debugging due to kernel taintn");
set_bit(flag, &tainted_mask);
if (tainted_mask & panic_on_taint) {
panic_on_taint = 0;
panic("panic_on_taint set ...");
}
}
EXPORT_SYMBOL(add_taint);
// include/linux/kernel.h
/* This cannot be an enum because some may be used in assembly source. */
#define TAINT_PROPRIETARY_MODULE 0
#define TAINT_FORCED_MODULE 1
#define TAINT_CPU_OUT_OF_SPEC 2
#define TAINT_FORCED_RMMOD 3
#define TAINT_MACHINE_CHECK 4
#define TAINT_BAD_PAGE 5
#define TAINT_USER 6
#define TAINT_DIE 7
#define TAINT_OVERRIDDEN_ACPI_TABLE 8
#define TAINT_WARN 9
#define TAINT_CRAP 10
#define TAINT_FIRMWARE_WORKAROUND 11
#define TAINT_OOT_MODULE 12
#define TAINT_UNSIGNED_MODULE 13
#define TAINT_SOFTLOCKUP 14
#define TAINT_LIVEPATCH 15
#define TAINT_AUX 16
#define TAINT_RANDSTRUCT 17
#define TAINT_FLAGS_COUNT 18
#define TAINT_FLAGS_MAX ((1UL << TAINT_FLAGS_COUNT) - 1)
struct taint_flag {
char c_true; /* character printed when tainted */
char c_false; /* character printed when not tainted */
bool module; /* also show as a per-module taint flag */
extern const struct taint_flag taint_flags[TAINT_FLAGS_COUNT];
// /kernel/panic.c
static unsigned long tainted_mask =
IS_ENABLED(CONFIG_GCC_PLUGIN_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0;
/*
* TAINT_FORCED_RMMOD could be a per-module flag but the module
* is being removed anyway.
*/
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
[ TAINT_PROPRIETARY_MODULE ] = { 'P', 'G', true },
[ TAINT_FORCED_MODULE ] = { 'F', ' ', true },
[ TAINT_CPU_OUT_OF_SPEC ] = { 'S', ' ', false },
[ TAINT_FORCED_RMMOD ] = { 'R', ' ', false },
[ TAINT_MACHINE_CHECK ] = { 'M', ' ', false },
[ TAINT_BAD_PAGE ] = { 'B', ' ', false },
[ TAINT_USER ] = { 'U', ' ', false },
[ TAINT_DIE ] = { 'D', ' ', false },
[ TAINT_OVERRIDDEN_ACPI_TABLE ] = { 'A', ' ', false },
[ TAINT_WARN ] = { 'W', ' ', false },
[ TAINT_CRAP ] = { 'C', ' ', true },
[ TAINT_FIRMWARE_WORKAROUND ] = { 'I', ' ', false },
[ TAINT_OOT_MODULE ] = { 'O', ' ', true },
[ TAINT_UNSIGNED_MODULE ] = { 'E', ' ', true },
[ TAINT_SOFTLOCKUP ] = { 'L', ' ', false },
[ TAINT_LIVEPATCH ] = { 'K', ' ', true },
[ TAINT_AUX ] = { 'X', ' ', true },
[ TAINT_RANDSTRUCT ] = { 'T', ' ', true },
};
/**
* print_tainted - return a string to represent the kernel taint state.
*
* For individual taint flag meanings, see Documentation/admin-guide/sysctl/kernel.rst
*
* The string is overwritten by the next call to print_tainted(),
* but is always NULL terminated.
*/
const char *print_tainted(void)
{
static char buf[TAINT_FLAGS_COUNT + sizeof("Tainted: ")];
BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
if (tainted_mask) {
char *s;
int i;
s = buf + sprintf(buf, "Tainted: ");
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
const struct taint_flag *t = &taint_flags[i];
*s++ = test_bit(i, &tainted_mask) ?
t->c_true : t->c_false;
}
*s = 0;
} else
snprintf(buf, sizeof(buf), "Not tainted");
return buf;
}
int test_taint(unsigned flag)
{
return test_bit(flag, &tainted_mask);
}
EXPORT_SYMBOL(test_taint);
unsigned long get_taint(void)
{
return tainted_mask;
}
总结
参考资料
Linux 5.13.0
https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html
原文地址:https://blog.csdn.net/weixin_45030965/article/details/126261043
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_47048.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!