Commit 25ddbb18aae33ad255eb9f35aacebe3af01e1e9c

Authored by Andi Kleen
Committed by Linus Torvalds
1 parent 889d51a107

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>

Showing 6 changed files with 101 additions and 82 deletions Side-by-side Diff

arch/x86/kernel/smpboot.c
... ... @@ -282,6 +282,8 @@
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 */
... ... @@ -397,7 +399,7 @@
397 399 goto valid_k7;
398 400  
399 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  
403 405 valid_k7:
... ... @@ -414,12 +416,10 @@
414 416 * Don't taint if we are running SMP kernel on a single non-MP
415 417 * approved Athlon
416 418 */
417   - if (tainted & TAINT_UNSAFE_SMP) {
418   - if (num_online_cpus())
419   - printk(KERN_INFO "WARNING: This combination of AMD"
420   - "processors is not suitable for SMP.\n");
421   - else
422   - tainted &= ~TAINT_UNSAFE_SMP;
  419 + if (unsafe_smp && num_online_cpus() > 1) {
  420 + printk(KERN_INFO "WARNING: This combination of AMD"
  421 + "processors is not suitable for SMP.\n");
  422 + add_taint(TAINT_UNSAFE_SMP);
423 423 }
424 424 }
425 425  
include/linux/kernel.h
... ... @@ -235,9 +235,10 @@
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 */
... ... @@ -250,16 +251,16 @@
250 251 SYSTEM_SUSPEND_DISK,
251 252 } system_state;
252 253  
253   -#define TAINT_PROPRIETARY_MODULE (1<<0)
254   -#define TAINT_FORCED_MODULE (1<<1)
255   -#define TAINT_UNSAFE_SMP (1<<2)
256   -#define TAINT_FORCED_RMMOD (1<<3)
257   -#define TAINT_MACHINE_CHECK (1<<4)
258   -#define TAINT_BAD_PAGE (1<<5)
259   -#define TAINT_USER (1<<6)
260   -#define TAINT_DIE (1<<7)
261   -#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
262   -#define TAINT_WARN (1<<9)
  254 +#define TAINT_PROPRIETARY_MODULE 0
  255 +#define TAINT_FORCED_MODULE 1
  256 +#define TAINT_UNSAFE_SMP 2
  257 +#define TAINT_FORCED_RMMOD 3
  258 +#define TAINT_MACHINE_CHECK 4
  259 +#define TAINT_BAD_PAGE 5
  260 +#define TAINT_USER 6
  261 +#define TAINT_DIE 7
  262 +#define TAINT_OVERRIDDEN_ACPI_TABLE 8
  263 +#define TAINT_WARN 9
263 264  
264 265 extern void dump_stack(void) __cold;
265 266  
... ... @@ -100,7 +100,7 @@
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,7 +923,7 @@
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,7 +1033,7 @@
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,7 +1634,7 @@
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);
1641 1641  
... ... @@ -2552,9 +2552,9 @@
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.
... ... @@ -23,7 +23,7 @@
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);
30 30  
31 31  
32 32  
... ... @@ -159,31 +159,60 @@
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);
181 199 }
182 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;
  210 +}
  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  
... ... @@ -226,7 +226,7 @@
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);
... ... @@ -149,7 +149,7 @@
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  
156 156  
... ... @@ -379,10 +379,9 @@
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
389 388  
390 389  
391 390  
392 391  
... ... @@ -2228,49 +2227,39 @@
2228 2227 NULL,NULL);
2229 2228 }
2230 2229  
2231   -#define OP_SET 0
2232   -#define OP_AND 1
2233   -#define OP_OR 2
2234   -
2235   -static 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 */
2263   -static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp,
  2234 +static int proc_taint(struct ctl_table *table, int write, struct file *filp,
2264 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 2241 if (write && !capable(CAP_SYS_ADMIN))
2269 2242 return -EPERM;
2270 2243  
2271   - op = OP_OR;
2272   - return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
2273   - do_proc_dointvec_bset_conv,&op);
  2244 + t = *table;
  2245 + t.data = &tmptaint;
  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  
2276 2265 struct do_proc_dointvec_minmax_conv_param {