aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2011-03-12 21:19:51 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-03-14 11:49:16 -0400
commit9d90c8d9cde929cbc575098e825d7c29d9f45054 (patch)
tree49cd83812a9cbbb40cb0c6b73b13455cad0029ea /kernel
parent54fad532b29aa9145f12a83f4f82820c2f23b4e2 (diff)
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 <lennart@poettering.net> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk.c138
1 files changed, 104 insertions, 34 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 2ddbdc73aade..5e3d042e7001 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -499,6 +499,71 @@ static void _call_console_drivers(unsigned start,
499} 499}
500 500
501/* 501/*
502 * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the
503 * lower 3 bit are the log level, the rest are the log facility. In case
504 * userspace passes usual userspace syslog messages to /dev/kmsg or
505 * /dev/ttyprintk, the log prefix might contain the facility. Printk needs
506 * to extract the correct log level for in-kernel processing, and not mangle
507 * the original value.
508 *
509 * If a prefix is found, the length of the prefix is returned. If 'level' is
510 * passed, it will be filled in with the log level without a possible facility
511 * value. If 'special' is passed, the special printk prefix chars are accepted
512 * and returned. If no valid header is found, 0 is returned and the passed
513 * variables are not touched.
514 */
515static size_t log_prefix(const char *p, unsigned int *level, char *special)
516{
517 unsigned int lev = 0;
518 char sp = '\0';
519 size_t len;
520
521 if (p[0] != '<' || !p[1])
522 return 0;
523 if (p[2] == '>') {
524 /* usual single digit level number or special char */
525 switch (p[1]) {
526 case '0' ... '7':
527 lev = p[1] - '0';
528 break;
529 case 'c': /* KERN_CONT */
530 case 'd': /* KERN_DEFAULT */
531 sp = p[1];
532 break;
533 default:
534 return 0;
535 }
536 len = 3;
537 } else {
538 /* multi digit including the level and facility number */
539 char *endp = NULL;
540
541 if (p[1] < '0' && p[1] > '9')
542 return 0;
543
544 lev = (simple_strtoul(&p[1], &endp, 10) & 7);
545 if (endp == NULL || endp[0] != '>')
546 return 0;
547 len = (endp + 1) - p;
548 }
549
550 /* do not accept special char if not asked for */
551 if (sp && !special)
552 return 0;
553
554 if (special) {
555 *special = sp;
556 /* return special char, do not touch level */
557 if (sp)
558 return len;
559 }
560
561 if (level)
562 *level = lev;
563 return len;
564}
565
566/*
502 * Call the console drivers, asking them to write out 567 * Call the console drivers, asking them to write out
503 * log_buf[start] to log_buf[end - 1]. 568 * log_buf[start] to log_buf[end - 1].
504 * The console_lock must be held. 569 * The console_lock must be held.
@@ -513,13 +578,9 @@ static void call_console_drivers(unsigned start, unsigned end)
513 cur_index = start; 578 cur_index = start;
514 start_print = start; 579 start_print = start;
515 while (cur_index != end) { 580 while (cur_index != end) {
516 if (msg_level < 0 && ((end - cur_index) > 2) && 581 if (msg_level < 0 && ((end - cur_index) > 2)) {
517 LOG_BUF(cur_index + 0) == '<' && 582 /* strip log prefix */
518 LOG_BUF(cur_index + 1) >= '0' && 583 cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL);
519 LOG_BUF(cur_index + 1) <= '7' &&
520 LOG_BUF(cur_index + 2) == '>') {
521 msg_level = LOG_BUF(cur_index + 1) - '0';
522 cur_index += 3;
523 start_print = cur_index; 584 start_print = cur_index;
524 } 585 }
525 while (cur_index != end) { 586 while (cur_index != end) {
@@ -717,6 +778,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
717 unsigned long flags; 778 unsigned long flags;
718 int this_cpu; 779 int this_cpu;
719 char *p; 780 char *p;
781 size_t plen;
782 char special;
720 783
721 boot_delay_msec(); 784 boot_delay_msec();
722 printk_delay(); 785 printk_delay();
@@ -757,45 +820,52 @@ asmlinkage int vprintk(const char *fmt, va_list args)
757 printed_len += vscnprintf(printk_buf + printed_len, 820 printed_len += vscnprintf(printk_buf + printed_len,
758 sizeof(printk_buf) - printed_len, fmt, args); 821 sizeof(printk_buf) - printed_len, fmt, args);
759 822
760
761 p = printk_buf; 823 p = printk_buf;
762 824
763 /* Do we have a loglevel in the string? */ 825 /* Read log level and handle special printk prefix */
764 if (p[0] == '<') { 826 plen = log_prefix(p, &current_log_level, &special);
765 unsigned char c = p[1]; 827 if (plen) {
766 if (c && p[2] == '>') { 828 p += plen;
767 switch (c) { 829
768 case '0' ... '7': /* loglevel */ 830 switch (special) {
769 current_log_level = c - '0'; 831 case 'c': /* Strip <c> KERN_CONT, continue line */
770 /* Fallthrough - make sure we're on a new line */ 832 plen = 0;
771 case 'd': /* KERN_DEFAULT */ 833 break;
772 if (!new_text_line) { 834 case 'd': /* Strip <d> KERN_DEFAULT, start new line */
773 emit_log_char('\n'); 835 plen = 0;
774 new_text_line = 1; 836 default:
775 } 837 if (!new_text_line) {
776 /* Fallthrough - skip the loglevel */ 838 emit_log_char('\n');
777 case 'c': /* KERN_CONT */ 839 new_text_line = 1;
778 p += 3;
779 break;
780 } 840 }
781 } 841 }
782 } 842 }
783 843
784 /* 844 /*
785 * Copy the output into log_buf. If the caller didn't provide 845 * Copy the output into log_buf. If the caller didn't provide
786 * appropriate log level tags, we insert them here 846 * the appropriate log prefix, we insert them here
787 */ 847 */
788 for ( ; *p; p++) { 848 for (; *p; p++) {
789 if (new_text_line) { 849 if (new_text_line) {
790 /* Always output the token */
791 emit_log_char('<');
792 emit_log_char(current_log_level + '0');
793 emit_log_char('>');
794 printed_len += 3;
795 new_text_line = 0; 850 new_text_line = 0;
796 851
852 if (plen) {
853 /* Copy original log prefix */
854 int i;
855
856 for (i = 0; i < plen; i++)
857 emit_log_char(printk_buf[i]);
858 printed_len += plen;
859 } else {
860 /* Add log prefix */
861 emit_log_char('<');
862 emit_log_char(current_log_level + '0');
863 emit_log_char('>');
864 printed_len += 3;
865 }
866
797 if (printk_time) { 867 if (printk_time) {
798 /* Follow the token with the time */ 868 /* Add the current time stamp */
799 char tbuf[50], *tp; 869 char tbuf[50], *tp;
800 unsigned tlen; 870 unsigned tlen;
801 unsigned long long t; 871 unsigned long long t;