Commit a44f71a9 authored by Kees Cook's avatar Kees Cook Committed by Linus Torvalds

bug: move WARN_ON() "cut here" into exception handler

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: 6b15f678 ("include/asm-generic/bug.h: fix "cut here" for WARN_ON for __WARN_TAINT architectures")
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Reported-by: default avatarChristophe 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2da1ead4
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define BUGFLAG_WARNING (1 << 0) #define BUGFLAG_WARNING (1 << 0)
#define BUGFLAG_ONCE (1 << 1) #define BUGFLAG_ONCE (1 << 1)
#define BUGFLAG_DONE (1 << 2) #define BUGFLAG_DONE (1 << 2)
#define BUGFLAG_NO_CUT_HERE (1 << 3) /* CUT_HERE already sent */
#define BUGFLAG_TAINT(taint) ((taint) << 8) #define BUGFLAG_TAINT(taint) ((taint) << 8)
#define BUG_GET_TAINT(bug) ((bug)->flags >> 8) #define BUG_GET_TAINT(bug) ((bug)->flags >> 8)
#endif #endif
...@@ -86,13 +87,10 @@ void warn_slowpath_fmt(const char *file, const int line, unsigned taint, ...@@ -86,13 +87,10 @@ void warn_slowpath_fmt(const char *file, const int line, unsigned taint,
warn_slowpath_fmt(__FILE__, __LINE__, taint, arg) warn_slowpath_fmt(__FILE__, __LINE__, taint, arg)
#else #else
extern __printf(1, 2) void __warn_printk(const char *fmt, ...); extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
#define __WARN() do { \ #define __WARN() __WARN_FLAGS(BUGFLAG_TAINT(TAINT_WARN))
printk(KERN_WARNING CUT_HERE); \
__WARN_FLAGS(BUGFLAG_TAINT(TAINT_WARN)); \
} while (0)
#define __WARN_printf(taint, arg...) do { \ #define __WARN_printf(taint, arg...) do { \
__warn_printk(arg); \ __warn_printk(arg); \
__WARN_FLAGS(BUGFLAG_TAINT(taint)); \ __WARN_FLAGS(BUGFLAG_NO_CUT_HERE | BUGFLAG_TAINT(taint));\
} while (0) } while (0)
#define WARN_ON_ONCE(condition) ({ \ #define WARN_ON_ONCE(condition) ({ \
int __ret_warn_on = !!(condition); \ int __ret_warn_on = !!(condition); \
......
...@@ -181,6 +181,15 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) ...@@ -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) { if (warning) {
/* this is a WARN_ON rather than BUG/BUG_ON */ /* this is a WARN_ON rather than BUG/BUG_ON */
__warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs, __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) ...@@ -188,8 +197,6 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
return BUG_TRAP_TYPE_WARN; return BUG_TRAP_TYPE_WARN;
} }
printk(KERN_DEFAULT CUT_HERE);
if (file) if (file)
pr_crit("kernel BUG at %s:%u!\n", file, line); pr_crit("kernel BUG at %s:%u!\n", file, line);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment