Fix: module signature vs tracepoints: add new TAINT_UNSIGNED_MODULE

Users have reported being unable to trace non-signed modules loaded
within a kernel supporting module signature.

This is caused by tracepoint.c:tracepoint_module_coming() refusing to
take into account tracepoints sitting within force-loaded modules
(TAINT_FORCED_MODULE). The reason for this check, in the first place, is
that a force-loaded module may have a struct module incompatible with
the layout expected by the kernel, and can thus cause a kernel crash
upon forced load of that module on a kernel with CONFIG_TRACEPOINTS=y.

Tracepoints, however, specifically accept TAINT_OOT_MODULE and
TAINT_CRAP, since those modules do not lead to the "very likely system
crash" issue cited above for force-loaded modules.

With kernels having CONFIG_MODULE_SIG=y (signed modules), a non-signed
module is tainted re-using the TAINT_FORCED_MODULE taint flag.
Unfortunately, this means that Tracepoints treat that module as a
force-loaded module, and thus silently refuse to consider any tracepoint
within this module.

Since an unsigned module does not fit within the "very likely system
crash" category of tainting, add a new TAINT_UNSIGNED_MODULE taint flag
to specifically address this taint behavior, and accept those modules
within Tracepoints. We use the letter 'X' as a taint flag character for
a module being loaded that doesn't know how to sign its name (proposed
by Steven Rostedt).

Also add the missing 'O' entry to trace event show_module_flags() list
for the sake of completeness.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
NAKed-by: Ingo Molnar <mingo@redhat.com>
CC: Thomas Gleixner <tglx@linutronix.de>
CC: David Howells <dhowells@redhat.com>
CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Mathieu Desnoyers 2014-03-13 12:11:30 +10:30 committed by Rusty Russell
parent cff26a51da
commit 66cc69e34e
9 changed files with 20 additions and 5 deletions

View File

@ -49,3 +49,4 @@ Description: Module taint flags:
O - out-of-tree module O - out-of-tree module
F - force-loaded module F - force-loaded module
C - staging driver module C - staging driver module
X - unsigned module

View File

@ -53,7 +53,8 @@ This has a number of options available:
If this is off (ie. "permissive"), then modules for which the key is not If this is off (ie. "permissive"), then modules for which the key is not
available and modules that are unsigned are permitted, but the kernel will available and modules that are unsigned are permitted, but the kernel will
be marked as being tainted. be marked as being tainted, and the concerned modules will be marked as
tainted, shown with the character 'X'.
If this is on (ie. "restrictive"), only modules that have a valid If this is on (ie. "restrictive"), only modules that have a valid
signature that can be verified by a public key in the kernel's possession signature that can be verified by a public key in the kernel's possession

View File

@ -265,6 +265,9 @@ characters, each representing a particular tainted value.
13: 'O' if an externally-built ("out-of-tree") module has been loaded. 13: 'O' if an externally-built ("out-of-tree") module has been loaded.
14: 'X' if an unsigned module has been loaded in a kernel supporting
module signature.
The primary reason for the 'Tainted: ' string is to tell kernel The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is occurred. Tainting is permanent: even if an offending module is

View File

@ -792,6 +792,8 @@ can be ORed together:
1024 - A module from drivers/staging was loaded. 1024 - A module from drivers/staging was loaded.
2048 - The system is working around a severe firmware bug. 2048 - The system is working around a severe firmware bug.
4096 - An out-of-tree module has been loaded. 4096 - An out-of-tree module has been loaded.
8192 - An unsigned module has been loaded in a kernel supporting module
signature.
============================================================== ==============================================================

View File

@ -469,6 +469,7 @@ extern enum system_states {
#define TAINT_CRAP 10 #define TAINT_CRAP 10
#define TAINT_FIRMWARE_WORKAROUND 11 #define TAINT_FIRMWARE_WORKAROUND 11
#define TAINT_OOT_MODULE 12 #define TAINT_OOT_MODULE 12
#define TAINT_UNSIGNED_MODULE 13
extern const char hex_asc[]; extern const char hex_asc[];
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] #define hex_asc_lo(x) hex_asc[((x) & 0x0f)]

View File

@ -22,8 +22,10 @@ struct module;
#define show_module_flags(flags) __print_flags(flags, "", \ #define show_module_flags(flags) __print_flags(flags, "", \
{ (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \ { (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \
{ (1UL << TAINT_OOT_MODULE), "O" }, \
{ (1UL << TAINT_FORCED_MODULE), "F" }, \ { (1UL << TAINT_FORCED_MODULE), "F" }, \
{ (1UL << TAINT_CRAP), "C" }) { (1UL << TAINT_CRAP), "C" }, \
{ (1UL << TAINT_UNSIGNED_MODULE), "X" })
TRACE_EVENT(module_load, TRACE_EVENT(module_load,

View File

@ -1013,6 +1013,8 @@ static size_t module_flags_taint(struct module *mod, char *buf)
buf[l++] = 'F'; buf[l++] = 'F';
if (mod->taints & (1 << TAINT_CRAP)) if (mod->taints & (1 << TAINT_CRAP))
buf[l++] = 'C'; buf[l++] = 'C';
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
buf[l++] = 'X';
/* /*
* TAINT_FORCED_RMMOD: could be added. * TAINT_FORCED_RMMOD: could be added.
* TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
@ -3214,7 +3216,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
pr_notice_once("%s: module verification failed: signature " pr_notice_once("%s: module verification failed: signature "
"and/or required key missing - tainting " "and/or required key missing - tainting "
"kernel\n", mod->name); "kernel\n", mod->name);
add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK); add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
} }
#endif #endif

View File

@ -210,6 +210,7 @@ static const struct tnt tnts[] = {
{ TAINT_CRAP, 'C', ' ' }, { TAINT_CRAP, 'C', ' ' },
{ TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
{ TAINT_OOT_MODULE, 'O', ' ' }, { TAINT_OOT_MODULE, 'O', ' ' },
{ TAINT_UNSIGNED_MODULE, 'X', ' ' },
}; };
/** /**
@ -228,6 +229,7 @@ static const struct tnt tnts[] = {
* 'C' - modules from drivers/staging are loaded. * 'C' - modules from drivers/staging are loaded.
* 'I' - Working around severe firmware bug. * 'I' - Working around severe firmware bug.
* 'O' - Out-of-tree module has been loaded. * 'O' - Out-of-tree module has been loaded.
* 'X' - Unsigned module has been loaded.
* *
* The string is overwritten by the next call to print_tainted(). * The string is overwritten by the next call to print_tainted().
*/ */

View File

@ -633,7 +633,8 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
bool trace_module_has_bad_taint(struct module *mod) bool trace_module_has_bad_taint(struct module *mod)
{ {
return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)); return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) |
(1 << TAINT_UNSIGNED_MODULE));
} }
static int tracepoint_module_coming(struct module *mod) static int tracepoint_module_coming(struct module *mod)
@ -644,7 +645,7 @@ static int tracepoint_module_coming(struct module *mod)
/* /*
* We skip modules that taint the kernel, especially those with different * We skip modules that taint the kernel, especially those with different
* module headers (for forced load), to make sure we don't cause a crash. * module headers (for forced load), to make sure we don't cause a crash.
* Staging and out-of-tree GPL modules are fine. * Staging, out-of-tree, and unsigned GPL modules are fine.
*/ */
if (trace_module_has_bad_taint(mod)) if (trace_module_has_bad_taint(mod))
return 0; return 0;