aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-06-25 18:01:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-25 20:00:38 -0400
commitd43ff430f434d862db59582c0f1f02382a678036 (patch)
tree1ade66d9cce26fc358a3d814bec1ad7bb06ec8cc /kernel/printk
parent4ae555a5313a302d36e34b3273545e4088c37cce (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.c34
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
508static 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 */
510struct devkmsg_user { 515struct 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
518static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) 523static 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;