Commit cef5d0f9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk

Pull printk updates from Petr Mladek:

 - Do not allow use of freed init data and code even when boot consoles
   are forced to stay. Also check for the init memory more precisely.

 - Some code clean up by starting contributors.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk:
  printk: Clean up do_syslog() error handling
  printk/console: Enhance the check for consoles using init memory
  printk/console: Always disable boot consoles that use init memory before it is freed
  printk: Modify operators of printed_len and text_len
parents 0fb02e71 077a1cc0
...@@ -1434,7 +1434,7 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1434,7 +1434,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
error = check_syslog_permissions(type, source); error = check_syslog_permissions(type, source);
if (error) if (error)
goto out; return error;
switch (type) { switch (type) {
case SYSLOG_ACTION_CLOSE: /* Close log */ case SYSLOG_ACTION_CLOSE: /* Close log */
...@@ -1442,20 +1442,16 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1442,20 +1442,16 @@ int do_syslog(int type, char __user *buf, int len, int source)
case SYSLOG_ACTION_OPEN: /* Open log */ case SYSLOG_ACTION_OPEN: /* Open log */
break; break;
case SYSLOG_ACTION_READ: /* Read from log */ case SYSLOG_ACTION_READ: /* Read from log */
error = -EINVAL;
if (!buf || len < 0) if (!buf || len < 0)
goto out; return -EINVAL;
error = 0;
if (!len) if (!len)
goto out; return 0;
if (!access_ok(VERIFY_WRITE, buf, len)) { if (!access_ok(VERIFY_WRITE, buf, len))
error = -EFAULT; return -EFAULT;
goto out;
}
error = wait_event_interruptible(log_wait, error = wait_event_interruptible(log_wait,
syslog_seq != log_next_seq); syslog_seq != log_next_seq);
if (error) if (error)
goto out; return error;
error = syslog_print(buf, len); error = syslog_print(buf, len);
break; break;
/* Read/clear last kernel messages */ /* Read/clear last kernel messages */
...@@ -1464,16 +1460,12 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1464,16 +1460,12 @@ int do_syslog(int type, char __user *buf, int len, int source)
/* FALL THRU */ /* FALL THRU */
/* Read last kernel messages */ /* Read last kernel messages */
case SYSLOG_ACTION_READ_ALL: case SYSLOG_ACTION_READ_ALL:
error = -EINVAL;
if (!buf || len < 0) if (!buf || len < 0)
goto out; return -EINVAL;
error = 0;
if (!len) if (!len)
goto out; return 0;
if (!access_ok(VERIFY_WRITE, buf, len)) { if (!access_ok(VERIFY_WRITE, buf, len))
error = -EFAULT; return -EFAULT;
goto out;
}
error = syslog_print_all(buf, len, clear); error = syslog_print_all(buf, len, clear);
break; break;
/* Clear ring buffer */ /* Clear ring buffer */
...@@ -1495,15 +1487,13 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1495,15 +1487,13 @@ int do_syslog(int type, char __user *buf, int len, int source)
break; break;
/* Set level of messages printed to console */ /* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL: case SYSLOG_ACTION_CONSOLE_LEVEL:
error = -EINVAL;
if (len < 1 || len > 8) if (len < 1 || len > 8)
goto out; return -EINVAL;
if (len < minimum_console_loglevel) if (len < minimum_console_loglevel)
len = minimum_console_loglevel; len = minimum_console_loglevel;
console_loglevel = len; console_loglevel = len;
/* Implicitly re-enable logging to console */ /* Implicitly re-enable logging to console */
saved_console_loglevel = LOGLEVEL_DEFAULT; saved_console_loglevel = LOGLEVEL_DEFAULT;
error = 0;
break; break;
/* Number of chars in the log buffer */ /* Number of chars in the log buffer */
case SYSLOG_ACTION_SIZE_UNREAD: case SYSLOG_ACTION_SIZE_UNREAD:
...@@ -1525,7 +1515,6 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1525,7 +1515,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
u64 seq = syslog_seq; u64 seq = syslog_seq;
u32 idx = syslog_idx; u32 idx = syslog_idx;
error = 0;
while (seq < log_next_seq) { while (seq < log_next_seq) {
struct printk_log *msg = log_from_idx(idx); struct printk_log *msg = log_from_idx(idx);
...@@ -1545,7 +1534,7 @@ int do_syslog(int type, char __user *buf, int len, int source) ...@@ -1545,7 +1534,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
error = -EINVAL; error = -EINVAL;
break; break;
} }
out:
return error; return error;
} }
...@@ -1697,10 +1686,10 @@ asmlinkage int vprintk_emit(int facility, int level, ...@@ -1697,10 +1686,10 @@ asmlinkage int vprintk_emit(int facility, int level,
{ {
static char textbuf[LOG_LINE_MAX]; static char textbuf[LOG_LINE_MAX];
char *text = textbuf; char *text = textbuf;
size_t text_len = 0; size_t text_len;
enum log_flags lflags = 0; enum log_flags lflags = 0;
unsigned long flags; unsigned long flags;
int printed_len = 0; int printed_len;
bool in_sched = false; bool in_sched = false;
if (level == LOGLEVEL_SCHED) { if (level == LOGLEVEL_SCHED) {
...@@ -1753,7 +1742,7 @@ asmlinkage int vprintk_emit(int facility, int level, ...@@ -1753,7 +1742,7 @@ asmlinkage int vprintk_emit(int facility, int level,
if (dict) if (dict)
lflags |= LOG_PREFIX|LOG_NEWLINE; lflags |= LOG_PREFIX|LOG_NEWLINE;
printed_len += log_output(facility, level, lflags, dict, dictlen, text, text_len); printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len);
logbuf_unlock_irqrestore(flags); logbuf_unlock_irqrestore(flags);
...@@ -2649,9 +2638,8 @@ void __init console_init(void) ...@@ -2649,9 +2638,8 @@ void __init console_init(void)
* makes it difficult to diagnose problems that occur during this time. * makes it difficult to diagnose problems that occur during this time.
* *
* To mitigate this problem somewhat, only unregister consoles whose memory * To mitigate this problem somewhat, only unregister consoles whose memory
* intersects with the init section. Note that code exists elsewhere to get * intersects with the init section. Note that all other boot consoles will
* rid of the boot console as soon as the proper console shows up, so there * get unregistred when the real preferred console is registered.
* won't be side-effects from postponing the removal.
*/ */
static int __init printk_late_init(void) static int __init printk_late_init(void)
{ {
...@@ -2659,15 +2647,22 @@ static int __init printk_late_init(void) ...@@ -2659,15 +2647,22 @@ static int __init printk_late_init(void)
int ret; int ret;
for_each_console(con) { for_each_console(con) {
if (!keep_bootcon && con->flags & CON_BOOT) { if (!(con->flags & CON_BOOT))
continue;
/* Check addresses that might be used for enabled consoles. */
if (init_section_intersects(con, sizeof(*con)) ||
init_section_contains(con->write, 0) ||
init_section_contains(con->read, 0) ||
init_section_contains(con->device, 0) ||
init_section_contains(con->unblank, 0) ||
init_section_contains(con->data, 0)) {
/* /*
* Make sure to unregister boot consoles whose data * Please, consider moving the reported consoles out
* resides in the init section before the init section * of the init section.
* is discarded. Boot consoles whose data will stick
* around will automatically be unregistered when the
* proper console replaces them.
*/ */
if (init_section_intersects(con, sizeof(*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); unregister_console(con);
} }
} }
......
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