From 1d3db7f8fbb135e9cd6627da77f84bcfc6ef2a81 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 29 Mar 2011 19:17:20 -0400 Subject: [PATCH] printk: do not mangle valid userspace syslog prefixes printk: do not mangle valid userspace syslog prefixes with /dev/kmsg (#691888) The patch is upstream in 2.6.39, and Lennart tells me the patch has been backported for the next Suse release as well. --- kernel.spec | 11 + ...ngle-valid-userspace-syslog-prefixes.patch | 214 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 printk-do-not-mangle-valid-userspace-syslog-prefixes.patch diff --git a/kernel.spec b/kernel.spec index 2ababf813..045971ec0 100644 --- a/kernel.spec +++ b/kernel.spec @@ -730,6 +730,8 @@ Patch12207: pci-pcie-links-may-not-get-configured-for-aspm-under-powersave-mode. Patch12303: dmar-disable-when-ricoh-multifunction.patch +Patch12305: printk-do-not-mangle-valid-userspace-syslog-prefixes.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1356,6 +1358,9 @@ ApplyPatch acpi_reboot.patch # rhbz#605888 ApplyPatch dmar-disable-when-ricoh-multifunction.patch +# rhbz#691888 +ApplyPatch printk-do-not-mangle-valid-userspace-syslog-prefixes.patch + # END OF PATCH APPLICATIONS %endif @@ -1964,6 +1969,12 @@ fi # and build. %changelog +* Tue Mar 29 2011 Kyle McMartin +- printk: do not mangle valid userspace syslog prefixes with + /dev/kmsg (#691888) + - The patch is upstream in 2.6.39, and Lennart tells me the patch has been + backported for the next Suse release as well. + * Sun Mar 27 2011 Chuck Ebbert 2.6.38.2-8 - Linux 2.6.38.2 - Drop patches merged in 2.6.38.2: diff --git a/printk-do-not-mangle-valid-userspace-syslog-prefixes.patch b/printk-do-not-mangle-valid-userspace-syslog-prefixes.patch new file mode 100644 index 000000000..73885ae57 --- /dev/null +++ b/printk-do-not-mangle-valid-userspace-syslog-prefixes.patch @@ -0,0 +1,214 @@ +From: Kay Sievers +Date: Sun, 13 Mar 2011 02:19:51 +0000 (+0100) +Subject: printk: do not mangle valid userspace syslog prefixes +X-Git-Tag: v2.6.39-rc1~471^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9d90c8d9cde929cbc575098e825d7c29d9f45054 + +printk: do not mangle valid userspace syslog prefixes + +printk: do not mangle valid userspace syslog prefixes with /dev/kmsg + +Log messages passed to the kernel log by using /dev/kmsg or /dev/ttyprintk +might contain a syslog prefix including the syslog facility value. + +This makes printk to recognize these headers properly, extract the real log +level from it to use, and add the prefix as a proper prefix to the +log buffer, instead of wrongly printing it as the log message text. + +Before: + $ echo '<14>text' > /dev/kmsg + $ dmesg -r + <4>[135159.594810] <14>text + +After: + $ echo '<14>text' > /dev/kmsg + $ dmesg -r + <14>[ 50.750654] text + +Cc: Lennart Poettering +Signed-off-by: Kay Sievers +Signed-off-by: Greg Kroah-Hartman +--- + +diff --git a/kernel/printk.c b/kernel/printk.c +index 2ddbdc7..5e3d042 100644 +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -499,6 +499,71 @@ static void _call_console_drivers(unsigned start, + } + + /* ++ * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the ++ * lower 3 bit are the log level, the rest are the log facility. In case ++ * userspace passes usual userspace syslog messages to /dev/kmsg or ++ * /dev/ttyprintk, the log prefix might contain the facility. Printk needs ++ * to extract the correct log level for in-kernel processing, and not mangle ++ * the original value. ++ * ++ * If a prefix is found, the length of the prefix is returned. If 'level' is ++ * passed, it will be filled in with the log level without a possible facility ++ * value. If 'special' is passed, the special printk prefix chars are accepted ++ * and returned. If no valid header is found, 0 is returned and the passed ++ * variables are not touched. ++ */ ++static size_t log_prefix(const char *p, unsigned int *level, char *special) ++{ ++ unsigned int lev = 0; ++ char sp = '\0'; ++ size_t len; ++ ++ if (p[0] != '<' || !p[1]) ++ return 0; ++ if (p[2] == '>') { ++ /* usual single digit level number or special char */ ++ switch (p[1]) { ++ case '0' ... '7': ++ lev = p[1] - '0'; ++ break; ++ case 'c': /* KERN_CONT */ ++ case 'd': /* KERN_DEFAULT */ ++ sp = p[1]; ++ break; ++ default: ++ return 0; ++ } ++ len = 3; ++ } else { ++ /* multi digit including the level and facility number */ ++ char *endp = NULL; ++ ++ if (p[1] < '0' && p[1] > '9') ++ return 0; ++ ++ lev = (simple_strtoul(&p[1], &endp, 10) & 7); ++ if (endp == NULL || endp[0] != '>') ++ return 0; ++ len = (endp + 1) - p; ++ } ++ ++ /* do not accept special char if not asked for */ ++ if (sp && !special) ++ return 0; ++ ++ if (special) { ++ *special = sp; ++ /* return special char, do not touch level */ ++ if (sp) ++ return len; ++ } ++ ++ if (level) ++ *level = lev; ++ return len; ++} ++ ++/* + * Call the console drivers, asking them to write out + * log_buf[start] to log_buf[end - 1]. + * The console_lock must be held. +@@ -513,13 +578,9 @@ static void call_console_drivers(unsigned start, unsigned end) + cur_index = start; + start_print = start; + while (cur_index != end) { +- if (msg_level < 0 && ((end - cur_index) > 2) && +- LOG_BUF(cur_index + 0) == '<' && +- LOG_BUF(cur_index + 1) >= '0' && +- LOG_BUF(cur_index + 1) <= '7' && +- LOG_BUF(cur_index + 2) == '>') { +- msg_level = LOG_BUF(cur_index + 1) - '0'; +- cur_index += 3; ++ if (msg_level < 0 && ((end - cur_index) > 2)) { ++ /* strip log prefix */ ++ cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL); + start_print = cur_index; + } + while (cur_index != end) { +@@ -717,6 +778,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) + unsigned long flags; + int this_cpu; + char *p; ++ size_t plen; ++ char special; + + boot_delay_msec(); + printk_delay(); +@@ -757,45 +820,52 @@ asmlinkage int vprintk(const char *fmt, va_list args) + printed_len += vscnprintf(printk_buf + printed_len, + sizeof(printk_buf) - printed_len, fmt, args); + +- + p = printk_buf; + +- /* Do we have a loglevel in the string? */ +- if (p[0] == '<') { +- unsigned char c = p[1]; +- if (c && p[2] == '>') { +- switch (c) { +- case '0' ... '7': /* loglevel */ +- current_log_level = c - '0'; +- /* Fallthrough - make sure we're on a new line */ +- case 'd': /* KERN_DEFAULT */ +- if (!new_text_line) { +- emit_log_char('\n'); +- new_text_line = 1; +- } +- /* Fallthrough - skip the loglevel */ +- case 'c': /* KERN_CONT */ +- p += 3; +- break; ++ /* Read log level and handle special printk prefix */ ++ plen = log_prefix(p, ¤t_log_level, &special); ++ if (plen) { ++ p += plen; ++ ++ switch (special) { ++ case 'c': /* Strip KERN_CONT, continue line */ ++ plen = 0; ++ break; ++ case 'd': /* Strip KERN_DEFAULT, start new line */ ++ plen = 0; ++ default: ++ if (!new_text_line) { ++ emit_log_char('\n'); ++ new_text_line = 1; + } + } + } + + /* +- * Copy the output into log_buf. If the caller didn't provide +- * appropriate log level tags, we insert them here ++ * Copy the output into log_buf. If the caller didn't provide ++ * the appropriate log prefix, we insert them here + */ +- for ( ; *p; p++) { ++ for (; *p; p++) { + if (new_text_line) { +- /* Always output the token */ +- emit_log_char('<'); +- emit_log_char(current_log_level + '0'); +- emit_log_char('>'); +- printed_len += 3; + new_text_line = 0; + ++ if (plen) { ++ /* Copy original log prefix */ ++ int i; ++ ++ for (i = 0; i < plen; i++) ++ emit_log_char(printk_buf[i]); ++ printed_len += plen; ++ } else { ++ /* Add log prefix */ ++ emit_log_char('<'); ++ emit_log_char(current_log_level + '0'); ++ emit_log_char('>'); ++ printed_len += 3; ++ } ++ + if (printk_time) { +- /* Follow the token with the time */ ++ /* Add the current time stamp */ + char tbuf[50], *tp; + unsigned tlen; + unsigned long long t;