diff options
author | Tejun Heo <tj@kernel.org> | 2015-06-25 18:01:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-25 20:00:38 -0400 |
commit | d43ff430f434d862db59582c0f1f02382a678036 (patch) | |
tree | 1ade66d9cce26fc358a3d814bec1ad7bb06ec8cc /kernel/printk | |
parent | 4ae555a5313a302d36e34b3273545e4088c37cce (diff) |
printk: guard the amount written per line by devkmsg_read()
This patchset updates netconsole so that it can emit messages with the
same header as used in /dev/kmsg which gives neconsole receiver full log
information which enables things like structured logging and detection
of lost messages.
This patch (of 7):
devkmsg_read() uses 8k buffer and assumes that the formatted output
message won't overrun which seems safe given LOG_LINE_MAX, the current use
of dict and the escaping method being used; however, we're planning to use
devkmsg formatting wider and accounting for the buffer size properly isn't
that complicated.
This patch defines CONSOLE_EXT_LOG_MAX as 8192 and updates devkmsg_read()
so that it limits output accordingly.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: David Miller <davem@davemloft.net>
Cc: Kay Sievers <kay@vrfy.org>
Reviewed-by: Petr Mladek <pmladek@suse.cz>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/printk')
-rw-r--r-- | kernel/printk/printk.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index c099b082cd02..a11549034e07 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c | |||
@@ -505,6 +505,11 @@ int check_syslog_permissions(int type, bool from_file) | |||
505 | return security_syslog(type); | 505 | return security_syslog(type); |
506 | } | 506 | } |
507 | 507 | ||
508 | static void append_char(char **pp, char *e, char c) | ||
509 | { | ||
510 | if (*pp < e) | ||
511 | *(*pp)++ = c; | ||
512 | } | ||
508 | 513 | ||
509 | /* /dev/kmsg - userspace message inject/listen interface */ | 514 | /* /dev/kmsg - userspace message inject/listen interface */ |
510 | struct devkmsg_user { | 515 | struct devkmsg_user { |
@@ -512,7 +517,7 @@ struct devkmsg_user { | |||
512 | u32 idx; | 517 | u32 idx; |
513 | enum log_flags prev; | 518 | enum log_flags prev; |
514 | struct mutex lock; | 519 | struct mutex lock; |
515 | char buf[8192]; | 520 | char buf[CONSOLE_EXT_LOG_MAX]; |
516 | }; | 521 | }; |
517 | 522 | ||
518 | static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) | 523 | static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) |
@@ -570,6 +575,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
570 | { | 575 | { |
571 | struct devkmsg_user *user = file->private_data; | 576 | struct devkmsg_user *user = file->private_data; |
572 | struct printk_log *msg; | 577 | struct printk_log *msg; |
578 | char *p, *e; | ||
573 | u64 ts_usec; | 579 | u64 ts_usec; |
574 | size_t i; | 580 | size_t i; |
575 | char cont = '-'; | 581 | char cont = '-'; |
@@ -579,6 +585,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
579 | if (!user) | 585 | if (!user) |
580 | return -EBADF; | 586 | return -EBADF; |
581 | 587 | ||
588 | p = user->buf; | ||
589 | e = user->buf + sizeof(user->buf); | ||
590 | |||
582 | ret = mutex_lock_interruptible(&user->lock); | 591 | ret = mutex_lock_interruptible(&user->lock); |
583 | if (ret) | 592 | if (ret) |
584 | return ret; | 593 | return ret; |
@@ -625,9 +634,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
625 | ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))) | 634 | ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))) |
626 | cont = '+'; | 635 | cont = '+'; |
627 | 636 | ||
628 | len = sprintf(user->buf, "%u,%llu,%llu,%c;", | 637 | p += scnprintf(p, e - p, "%u,%llu,%llu,%c;", |
629 | (msg->facility << 3) | msg->level, | 638 | (msg->facility << 3) | msg->level, |
630 | user->seq, ts_usec, cont); | 639 | user->seq, ts_usec, cont); |
631 | user->prev = msg->flags; | 640 | user->prev = msg->flags; |
632 | 641 | ||
633 | /* escape non-printable characters */ | 642 | /* escape non-printable characters */ |
@@ -635,11 +644,11 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
635 | unsigned char c = log_text(msg)[i]; | 644 | unsigned char c = log_text(msg)[i]; |
636 | 645 | ||
637 | if (c < ' ' || c >= 127 || c == '\\') | 646 | if (c < ' ' || c >= 127 || c == '\\') |
638 | len += sprintf(user->buf + len, "\\x%02x", c); | 647 | p += scnprintf(p, e - p, "\\x%02x", c); |
639 | else | 648 | else |
640 | user->buf[len++] = c; | 649 | append_char(&p, e, c); |
641 | } | 650 | } |
642 | user->buf[len++] = '\n'; | 651 | append_char(&p, e, '\n'); |
643 | 652 | ||
644 | if (msg->dict_len) { | 653 | if (msg->dict_len) { |
645 | bool line = true; | 654 | bool line = true; |
@@ -648,30 +657,31 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
648 | unsigned char c = log_dict(msg)[i]; | 657 | unsigned char c = log_dict(msg)[i]; |
649 | 658 | ||
650 | if (line) { | 659 | if (line) { |
651 | user->buf[len++] = ' '; | 660 | append_char(&p, e, ' '); |
652 | line = false; | 661 | line = false; |
653 | } | 662 | } |
654 | 663 | ||
655 | if (c == '\0') { | 664 | if (c == '\0') { |
656 | user->buf[len++] = '\n'; | 665 | append_char(&p, e, '\n'); |
657 | line = true; | 666 | line = true; |
658 | continue; | 667 | continue; |
659 | } | 668 | } |
660 | 669 | ||
661 | if (c < ' ' || c >= 127 || c == '\\') { | 670 | if (c < ' ' || c >= 127 || c == '\\') { |
662 | len += sprintf(user->buf + len, "\\x%02x", c); | 671 | p += scnprintf(p, e - p, "\\x%02x", c); |
663 | continue; | 672 | continue; |
664 | } | 673 | } |
665 | 674 | ||
666 | user->buf[len++] = c; | 675 | append_char(&p, e, c); |
667 | } | 676 | } |
668 | user->buf[len++] = '\n'; | 677 | append_char(&p, e, '\n'); |
669 | } | 678 | } |
670 | 679 | ||
671 | user->idx = log_next(user->idx); | 680 | user->idx = log_next(user->idx); |
672 | user->seq++; | 681 | user->seq++; |
673 | raw_spin_unlock_irq(&logbuf_lock); | 682 | raw_spin_unlock_irq(&logbuf_lock); |
674 | 683 | ||
684 | len = p - user->buf; | ||
675 | if (len > count) { | 685 | if (len > count) { |
676 | ret = -EINVAL; | 686 | ret = -EINVAL; |
677 | goto out; | 687 | goto out; |