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
This commit is contained in:
commit
cef5d0f952
|
@ -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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
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)
|
||||||
* 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)
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue