| From: Matt Redfearn <matt.redfearn@imgtec.com> |
| Date: Fri, 14 Jul 2017 14:51:12 +0200 |
| Subject: printk/console: Always disable boot consoles that use init memory |
| before it is freed |
| |
| commit 2b1be689f3aadcfe0a768314c80e43483c784659 upstream. |
| |
| Commit 4c30c6f566c0 ("kernel/printk: do not turn off bootconsole in |
| printk_late_init() if keep_bootcon") added a check on keep_bootcon to |
| ensure that boot consoles were kept around until the real console is |
| registered. |
| |
| This can lead to problems if the boot console data and code are in the |
| init section, since it can be freed before the boot console is |
| unregistered. |
| |
| Commit 81cc26f2bd11 ("printk: only unregister boot consoles when |
| necessary") fixed this a better way. It allowed to keep boot consoles |
| that did not use init data. Unfortunately it did not remove the check |
| of keep_bootcon. |
| |
| This can lead to crashes and weird panics when the bootconsole is |
| accessed after free, especially if page poisoning is in use and the |
| code / data have been overwritten with a poison value. |
| |
| To prevent this, always free the boot console if it is within the init |
| section. In addition, print a warning about that the console is removed |
| prematurely. |
| |
| Finally there is a new comment how to avoid the warning. It replaced |
| an explanation that duplicated a more comprehensive function |
| description few lines above. |
| |
| Fixes: 4c30c6f566c0 ("kernel/printk: do not turn off bootconsole in printk_late_init() if keep_bootcon") |
| Link: http://lkml.kernel.org/r/1500036673-7122-2-git-send-email-pmladek@suse.com |
| Cc: Steven Rostedt <rostedt@goodmis.org> |
| Cc: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: Jiri Slaby <jslaby@suse.com> |
| Cc: "David S. Miller" <davem@davemloft.net> |
| Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk> |
| Cc: "Fabio M. Di Nitto" <fdinitto@redhat.com> |
| Cc: linux-serial@vger.kernel.org |
| Cc: linux-kernel@vger.kernel.org |
| Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> |
| [pmladek@suse.com: print the warning, code and comments clean up] |
| Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
| Signed-off-by: Petr Mladek <pmladek@suse.com> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| kernel/printk/printk.c | 20 +++++++++----------- |
| 1 file changed, 9 insertions(+), 11 deletions(-) |
| |
| --- a/kernel/printk/printk.c |
| +++ b/kernel/printk/printk.c |
| @@ -2570,25 +2570,23 @@ EXPORT_SYMBOL(unregister_console); |
| * makes it difficult to diagnose problems that occur during this time. |
| * |
| * To mitigate this problem somewhat, only unregister consoles whose memory |
| - * intersects with the init section. Note that code exists elsewhere to get |
| - * rid of the boot console as soon as the proper console shows up, so there |
| - * won't be side-effects from postponing the removal. |
| + * intersects with the init section. Note that all other boot consoles will |
| + * get unregistred when the real preferred console is registered. |
| */ |
| static int __init printk_late_init(void) |
| { |
| struct console *con; |
| |
| for_each_console(con) { |
| - if (!keep_bootcon && con->flags & CON_BOOT) { |
| + if ((con->flags & CON_BOOT) && |
| + init_section_intersects(con, sizeof(*con))) { |
| /* |
| - * Make sure to unregister boot consoles whose data |
| - * resides in the init section before the init section |
| - * is discarded. Boot consoles whose data will stick |
| - * around will automatically be unregistered when the |
| - * proper console replaces them. |
| + * Please, consider moving the reported consoles out |
| + * of the init section. |
| */ |
| - if (init_section_intersects(con, sizeof(*con))) |
| - unregister_console(con); |
| + pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", |
| + con->name, con->index); |
| + unregister_console(con); |
| } |
| } |
| hotcpu_notifier(console_cpu_notify, 0); |