|
Kyle McMartin |
1d3db7f |
From: Kay Sievers <kay.sievers@vrfy.org>
|
|
Kyle McMartin |
1d3db7f |
Date: Sun, 13 Mar 2011 02:19:51 +0000 (+0100)
|
|
Kyle McMartin |
1d3db7f |
Subject: printk: do not mangle valid userspace syslog prefixes
|
|
Kyle McMartin |
1d3db7f |
X-Git-Tag: v2.6.39-rc1~471^2
|
|
Kyle McMartin |
1d3db7f |
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9d90c8d9cde929cbc575098e825d7c29d9f45054
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
printk: do not mangle valid userspace syslog prefixes
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
printk: do not mangle valid userspace syslog prefixes with /dev/kmsg
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
Log messages passed to the kernel log by using /dev/kmsg or /dev/ttyprintk
|
|
Kyle McMartin |
1d3db7f |
might contain a syslog prefix including the syslog facility value.
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
This makes printk to recognize these headers properly, extract the real log
|
|
Kyle McMartin |
1d3db7f |
level from it to use, and add the prefix as a proper prefix to the
|
|
Kyle McMartin |
1d3db7f |
log buffer, instead of wrongly printing it as the log message text.
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
Before:
|
|
Kyle McMartin |
1d3db7f |
$ echo '<14>text' > /dev/kmsg
|
|
Kyle McMartin |
1d3db7f |
$ dmesg -r
|
|
Kyle McMartin |
1d3db7f |
<4>[135159.594810] <14>text
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
After:
|
|
Kyle McMartin |
1d3db7f |
$ echo '<14>text' > /dev/kmsg
|
|
Kyle McMartin |
1d3db7f |
$ dmesg -r
|
|
Kyle McMartin |
1d3db7f |
<14>[ 50.750654] text
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
Cc: Lennart Poettering <lennart@poettering.net>
|
|
Kyle McMartin |
1d3db7f |
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
|
|
Kyle McMartin |
1d3db7f |
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
|
Kyle McMartin |
1d3db7f |
---
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
diff --git a/kernel/printk.c b/kernel/printk.c
|
|
Kyle McMartin |
1d3db7f |
index 2ddbdc7..5e3d042 100644
|
|
Kyle McMartin |
1d3db7f |
--- a/kernel/printk.c
|
|
Kyle McMartin |
1d3db7f |
+++ b/kernel/printk.c
|
|
Kyle McMartin |
1d3db7f |
@@ -499,6 +499,71 @@ static void _call_console_drivers(unsigned start,
|
|
Kyle McMartin |
1d3db7f |
}
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
/*
|
|
Kyle McMartin |
1d3db7f |
+ * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the
|
|
Kyle McMartin |
1d3db7f |
+ * lower 3 bit are the log level, the rest are the log facility. In case
|
|
Kyle McMartin |
1d3db7f |
+ * userspace passes usual userspace syslog messages to /dev/kmsg or
|
|
Kyle McMartin |
1d3db7f |
+ * /dev/ttyprintk, the log prefix might contain the facility. Printk needs
|
|
Kyle McMartin |
1d3db7f |
+ * to extract the correct log level for in-kernel processing, and not mangle
|
|
Kyle McMartin |
1d3db7f |
+ * the original value.
|
|
Kyle McMartin |
1d3db7f |
+ *
|
|
Kyle McMartin |
1d3db7f |
+ * If a prefix is found, the length of the prefix is returned. If 'level' is
|
|
Kyle McMartin |
1d3db7f |
+ * passed, it will be filled in with the log level without a possible facility
|
|
Kyle McMartin |
1d3db7f |
+ * value. If 'special' is passed, the special printk prefix chars are accepted
|
|
Kyle McMartin |
1d3db7f |
+ * and returned. If no valid header is found, 0 is returned and the passed
|
|
Kyle McMartin |
1d3db7f |
+ * variables are not touched.
|
|
Kyle McMartin |
1d3db7f |
+ */
|
|
Kyle McMartin |
1d3db7f |
+static size_t log_prefix(const char *p, unsigned int *level, char *special)
|
|
Kyle McMartin |
1d3db7f |
+{
|
|
Kyle McMartin |
1d3db7f |
+ unsigned int lev = 0;
|
|
Kyle McMartin |
1d3db7f |
+ char sp = '\0';
|
|
Kyle McMartin |
1d3db7f |
+ size_t len;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ if (p[0] != '<' || !p[1])
|
|
Kyle McMartin |
1d3db7f |
+ return 0;
|
|
Kyle McMartin |
1d3db7f |
+ if (p[2] == '>') {
|
|
Kyle McMartin |
1d3db7f |
+ /* usual single digit level number or special char */
|
|
Kyle McMartin |
1d3db7f |
+ switch (p[1]) {
|
|
Kyle McMartin |
1d3db7f |
+ case '0' ... '7':
|
|
Kyle McMartin |
1d3db7f |
+ lev = p[1] - '0';
|
|
Kyle McMartin |
1d3db7f |
+ break;
|
|
Kyle McMartin |
1d3db7f |
+ case 'c': /* KERN_CONT */
|
|
Kyle McMartin |
1d3db7f |
+ case 'd': /* KERN_DEFAULT */
|
|
Kyle McMartin |
1d3db7f |
+ sp = p[1];
|
|
Kyle McMartin |
1d3db7f |
+ break;
|
|
Kyle McMartin |
1d3db7f |
+ default:
|
|
Kyle McMartin |
1d3db7f |
+ return 0;
|
|
Kyle McMartin |
1d3db7f |
+ }
|
|
Kyle McMartin |
1d3db7f |
+ len = 3;
|
|
Kyle McMartin |
1d3db7f |
+ } else {
|
|
Kyle McMartin |
1d3db7f |
+ /* multi digit including the level and facility number */
|
|
Kyle McMartin |
1d3db7f |
+ char *endp = NULL;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ if (p[1] < '0' && p[1] > '9')
|
|
Kyle McMartin |
1d3db7f |
+ return 0;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ lev = (simple_strtoul(&p[1], &endp, 10) & 7);
|
|
Kyle McMartin |
1d3db7f |
+ if (endp == NULL || endp[0] != '>')
|
|
Kyle McMartin |
1d3db7f |
+ return 0;
|
|
Kyle McMartin |
1d3db7f |
+ len = (endp + 1) - p;
|
|
Kyle McMartin |
1d3db7f |
+ }
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ /* do not accept special char if not asked for */
|
|
Kyle McMartin |
1d3db7f |
+ if (sp && !special)
|
|
Kyle McMartin |
1d3db7f |
+ return 0;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ if (special) {
|
|
Kyle McMartin |
1d3db7f |
+ *special = sp;
|
|
Kyle McMartin |
1d3db7f |
+ /* return special char, do not touch level */
|
|
Kyle McMartin |
1d3db7f |
+ if (sp)
|
|
Kyle McMartin |
1d3db7f |
+ return len;
|
|
Kyle McMartin |
1d3db7f |
+ }
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ if (level)
|
|
Kyle McMartin |
1d3db7f |
+ *level = lev;
|
|
Kyle McMartin |
1d3db7f |
+ return len;
|
|
Kyle McMartin |
1d3db7f |
+}
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+/*
|
|
Kyle McMartin |
1d3db7f |
* Call the console drivers, asking them to write out
|
|
Kyle McMartin |
1d3db7f |
* log_buf[start] to log_buf[end - 1].
|
|
Kyle McMartin |
1d3db7f |
* The console_lock must be held.
|
|
Kyle McMartin |
1d3db7f |
@@ -513,13 +578,9 @@ static void call_console_drivers(unsigned start, unsigned end)
|
|
Kyle McMartin |
1d3db7f |
cur_index = start;
|
|
Kyle McMartin |
1d3db7f |
start_print = start;
|
|
Kyle McMartin |
1d3db7f |
while (cur_index != end) {
|
|
Kyle McMartin |
1d3db7f |
- if (msg_level < 0 && ((end - cur_index) > 2) &&
|
|
Kyle McMartin |
1d3db7f |
- LOG_BUF(cur_index + 0) == '<' &&
|
|
Kyle McMartin |
1d3db7f |
- LOG_BUF(cur_index + 1) >= '0' &&
|
|
Kyle McMartin |
1d3db7f |
- LOG_BUF(cur_index + 1) <= '7' &&
|
|
Kyle McMartin |
1d3db7f |
- LOG_BUF(cur_index + 2) == '>') {
|
|
Kyle McMartin |
1d3db7f |
- msg_level = LOG_BUF(cur_index + 1) - '0';
|
|
Kyle McMartin |
1d3db7f |
- cur_index += 3;
|
|
Kyle McMartin |
1d3db7f |
+ if (msg_level < 0 && ((end - cur_index) > 2)) {
|
|
Kyle McMartin |
1d3db7f |
+ /* strip log prefix */
|
|
Kyle McMartin |
1d3db7f |
+ cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL);
|
|
Kyle McMartin |
1d3db7f |
start_print = cur_index;
|
|
Kyle McMartin |
1d3db7f |
}
|
|
Kyle McMartin |
1d3db7f |
while (cur_index != end) {
|
|
Kyle McMartin |
1d3db7f |
@@ -717,6 +778,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
|
|
Kyle McMartin |
1d3db7f |
unsigned long flags;
|
|
Kyle McMartin |
1d3db7f |
int this_cpu;
|
|
Kyle McMartin |
1d3db7f |
char *p;
|
|
Kyle McMartin |
1d3db7f |
+ size_t plen;
|
|
Kyle McMartin |
1d3db7f |
+ char special;
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
boot_delay_msec();
|
|
Kyle McMartin |
1d3db7f |
printk_delay();
|
|
Kyle McMartin |
1d3db7f |
@@ -757,45 +820,52 @@ asmlinkage int vprintk(const char *fmt, va_list args)
|
|
Kyle McMartin |
1d3db7f |
printed_len += vscnprintf(printk_buf + printed_len,
|
|
Kyle McMartin |
1d3db7f |
sizeof(printk_buf) - printed_len, fmt, args);
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
-
|
|
Kyle McMartin |
1d3db7f |
p = printk_buf;
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
- /* Do we have a loglevel in the string? */
|
|
Kyle McMartin |
1d3db7f |
- if (p[0] == '<') {
|
|
Kyle McMartin |
1d3db7f |
- unsigned char c = p[1];
|
|
Kyle McMartin |
1d3db7f |
- if (c && p[2] == '>') {
|
|
Kyle McMartin |
1d3db7f |
- switch (c) {
|
|
Kyle McMartin |
1d3db7f |
- case '0' ... '7': /* loglevel */
|
|
Kyle McMartin |
1d3db7f |
- current_log_level = c - '0';
|
|
Kyle McMartin |
1d3db7f |
- /* Fallthrough - make sure we're on a new line */
|
|
Kyle McMartin |
1d3db7f |
- case 'd': /* KERN_DEFAULT */
|
|
Kyle McMartin |
1d3db7f |
- if (!new_text_line) {
|
|
Kyle McMartin |
1d3db7f |
- emit_log_char('\n');
|
|
Kyle McMartin |
1d3db7f |
- new_text_line = 1;
|
|
Kyle McMartin |
1d3db7f |
- }
|
|
Kyle McMartin |
1d3db7f |
- /* Fallthrough - skip the loglevel */
|
|
Kyle McMartin |
1d3db7f |
- case 'c': /* KERN_CONT */
|
|
Kyle McMartin |
1d3db7f |
- p += 3;
|
|
Kyle McMartin |
1d3db7f |
- break;
|
|
Kyle McMartin |
1d3db7f |
+ /* Read log level and handle special printk prefix */
|
|
Kyle McMartin |
1d3db7f |
+ plen = log_prefix(p, ¤t_log_level, &special);
|
|
Kyle McMartin |
1d3db7f |
+ if (plen) {
|
|
Kyle McMartin |
1d3db7f |
+ p += plen;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ switch (special) {
|
|
Kyle McMartin |
1d3db7f |
+ case 'c': /* Strip <c> KERN_CONT, continue line */
|
|
Kyle McMartin |
1d3db7f |
+ plen = 0;
|
|
Kyle McMartin |
1d3db7f |
+ break;
|
|
Kyle McMartin |
1d3db7f |
+ case 'd': /* Strip <d> KERN_DEFAULT, start new line */
|
|
Kyle McMartin |
1d3db7f |
+ plen = 0;
|
|
Kyle McMartin |
1d3db7f |
+ default:
|
|
Kyle McMartin |
1d3db7f |
+ if (!new_text_line) {
|
|
Kyle McMartin |
1d3db7f |
+ emit_log_char('\n');
|
|
Kyle McMartin |
1d3db7f |
+ new_text_line = 1;
|
|
Kyle McMartin |
1d3db7f |
}
|
|
Kyle McMartin |
1d3db7f |
}
|
|
Kyle McMartin |
1d3db7f |
}
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
/*
|
|
Kyle McMartin |
1d3db7f |
- * Copy the output into log_buf. If the caller didn't provide
|
|
Kyle McMartin |
1d3db7f |
- * appropriate log level tags, we insert them here
|
|
Kyle McMartin |
1d3db7f |
+ * Copy the output into log_buf. If the caller didn't provide
|
|
Kyle McMartin |
1d3db7f |
+ * the appropriate log prefix, we insert them here
|
|
Kyle McMartin |
1d3db7f |
*/
|
|
Kyle McMartin |
1d3db7f |
- for ( ; *p; p++) {
|
|
Kyle McMartin |
1d3db7f |
+ for (; *p; p++) {
|
|
Kyle McMartin |
1d3db7f |
if (new_text_line) {
|
|
Kyle McMartin |
1d3db7f |
- /* Always output the token */
|
|
Kyle McMartin |
1d3db7f |
- emit_log_char('<');
|
|
Kyle McMartin |
1d3db7f |
- emit_log_char(current_log_level + '0');
|
|
Kyle McMartin |
1d3db7f |
- emit_log_char('>');
|
|
Kyle McMartin |
1d3db7f |
- printed_len += 3;
|
|
Kyle McMartin |
1d3db7f |
new_text_line = 0;
|
|
Kyle McMartin |
1d3db7f |
|
|
Kyle McMartin |
1d3db7f |
+ if (plen) {
|
|
Kyle McMartin |
1d3db7f |
+ /* Copy original log prefix */
|
|
Kyle McMartin |
1d3db7f |
+ int i;
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
+ for (i = 0; i < plen; i++)
|
|
Kyle McMartin |
1d3db7f |
+ emit_log_char(printk_buf[i]);
|
|
Kyle McMartin |
1d3db7f |
+ printed_len += plen;
|
|
Kyle McMartin |
1d3db7f |
+ } else {
|
|
Kyle McMartin |
1d3db7f |
+ /* Add log prefix */
|
|
Kyle McMartin |
1d3db7f |
+ emit_log_char('<');
|
|
Kyle McMartin |
1d3db7f |
+ emit_log_char(current_log_level + '0');
|
|
Kyle McMartin |
1d3db7f |
+ emit_log_char('>');
|
|
Kyle McMartin |
1d3db7f |
+ printed_len += 3;
|
|
Kyle McMartin |
1d3db7f |
+ }
|
|
Kyle McMartin |
1d3db7f |
+
|
|
Kyle McMartin |
1d3db7f |
if (printk_time) {
|
|
Kyle McMartin |
1d3db7f |
- /* Follow the token with the time */
|
|
Kyle McMartin |
1d3db7f |
+ /* Add the current time stamp */
|
|
Kyle McMartin |
1d3db7f |
char tbuf[50], *tp;
|
|
Kyle McMartin |
1d3db7f |
unsigned tlen;
|
|
Kyle McMartin |
1d3db7f |
unsigned long long t;
|