Skip to content

Commit db38d5c

Browse files
aquinitorvalds
authored andcommitted
kernel: add panic_on_taint
Analogously to the introduction of panic_on_warn, this patch introduces a kernel option named panic_on_taint in order to provide a simple and generic way to stop execution and catch a coredump when the kernel gets tainted by any given flag. This is useful for debugging sessions as it avoids having to rebuild the kernel to explicitly add calls to panic() into the code sites that introduce the taint flags of interest. For instance, if one is interested in proceeding with a post-mortem analysis at the point a given code path is hitting a bad page (i.e. unaccount_page_cache_page(), or slab_bug()), a coredump can be collected by rebooting the kernel with 'panic_on_taint=0x20' amended to the command line. Another, perhaps less frequent, use for this option would be as a means for assuring a security policy case where only a subset of taints, or no single taint (in paranoid mode), is allowed for the running system. The optional switch 'nousertaint' is handy in this particular scenario, as it will avoid userspace induced crashes by writes to sysctl interface /proc/sys/kernel/tainted causing false positive hits for such policies. [[email protected]: tweak kernel-parameters.txt wording] Suggested-by: Qian Cai <[email protected]> Signed-off-by: Rafael Aquini <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Reviewed-by: Luis Chamberlain <[email protected]> Cc: Dave Young <[email protected]> Cc: Baoquan He <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Kees Cook <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: "Theodore Ts'o" <[email protected]> Cc: Adrian Bunk <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Laura Abbott <[email protected]> Cc: Jeff Mahoney <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: Takashi Iwai <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent ceabef7 commit db38d5c

File tree

6 files changed

+75
-1
lines changed

6 files changed

+75
-1
lines changed

Documentation/admin-guide/kdump/kdump.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,14 @@ will cause a kdump to occur at the panic() call. In cases where a user wants
521521
to specify this during runtime, /proc/sys/kernel/panic_on_warn can be set to 1
522522
to achieve the same behaviour.
523523

524+
Trigger Kdump on add_taint()
525+
============================
526+
527+
The kernel parameter panic_on_taint facilitates a conditional call to panic()
528+
from within add_taint() whenever the value set in this bitmask matches with the
529+
bit flag being set by add_taint().
530+
This will cause a kdump to occur at the add_taint()->panic() call.
531+
524532
Contact
525533
=======
526534

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,19 @@
34473447
bit 4: print ftrace buffer
34483448
bit 5: print all printk messages in buffer
34493449

3450+
panic_on_taint= Bitmask for conditionally calling panic() in add_taint()
3451+
Format: <hex>[,nousertaint]
3452+
Hexadecimal bitmask representing the set of TAINT flags
3453+
that will cause the kernel to panic when add_taint() is
3454+
called with any of the flags in this set.
3455+
The optional switch "nousertaint" can be utilized to
3456+
prevent userspace forced crashes by writing to sysctl
3457+
/proc/sys/kernel/tainted any flagset matching with the
3458+
bitmask set on panic_on_taint.
3459+
See Documentation/admin-guide/tainted-kernels.rst for
3460+
extra details on the taint flags that users can pick
3461+
to compose the bitmask to assign to panic_on_taint.
3462+
34503463
panic_on_warn panic() instead of WARN(). Useful to cause kdump
34513464
on a WARN().
34523465

Documentation/admin-guide/sysctl/kernel.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,13 @@ ORed together. The letters are seen in "Tainted" line of Oops reports.
12391239

12401240
See :doc:`/admin-guide/tainted-kernels` for more information.
12411241

1242+
Note:
1243+
writes to this sysctl interface will fail with ``EINVAL`` if the kernel is
1244+
booted with the command line option ``panic_on_taint=<bitmask>,nousertaint``
1245+
and any of the ORed together values being written to ``tainted`` match with
1246+
the bitmask declared on panic_on_taint.
1247+
See :doc:`/admin-guide/kernel-parameters` for more details on that particular
1248+
kernel command line option and its optional ``nousertaint`` switch.
12421249

