Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andi Kleen and committed by
Linus Torvalds
25ddbb18 889d51a1

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