Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25ddbb18 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds
Browse files

Make the taint flags reliable



It's somewhat unlikely that it happens, but right now a race window
between interrupts or machine checks or oopses could corrupt the tainted
bitmap because it is modified in a non atomic fashion.

Convert the taint variable to an unsigned long and use only atomic bit
operations on it.

Unfortunately this means the intvec sysctl functions cannot be used on it
anymore.

It turned out the taint sysctl handler could actually be simplified a bit
(since it only increases capabilities) so this patch actually removes
code.

[akpm@linux-foundation.org: remove unneeded include]
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 889d51a1
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -282,6 +282,8 @@ static void __cpuinit smp_callin(void)
	cpu_set(cpuid, cpu_callin_map);
}

static int __cpuinitdata unsafe_smp;

/*
 * Activate a secondary processor.
 */
@@ -397,7 +399,7 @@ static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
				goto valid_k7;

		/* If we get here, not a certified SMP capable AMD system. */
		add_taint(TAINT_UNSAFE_SMP);
		unsafe_smp = 1;
	}

valid_k7:
@@ -414,12 +416,10 @@ static void __cpuinit smp_checks(void)
	 * Don't taint if we are running SMP kernel on a single non-MP
	 * approved Athlon
	 */
	if (tainted & TAINT_UNSAFE_SMP) {
		if (num_online_cpus())
	if (unsafe_smp && num_online_cpus() > 1) {
		printk(KERN_INFO "WARNING: This combination of AMD"
			"processors is not suitable for SMP.\n");
		else
			tainted &= ~TAINT_UNSAFE_SMP;
		add_taint(TAINT_UNSAFE_SMP);
	}
}

+13 −12
Original line number Diff line number Diff line
@@ -235,9 +235,10 @@ extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in
extern int panic_timeout;
extern int panic_on_oops;
extern int panic_on_unrecovered_nmi;
extern int tainted;
extern const char *print_tainted(void);
extern void add_taint(unsigned);
extern void add_taint(unsigned flag);
extern int test_taint(unsigned flag);
extern unsigned long get_taint(void);
extern int root_mountflags;

/* Values used for system_state */
@@ -250,16 +251,16 @@ extern enum system_states {
	SYSTEM_SUSPEND_DISK,
} system_state;

#define TAINT_PROPRIETARY_MODULE	(1<<0)
#define TAINT_FORCED_MODULE		(1<<1)
#define TAINT_UNSAFE_SMP		(1<<2)
#define TAINT_FORCED_RMMOD		(1<<3)
#define TAINT_MACHINE_CHECK		(1<<4)
#define TAINT_BAD_PAGE			(1<<5)
#define TAINT_USER			(1<<6)
#define TAINT_DIE			(1<<7)
#define TAINT_OVERRIDDEN_ACPI_TABLE	(1<<8)
#define TAINT_WARN			(1<<9)
#define TAINT_PROPRIETARY_MODULE	0
#define TAINT_FORCED_MODULE		1
#define TAINT_UNSAFE_SMP		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

extern void dump_stack(void) __cold;

+6 −6
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ static inline int strong_try_module_get(struct module *mod)
static inline void add_taint_module(struct module *mod, unsigned flag)
{
	add_taint(flag);
	mod->taints |= flag;
	mod->taints |= (1U << flag);
}

/*
@@ -923,7 +923,7 @@ static const char vermagic[] = VERMAGIC_STRING;
static int try_to_force_load(struct module *mod, const char *symname)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
	if (!(tainted & TAINT_FORCED_MODULE))
	if (!test_taint(TAINT_FORCED_MODULE))
		printk("%s: no version for \"%s\" found: kernel tainted.\n",
		       mod->name, symname);
	add_taint_module(mod, TAINT_FORCED_MODULE);
@@ -1033,7 +1033,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
	const unsigned long *crc;

	ret = find_symbol(name, &owner, &crc,
			  !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
			  !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
	if (!IS_ERR_VALUE(ret)) {
		/* use_module can fail due to OOM,
		   or module initialization or unloading */
@@ -1634,7 +1634,7 @@ static void set_license(struct module *mod, const char *license)
		license = "unspecified";

	if (!license_is_gpl_compatible(license)) {
		if (!(tainted & TAINT_PROPRIETARY_MODULE))
		if (!test_taint(TAINT_PROPRIETARY_MODULE))
			printk(KERN_WARNING "%s: module license '%s' taints "
				"kernel.\n", mod->name, license);
		add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
@@ -2552,9 +2552,9 @@ static char *module_flags(struct module *mod, char *buf)
	    mod->state == MODULE_STATE_GOING ||
	    mod->state == MODULE_STATE_COMING) {
		buf[bx++] = '(';
		if (mod->taints & TAINT_PROPRIETARY_MODULE)
		if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
			buf[bx++] = 'P';
		if (mod->taints & TAINT_FORCED_MODULE)
		if (mod->taints & (1 << TAINT_FORCED_MODULE))
			buf[bx++] = 'F';
		/*
		 * TAINT_FORCED_RMMOD: could be added.
+46 −17
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@
#include <linux/kallsyms.h>

int panic_on_oops;
int tainted;
static unsigned long tainted_mask;
static int pause_on_oops;
static int pause_on_oops_flag;
static DEFINE_SPINLOCK(pause_on_oops_lock);
@@ -159,31 +159,60 @@ EXPORT_SYMBOL(panic);
 *	The string is overwritten by the next call to print_taint().
 */

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

static const struct tnt tnts[] = {
	{ TAINT_PROPRIETARY_MODULE, 'P', 'G' },
	{ TAINT_FORCED_MODULE, 'F', ' ' },
	{ TAINT_UNSAFE_SMP, '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', ' ' },
};

const char *print_tainted(void)
{
	static char buf[20];
	if (tainted) {
		snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c",
			tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
			tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
			tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
			tainted & TAINT_FORCED_RMMOD ? 'R' : ' ',
			tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
			tainted & TAINT_BAD_PAGE ? 'B' : ' ',
			tainted & TAINT_USER ? 'U' : ' ',
			tainted & TAINT_DIE ? 'D' : ' ',
			tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ',
			tainted & TAINT_WARN ? 'W' : ' ');
	static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ") + 1];

	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) ?
					t->true : t->false;
		}
	else
		*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;
}

void add_taint(unsigned flag)
{
	debug_locks = 0; /* can't trust the integrity of the kernel anymore */
	tainted |= flag;
	set_bit(flag, &tainted_mask);
}
EXPORT_SYMBOL(add_taint);

+1 −1
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ static void check_hung_uninterruptible_tasks(int this_cpu)
	 * If the system crashed already then all bets are off,
	 * do not report extra hung tasks:
	 */
	if ((tainted & TAINT_DIE) || did_panic)
	if (test_taint(TAINT_DIE) || did_panic)
		return;

	read_lock(&tasklist_lock);
Loading