History

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. [akpm@linux-foundation.org: tweak kernel-parameters.txt wording]

Rafael Aquini committed 6 years ago

Commit db38d5c1 parent ceabef76 files · +75 −1Browse files

Unified · Split

6 files
  1. Documentation/admin-guide/kdump/kdump.rst +8 −0
  2. Documentation/admin-guide/kernel-parameters.txt +13 −0
  3. Documentation/admin-guide/sysctl/kernel.rst +7 −0
  4. include/linux/kernel.h +3 −0
  5. kernel/panic.c +34 −0
  6. kernel/sysctl.c +10 −1
Documentation/admin-guide/kdump/kdump.rst+8−0
@@ -521,6 +521,14 @@ will cause a kdump to occur at the panic() call. In cases where a user wants · 520 unmodified lines
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+13−0
@@ -3447,6 +3447,19 @@ · 3446 unmodified lines
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+7−0
@@ -1239,6 +1239,13 @@ ORed together. The letters are seen in "Tainted" line of Oops reports. · 1238 unmodified lines
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+3−0
@@ -528,6 +528,8 @@ extern int panic_on_oops; · 527 unmodified lines
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 { · 62 unmodified lines
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+34−0
@@ -44,6 +44,8 @@ static int pause_on_oops_flag; · 43 unmodified lines
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) · 384 unmodified lines
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) · 246 unmodified lines
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+10−1
@@ -866,11 +866,20 @@ static int proc_taint(struct ctl_table *table, int write, · 865 unmodified lines
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);