aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <andi@firstfloor.org>2008-10-16 01:01:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 14:21:31 -0400
commit25ddbb18aae33ad255eb9f35aacebe3af01e1e9c (patch)
tree8df1f840a226ed640c2096710b7d0f1f4d1b88aa
parent889d51a10712b6fd6175196626de2116858394f4 (diff)
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: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/kernel/smpboot.c14
-rw-r--r--include/linux/kernel.h25
-rw-r--r--kernel/module.c12
-rw-r--r--kernel/panic.c63
-rw-r--r--kernel/softlockup.c2
-rw-r--r--kernel/sysctl.c67
6 files changed, 101 insertions, 82 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 8c3aca7cb343..7ed9e070a6e9 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -282,6 +282,8 @@ static void __cpuinit smp_callin(void)
282 cpu_set(cpuid, cpu_callin_map); 282 cpu_set(cpuid, cpu_callin_map);
283} 283}
284 284
285static int __cpuinitdata unsafe_smp;
286
285/* 287/*
286 * Activate a secondary processor. 288 * Activate a secondary processor.
287 */ 289 */
@@ -397,7 +399,7 @@ static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
397 goto valid_k7; 399 goto valid_k7;
398 400
399 /* If we get here, not a certified SMP capable AMD system. */ 401 /* If we get here, not a certified SMP capable AMD system. */
400 add_taint(TAINT_UNSAFE_SMP); 402 unsafe_smp = 1;
401 } 403 }
402 404
403valid_k7: 405valid_k7:
@@ -414,12 +416,10 @@ static void __cpuinit smp_checks(void)
414 * Don't taint if we are running SMP kernel on a single non-MP 416 * Don't taint if we are running SMP kernel on a single non-MP
415 * approved Athlon 417 * approved Athlon
416 */ 418 */
417 if (tainted & TAINT_UNSAFE_SMP) { 419 if (unsafe_smp && num_online_cpus() > 1) {
418 if (num_online_cpus()) 420 printk(KERN_INFO "WARNING: This combination of AMD"
419 printk(KERN_INFO "WARNING: This combination of AMD" 421 "processors is not suitable for SMP.\n");
420 "processors is not suitable for SMP.\n"); 422 add_taint(TAINT_UNSAFE_SMP);
421 else
422 tainted &= ~TAINT_UNSAFE_SMP;
423 } 423 }
424} 424}
425 425
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 75d81f157d2e..e971c55f45ac 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -235,9 +235,10 @@ extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in
235extern int panic_timeout; 235extern int panic_timeout;
236extern int panic_on_oops; 236extern int panic_on_oops;
237extern int panic_on_unrecovered_nmi; 237extern int panic_on_unrecovered_nmi;
238extern int tainted;
239extern const char *print_tainted(void); 238extern const char *print_tainted(void);
240extern void add_taint(unsigned); 239extern void add_taint(unsigned flag);
240extern int test_taint(unsigned flag);
241extern unsigned long get_taint(void);
241extern int root_mountflags; 242extern int root_mountflags;
242 243
243/* Values used for system_state */ 244/* Values used for system_state */
@@ -250,16 +251,16 @@ extern enum system_states {
250 SYSTEM_SUSPEND_DISK, 251 SYSTEM_SUSPEND_DISK,
251} system_state; 252} system_state;
252 253
253#define TAINT_PROPRIETARY_MODULE (1<<0) 254#define TAINT_PROPRIETARY_MODULE 0
254#define TAINT_FORCED_MODULE (1<<1) 255#define TAINT_FORCED_MODULE 1
255#define TAINT_UNSAFE_SMP (1<<2) 256#define TAINT_UNSAFE_SMP 2
256#define TAINT_FORCED_RMMOD (1<<3) 257#define TAINT_FORCED_RMMOD 3
257#define TAINT_MACHINE_CHECK (1<<4) 258#define TAINT_MACHINE_CHECK 4
258#define TAINT_BAD_PAGE (1<<5) 259#define TAINT_BAD_PAGE 5
259#define TAINT_USER (1<<6) 260#define TAINT_USER 6
260#define TAINT_DIE (1<<7) 261#define TAINT_DIE 7
261#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8) 262#define TAINT_OVERRIDDEN_ACPI_TABLE 8
262#define TAINT_WARN (1<<9) 263#define TAINT_WARN 9
263 264
264extern void dump_stack(void) __cold; 265extern void dump_stack(void) __cold;
265 266
diff --git a/kernel/module.c b/kernel/module.c
index 9db11911e04b..dd9ac6ad5cb9 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -100,7 +100,7 @@ static inline int strong_try_module_get(struct module *mod)
100static inline void add_taint_module(struct module *mod, unsigned flag) 100static inline void add_taint_module(struct module *mod, unsigned flag)
101{ 101{
102 add_taint(flag); 102 add_taint(flag);
103 mod->taints |= flag; 103 mod->taints |= (1U << flag);
104} 104}
105 105
106/* 106/*
@@ -923,7 +923,7 @@ static const char vermagic[] = VERMAGIC_STRING;
923static int try_to_force_load(struct module *mod, const char *symname) 923static int try_to_force_load(struct module *mod, const char *symname)
924{ 924{
925#ifdef CONFIG_MODULE_FORCE_LOAD 925#ifdef CONFIG_MODULE_FORCE_LOAD
926 if (!(tainted & TAINT_FORCED_MODULE)) 926 if (!test_taint(TAINT_FORCED_MODULE))
927 printk("%s: no version for \"%s\" found: kernel tainted.\n", 927 printk("%s: no version for \"%s\" found: kernel tainted.\n",
928 mod->name, symname); 928 mod->name, symname);
929 add_taint_module(mod, TAINT_FORCED_MODULE); 929 add_taint_module(mod, TAINT_FORCED_MODULE);
@@ -1033,7 +1033,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
1033 const unsigned long *crc; 1033 const unsigned long *crc;
1034 1034
1035 ret = find_symbol(name, &owner, &crc, 1035 ret = find_symbol(name, &owner, &crc,
1036 !(mod->taints & TAINT_PROPRIETARY_MODULE), true); 1036 !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
1037 if (!IS_ERR_VALUE(ret)) { 1037 if (!IS_ERR_VALUE(ret)) {
1038 /* use_module can fail due to OOM, 1038 /* use_module can fail due to OOM,
1039 or module initialization or unloading */ 1039 or module initialization or unloading */
@@ -1634,7 +1634,7 @@ static void set_license(struct module *mod, const char *license)
1634 license = "unspecified"; 1634 license = "unspecified";
1635 1635
1636 if (!license_is_gpl_compatible(license)) { 1636 if (!license_is_gpl_compatible(license)) {
1637 if (!(tainted & TAINT_PROPRIETARY_MODULE)) 1637 if (!test_taint(TAINT_PROPRIETARY_MODULE))
1638 printk(KERN_WARNING "%s: module license '%s' taints " 1638 printk(KERN_WARNING "%s: module license '%s' taints "
1639 "kernel.\n", mod->name, license); 1639 "kernel.\n", mod->name, license);
1640 add_taint_module(mod, TAINT_PROPRIETARY_MODULE); 1640 add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
@@ -2552,9 +2552,9 @@ static char *module_flags(struct module *mod, char *buf)
2552 mod->state == MODULE_STATE_GOING || 2552 mod->state == MODULE_STATE_GOING ||
2553 mod->state == MODULE_STATE_COMING) { 2553 mod->state == MODULE_STATE_COMING) {
2554 buf[bx++] = '('; 2554 buf[bx++] = '(';
2555 if (mod->taints & TAINT_PROPRIETARY_MODULE) 2555 if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
2556 buf[bx++] = 'P'; 2556 buf[bx++] = 'P';
2557 if (mod->taints & TAINT_FORCED_MODULE) 2557 if (mod->taints & (1 << TAINT_FORCED_MODULE))
2558 buf[bx++] = 'F'; 2558 buf[bx++] = 'F';
2559 /* 2559 /*
2560 * TAINT_FORCED_RMMOD: could be added. 2560 * TAINT_FORCED_RMMOD: could be added.
diff --git a/kernel/panic.c b/kernel/panic.c
index 12c5a0a6c89b..028013f7afd4 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -23,7 +23,7 @@
23#include <linux/kallsyms.h> 23#include <linux/kallsyms.h>
24 24
25int panic_on_oops; 25int panic_on_oops;
26int tainted; 26static unsigned long tainted_mask;
27static int pause_on_oops; 27static int pause_on_oops;
28static int pause_on_oops_flag; 28static int pause_on_oops_flag;
29static DEFINE_SPINLOCK(pause_on_oops_lock); 29static DEFINE_SPINLOCK(pause_on_oops_lock);
@@ -159,31 +159,60 @@ EXPORT_SYMBOL(panic);
159 * The string is overwritten by the next call to print_taint(). 159 * The string is overwritten by the next call to print_taint().
160 */ 160 */
161 161
162struct tnt {
163 u8 bit;
164 char true;
165 char false;
166};
167
168static const struct tnt tnts[] = {
169 { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
170 { TAINT_FORCED_MODULE, 'F', ' ' },
171 { TAINT_UNSAFE_SMP, 'S', ' ' },
172 { TAINT_FORCED_RMMOD, 'R', ' ' },
173 { TAINT_MACHINE_CHECK, 'M', ' ' },
174 { TAINT_BAD_PAGE, 'B', ' ' },
175 { TAINT_USER, 'U', ' ' },
176 { TAINT_DIE, 'D', ' ' },
177 { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
178 { TAINT_WARN, 'W', ' ' },
179};
180
162const char *print_tainted(void) 181const char *print_tainted(void)
163{ 182{
164 static char buf[20]; 183 static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ") + 1];
165 if (tainted) { 184
166 snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c", 185 if (tainted_mask) {
167 tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', 186 char *s;
168 tainted & TAINT_FORCED_MODULE ? 'F' : ' ', 187 int i;
169 tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', 188
170 tainted & TAINT_FORCED_RMMOD ? 'R' : ' ', 189 s = buf + sprintf(buf, "Tainted: ");
171 tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', 190 for (i = 0; i < ARRAY_SIZE(tnts); i++) {
172 tainted & TAINT_BAD_PAGE ? 'B' : ' ', 191 const struct tnt *t = &tnts[i];
173 tainted & TAINT_USER ? 'U' : ' ', 192 *s++ = test_bit(t->bit, &tainted_mask) ?
174 tainted & TAINT_DIE ? 'D' : ' ', 193 t->true : t->false;
175 tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ', 194 }
176 tainted & TAINT_WARN ? 'W' : ' '); 195 *s = 0;
177 } 196 } else
178 else
179 snprintf(buf, sizeof(buf), "Not tainted"); 197 snprintf(buf, sizeof(buf), "Not tainted");
180 return(buf); 198 return(buf);
181} 199}
182 200
201int test_taint(unsigned flag)
202{
203 return test_bit(flag, &tainted_mask);
204}
205EXPORT_SYMBOL(test_taint);
206
207unsigned long get_taint(void)
208{
209 return tainted_mask;
210}
211
183void add_taint(unsigned flag) 212void add_taint(unsigned flag)
184{ 213{
185 debug_locks = 0; /* can't trust the integrity of the kernel anymore */ 214 debug_locks = 0; /* can't trust the integrity of the kernel anymore */
186 tainted |= flag; 215 set_bit(flag, &tainted_mask);
187} 216}
188EXPORT_SYMBOL(add_taint); 217EXPORT_SYMBOL(add_taint);
189 218
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index cb838ee93a82..3953e4aed733 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -226,7 +226,7 @@ static void check_hung_uninterruptible_tasks(int this_cpu)
226 * If the system crashed already then all bets are off, 226 * If the system crashed already then all bets are off,
227 * do not report extra hung tasks: 227 * do not report extra hung tasks:
228 */ 228 */
229 if ((tainted & TAINT_DIE) || did_panic) 229 if (test_taint(TAINT_DIE) || did_panic)
230 return; 230 return;
231 231
232 read_lock(&tasklist_lock); 232 read_lock(&tasklist_lock);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index cfc5295f1e82..ec88fcc9a0d2 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -149,7 +149,7 @@ extern int max_lock_depth;
149#ifdef CONFIG_PROC_SYSCTL 149#ifdef CONFIG_PROC_SYSCTL
150static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp, 150static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp,
151 void __user *buffer, size_t *lenp, loff_t *ppos); 151 void __user *buffer, size_t *lenp, loff_t *ppos);
152static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp, 152static int proc_taint(struct ctl_table *table, int write, struct file *filp,
153 void __user *buffer, size_t *lenp, loff_t *ppos); 153 void __user *buffer, size_t *lenp, loff_t *ppos);
154#endif 154#endif
155 155
@@ -379,10 +379,9 @@ static struct ctl_table kern_table[] = {
379#ifdef CONFIG_PROC_SYSCTL 379#ifdef CONFIG_PROC_SYSCTL
380 { 380 {
381 .procname = "tainted", 381 .procname = "tainted",
382 .data = &tainted, 382 .maxlen = sizeof(long),
383 .maxlen = sizeof(int),
384 .mode = 0644, 383 .mode = 0644,
385 .proc_handler = &proc_dointvec_taint, 384 .proc_handler = &proc_taint,
386 }, 385 },
387#endif 386#endif
388#ifdef CONFIG_LATENCYTOP 387#ifdef CONFIG_LATENCYTOP
@@ -2228,49 +2227,39 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp,
2228 NULL,NULL); 2227 NULL,NULL);
2229} 2228}
2230 2229
2231#define OP_SET 0
2232#define OP_AND 1
2233#define OP_OR 2
2234
2235static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
2236 int *valp,
2237 int write, void *data)
2238{
2239 int op = *(int *)data;
2240 if (write) {
2241 int val = *negp ? -*lvalp : *lvalp;
2242 switch(op) {
2243 case OP_SET: *valp = val; break;
2244 case OP_AND: *valp &= val; break;
2245 case OP_OR: *valp |= val; break;
2246 }
2247 } else {
2248 int val = *valp;
2249 if (val < 0) {
2250 *negp = -1;
2251 *lvalp = (unsigned long)-val;
2252 } else {
2253 *negp = 0;
2254 *lvalp = (unsigned long)val;
2255 }
2256 }
2257 return 0;
2258}
2259
2260/* 2230/*
2261 * Taint values can only be increased 2231 * Taint values can only be increased
2232 * This means we can safely use a temporary.
2262 */ 2233 */
2263static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp, 2234static int proc_taint(struct ctl_table *table, int write, struct file *filp,
2264 void __user *buffer, size_t *lenp, loff_t *ppos) 2235 void __user *buffer, size_t *lenp, loff_t *ppos)
2265{ 2236{
2266 int op; 2237 struct ctl_table t;
2238 unsigned long tmptaint = get_taint();
2239 int err;
2267 2240
2268 if (write && !capable(CAP_SYS_ADMIN)) 2241 if (write && !capable(CAP_SYS_ADMIN))
2269 return -EPERM; 2242 return -EPERM;
2270 2243
2271 op = OP_OR; 2244 t = *table;
2272 return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, 2245 t.data = &tmptaint;
2273 do_proc_dointvec_bset_conv,&op); 2246 err = proc_doulongvec_minmax(&t, write, filp, buffer, lenp, ppos);
2247 if (err < 0)
2248 return err;
2249
2250 if (write) {
2251 /*
2252 * Poor man's atomic or. Not worth adding a primitive
2253 * to everyone's atomic.h for this
2254 */
2255 int i;
2256 for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) {
2257 if ((tmptaint >> i) & 1)
2258 add_taint(i);
2259 }
2260 }
2261
2262 return err;
2274} 2263}
2275 2264
2276struct do_proc_dointvec_minmax_conv_param { 2265struct do_proc_dointvec_minmax_conv_param {