Skip to content

Commit

Permalink
taint/module: Clean up global and module taint flags handling
Browse files Browse the repository at this point in the history
The commit 66cc69e ("Fix: module signature vs tracepoints:
add new TAINT_UNSIGNED_MODULE") updated module_taint_flags() to
potentially print one more character. But it did not increase the
size of the corresponding buffers in m_show() and print_modules().

We have recently done the same mistake when adding a taint flag
for livepatching, see
https://lkml.kernel.org/r/cfba2c823bb984690b73572aaae1db596b54a082.1472137475.git.jpoimboe@redhat.com

Also struct module uses an incompatible type for mod-taints flags.
It survived from the commit 2bc2d61 ("[PATCH] list module
taint flags in Oops/panic"). There was used "int" for the global taint
flags at these times. But only the global tain flags was later changed
to "unsigned long" by the commit 25ddbb1 ("Make the taint
flags reliable").

This patch defines TAINT_FLAGS_COUNT that can be used to create
arrays and buffers of the right size. Note that we could not use
enum because the taint flag indexes are used also in assembly code.

Then it reworks the table that describes the taint flags. The TAINT_*
numbers can be used as the index. Instead, we add information
if the taint flag is also shown per-module.

Finally, it uses "unsigned long", bit operations, and the updated
taint_flags table also for mod->taints.

It is not optimal because only few taint flags can be printed by
module_taint_flags(). But better be on the safe side. IMHO, it is
not worth the optimization and this is a good compromise.

Signed-off-by: Petr Mladek <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[[email protected]: fix broken lkml link in changelog]
Signed-off-by: Jessica Yu <[email protected]>
  • Loading branch information
pmladek authored and Jessica Yu committed Nov 26, 2016
1 parent c7d47f2 commit 7fd8329
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 49 deletions.
9 changes: 9 additions & 0 deletions include/linux/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,15 @@ extern enum system_states {
#define TAINT_UNSIGNED_MODULE 13
#define TAINT_SOFTLOCKUP 14
#define TAINT_LIVEPATCH 15
#define TAINT_FLAGS_COUNT 16

struct taint_flag {
char true; /* character printed when tainted */
char 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];

extern const char hex_asc[];
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
Expand Down
2 changes: 1 addition & 1 deletion include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ struct module {
/* Arch-specific module values */
struct mod_arch_specific arch;

unsigned int taints; /* same bits as kernel:tainted */
unsigned long taints; /* same bits as kernel:taint_flags */

#ifdef CONFIG_GENERIC_BUG
/* Support for BUG */
Expand Down
33 changes: 13 additions & 20 deletions kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,
enum lockdep_ok lockdep_ok)
{
add_taint(flag, lockdep_ok);
mod->taints |= (1U << flag);
set_bit(flag, &mod->taints);
}

/*
Expand Down Expand Up @@ -1138,24 +1138,13 @@ static inline int module_unload_init(struct module *mod)
static size_t module_flags_taint(struct module *mod, char *buf)
{
size_t l = 0;
int i;

for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
if (taint_flags[i].module && test_bit(i, &mod->taints))
buf[l++] = taint_flags[i].true;
}

if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
buf[l++] = 'P';
if (mod->taints & (1 << TAINT_OOT_MODULE))
buf[l++] = 'O';
if (mod->taints & (1 << TAINT_FORCED_MODULE))
buf[l++] = 'F';
if (mod->taints & (1 << TAINT_CRAP))
buf[l++] = 'C';
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
buf[l++] = 'E';
if (mod->taints & (1 << TAINT_LIVEPATCH))
buf[l++] = 'K';
/*
* TAINT_FORCED_RMMOD: could be added.
* TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
* apply to modules.
*/
return l;
}

Expand Down Expand Up @@ -4041,6 +4030,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
}
#endif /* CONFIG_KALLSYMS */

/* Maximum number of characters written by module_flags() */
#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)

/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
static char *module_flags(struct module *mod, char *buf)
{
int bx = 0;
Expand Down Expand Up @@ -4085,7 +4078,7 @@ static void m_stop(struct seq_file *m, void *p)
static int m_show(struct seq_file *m, void *p)
{
struct module *mod = list_entry(p, struct module, list);
char buf[8];
char buf[MODULE_FLAGS_BUF_SIZE];

/* We always ignore unformed modules. */
if (mod->state == MODULE_STATE_UNFORMED)
Expand Down Expand Up @@ -4256,7 +4249,7 @@ EXPORT_SYMBOL_GPL(__module_text_address);
void print_modules(void)
{
struct module *mod;
char buf[8];
char buf[MODULE_FLAGS_BUF_SIZE];

printk(KERN_DEFAULT "Modules linked in:");
/* Most callers should already have preempt disabled, but make sure */
Expand Down
53 changes: 25 additions & 28 deletions kernel/panic.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,30 +298,27 @@ void panic(const char *fmt, ...)

EXPORT_SYMBOL(panic);


struct tnt {
u8 bit;
char true;
char false;
};

static const struct tnt tnts[] = {
{ TAINT_PROPRIETARY_MODULE, 'P', 'G' },
{ TAINT_FORCED_MODULE, 'F', ' ' },
{ TAINT_CPU_OUT_OF_SPEC, 'S', ' ' },
{ TAINT_FORCED_RMMOD, 'R', ' ' },
{ TAINT_MACHINE_CHECK, 'M', ' ' },
{ TAINT_BAD_PAGE, 'B', ' ' },
{ TAINT_USER, 'U', ' ' },
{ TAINT_DIE, 'D', ' ' },
{ TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
{ TAINT_WARN, 'W', ' ' },
{ TAINT_CRAP, 'C', ' ' },
{ TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
{ TAINT_OOT_MODULE, 'O', ' ' },
{ TAINT_UNSIGNED_MODULE, 'E', ' ' },
{ TAINT_SOFTLOCKUP, 'L', ' ' },
{ TAINT_LIVEPATCH, 'K', ' ' },
/*
* 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] = {
{ 'P', 'G', true }, /* TAINT_PROPRIETARY_MODULE */
{ 'F', ' ', true }, /* TAINT_FORCED_MODULE */
{ 'S', ' ', false }, /* TAINT_CPU_OUT_OF_SPEC */
{ 'R', ' ', false }, /* TAINT_FORCED_RMMOD */
{ 'M', ' ', false }, /* TAINT_MACHINE_CHECK */
{ 'B', ' ', false }, /* TAINT_BAD_PAGE */
{ 'U', ' ', false }, /* TAINT_USER */
{ 'D', ' ', false }, /* TAINT_DIE */
{ 'A', ' ', false }, /* TAINT_OVERRIDDEN_ACPI_TABLE */
{ 'W', ' ', false }, /* TAINT_WARN */
{ 'C', ' ', true }, /* TAINT_CRAP */
{ 'I', ' ', false }, /* TAINT_FIRMWARE_WORKAROUND */
{ 'O', ' ', true }, /* TAINT_OOT_MODULE */
{ 'E', ' ', true }, /* TAINT_UNSIGNED_MODULE */
{ 'L', ' ', false }, /* TAINT_SOFTLOCKUP */
{ 'K', ' ', true }, /* TAINT_LIVEPATCH */
};

/**
Expand All @@ -348,16 +345,16 @@ static const struct tnt tnts[] = {
*/
const char *print_tainted(void)
{
static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ")];
static char buf[TAINT_FLAGS_COUNT + sizeof("Tainted: ")];

if (tainted_mask) {
char *s;
int i;

s = buf + sprintf(buf, "Tainted: ");
for (i = 0; i < ARRAY_SIZE(tnts); i++) {
const struct tnt *t = &tnts[i];
*s++ = test_bit(t->bit, &tainted_mask) ?
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
const struct taint_flag *t = &taint_flags[i];
*s++ = test_bit(i, &tainted_mask) ?
t->true : t->false;
}
*s = 0;
Expand Down

0 comments on commit 7fd8329

Please sign in to comment.