| From 4623305d0a2c5bf624f0bc70787b6115b3fce5f6 Mon Sep 17 00:00:00 2001 |
| From: Kees Cook <keescook@chromium.org> |
| Date: Wed, 25 Sep 2019 16:48:11 -0700 |
| Subject: [PATCH] bug: move WARN_ON() "cut here" into exception handler |
| |
| commit a44f71a9ab99b509fec9d5a9f5c222debd89934f upstream. |
| |
| The original clean up of "cut here" missed the WARN_ON() case (that does |
| not have a printk message), which was fixed recently by adding an explicit |
| printk of "cut here". This had the downside of adding a printk() to every |
| WARN_ON() caller, which reduces the utility of using an instruction |
| exception to streamline the resulting code. By making this a new BUGFLAG, |
| all of these can be removed and "cut here" can be handled by the exception |
| handler. |
| |
| This was very pronounced on PowerPC, but the effect can be seen on x86 as |
| well. The resulting text size of a defconfig build shows some small |
| savings from this patch: |
| |
| text data bss dec hex filename |
| 19691167 5134320 1646664 26472151 193eed7 vmlinux.before |
| 19676362 5134260 1663048 26473670 193f4c6 vmlinux.after |
| |
| This change also opens the door for creating something like BUG_MSG(), |
| where a custom printk() before issuing BUG(), without confusing the "cut |
| here" line. |
| |
| Link: http://lkml.kernel.org/r/201908200943.601DD59DCE@keescook |
| Fixes: 6b15f678fb7d ("include/asm-generic/bug.h: fix "cut here" for WARN_ON for __WARN_TAINT architectures") |
| Signed-off-by: Kees Cook <keescook@chromium.org> |
| Reported-by: Christophe Leroy <christophe.leroy@c-s.fr> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Christophe Leroy <christophe.leroy@c-s.fr> |
| Cc: Drew Davenport <ddavenport@chromium.org> |
| Cc: Arnd Bergmann <arnd@arndb.de> |
| Cc: "Steven Rostedt (VMware)" <rostedt@goodmis.org> |
| Cc: Feng Tang <feng.tang@intel.com> |
| Cc: Petr Mladek <pmladek@suse.com> |
| Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> |
| Cc: Borislav Petkov <bp@suse.de> |
| Cc: YueHaibing <yuehaibing@huawei.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h |
| index b4a2639130a0..384b5c835ced 100644 |
| --- a/include/asm-generic/bug.h |
| +++ b/include/asm-generic/bug.h |
| @@ -10,6 +10,7 @@ |
| #define BUGFLAG_WARNING (1 << 0) |
| #define BUGFLAG_ONCE (1 << 1) |
| #define BUGFLAG_DONE (1 << 2) |
| +#define BUGFLAG_NO_CUT_HERE (1 << 3) /* CUT_HERE already sent */ |
| #define BUGFLAG_TAINT(taint) ((taint) << 8) |
| #define BUG_GET_TAINT(bug) ((bug)->flags >> 8) |
| #endif |
| @@ -86,13 +87,10 @@ void warn_slowpath_fmt(const char *file, const int line, unsigned taint, |
| warn_slowpath_fmt(__FILE__, __LINE__, taint, arg) |
| #else |
| extern __printf(1, 2) void __warn_printk(const char *fmt, ...); |
| -#define __WARN() do { \ |
| - printk(KERN_WARNING CUT_HERE); \ |
| - __WARN_FLAGS(BUGFLAG_TAINT(TAINT_WARN)); \ |
| - } while (0) |
| +#define __WARN() __WARN_FLAGS(BUGFLAG_TAINT(TAINT_WARN)) |
| #define __WARN_printf(taint, arg...) do { \ |
| __warn_printk(arg); \ |
| - __WARN_FLAGS(BUGFLAG_TAINT(taint)); \ |
| + __WARN_FLAGS(BUGFLAG_NO_CUT_HERE | BUGFLAG_TAINT(taint));\ |
| } while (0) |
| #define WARN_ON_ONCE(condition) ({ \ |
| int __ret_warn_on = !!(condition); \ |
| diff --git a/lib/bug.c b/lib/bug.c |
| index 1077366f496b..8c98af0bf585 100644 |
| --- a/lib/bug.c |
| +++ b/lib/bug.c |
| @@ -181,6 +181,15 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) |
| } |
| } |
| |
| + /* |
| + * BUG() and WARN_ON() families don't print a custom debug message |
| + * before triggering the exception handler, so we must add the |
| + * "cut here" line now. WARN() issues its own "cut here" before the |
| + * extra debugging message it writes before triggering the handler. |
| + */ |
| + if ((bug->flags & BUGFLAG_NO_CUT_HERE) == 0) |
| + printk(KERN_DEFAULT CUT_HERE); |
| + |
| if (warning) { |
| /* this is a WARN_ON rather than BUG/BUG_ON */ |
| __warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs, |
| @@ -188,8 +197,6 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) |
| return BUG_TRAP_TYPE_WARN; |
| } |
| |
| - printk(KERN_DEFAULT CUT_HERE); |
| - |
| if (file) |
| pr_crit("kernel BUG at %s:%u!\n", file, line); |
| else |
| -- |
| 2.7.4 |
| |