12431250
threads-max
12441251
===========

include/linux/kernel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@ extern int panic_on_oops;
528528
extern int panic_on_unrecovered_nmi;
529529
extern int panic_on_io_nmi;
530530
extern int panic_on_warn;
531+
extern unsigned long panic_on_taint;
532+
extern bool panic_on_taint_nousertaint;
531533
extern int sysctl_panic_on_rcu_stall;
532534
extern int sysctl_panic_on_stackoverflow;
533535

@@ -596,6 +598,7 @@ extern enum system_states {
596598
#define TAINT_AUX 16
597599
#define TAINT_RANDSTRUCT 17
598600
#define TAINT_FLAGS_COUNT 18
601+
#define TAINT_FLAGS_MAX ((1UL << TAINT_FLAGS_COUNT) - 1)
599602

600603
struct taint_flag {
601604
char c_true; /* character printed when tainted */

kernel/panic.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static int pause_on_oops_flag;
4444
static DEFINE_SPINLOCK(pause_on_oops_lock);
4545
bool crash_kexec_post_notifiers;
4646
int panic_on_warn __read_mostly;
47+
unsigned long panic_on_taint;
48+
bool panic_on_taint_nousertaint = false;
4749

4850
int panic_timeout = CONFIG_PANIC_TIMEOUT;
4951
EXPORT_SYMBOL_GPL(panic_timeout);
@@ -434,6 +436,11 @@ void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
434436
pr_warn("Disabling lock debugging due to kernel taint\n");
435437

436438
set_bit(flag, &tainted_mask);
439+
440+
if (tainted_mask & panic_on_taint) {
441+
panic_on_taint = 0;
442+
panic("panic_on_taint set ...");
443+
}
437444
}
438445
EXPORT_SYMBOL(add_taint);
439446

@@ -686,3 +693,30 @@ static int __init oops_setup(char *s)
686693
return 0;
687694
}
688695
early_param("oops", oops_setup);
696+
697+
static int __init panic_on_taint_setup(char *s)
698+
{
699+
char *taint_str;
700+
701+
if (!s)
702+
return -EINVAL;
703+
704+
taint_str = strsep(&s, ",");
705+
if (kstrtoul(taint_str, 16, &panic_on_taint))
706+
return -EINVAL;
707+
708+
/* make sure panic_on_taint doesn't hold out-of-range TAINT flags */
709+
panic_on_taint &= TAINT_FLAGS_MAX;
710+
711+
if (!panic_on_taint)
712+
return -EINVAL;
713+
714+
if (s && !strcmp(s, "nousertaint"))
715+
panic_on_taint_nousertaint = true;
716+
717+
pr_info("panic_on_taint: bitmask=0x%lx nousertaint_mode=%sabled\n",
718+
panic_on_taint, panic_on_taint_nousertaint ? "en" : "dis");
719+
720+
return 0;
721+
}
722+
early_param("panic_on_taint", panic_on_taint_setup);

kernel/sysctl.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,11 +866,20 @@ static int proc_taint(struct ctl_table *table, int write,
866866
return err;
867867

868868
if (write) {
869+
int i;
870+
871+
/*
872+
* If we are relying on panic_on_taint not producing
873+
* false positives due to userspace input, bail out
874+
* before setting the requested taint flags.
875+
*/
876+
if (panic_on_taint_nousertaint && (tmptaint & panic_on_taint))
877+
return -EINVAL;
878+
869879
/*
870880
* Poor man's atomic or. Not worth adding a primitive
871881
* to everyone's atomic.h for this
872882
*/
873-
int i;
874883
for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) {
875884
if ((tmptaint >> i) & 1)
876885
add_taint(i, LOCKDEP_STILL_OK);

0 commit comments

Comments
 (0)