Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kmsg: honor dmesg_restrict sysctl on /dev/kmsg

The dmesg_restrict sysctl currently covers the syslog method for access
dmesg, however /dev/kmsg isn't covered by the same protections. Most
people haven't noticed because util-linux dmesg(1) defaults to using the
syslog method for access in older versions. With util-linux dmesg(1)
defaults to reading directly from /dev/kmsg.

To fix /dev/kmsg, let's compare the existing interfaces and what they
allow:

- /proc/kmsg allows:
- open (SYSLOG_ACTION_OPEN) if CAP_SYSLOG since it uses a destructive
single-reader interface (SYSLOG_ACTION_READ).
- everything, after an open.

- syslog syscall allows:
- anything, if CAP_SYSLOG.
- SYSLOG_ACTION_READ_ALL and SYSLOG_ACTION_SIZE_BUFFER, if
dmesg_restrict==0.
- nothing else (EPERM).

The use-cases were:
- dmesg(1) needs to do non-destructive SYSLOG_ACTION_READ_ALLs.
- sysklog(1) needs to open /proc/kmsg, drop privs, and still issue the
destructive SYSLOG_ACTION_READs.

AIUI, dmesg(1) is moving to /dev/kmsg, and systemd-journald doesn't
clear the ring buffer.

Based on the comments in devkmsg_llseek, it sounds like actions besides
reading aren't going to be supported by /dev/kmsg (i.e.
SYSLOG_ACTION_CLEAR), so we have a strict subset of the non-destructive
syslog syscall actions.

To this end, move the check as Josh had done, but also rename the
constants to reflect their new uses (SYSLOG_FROM_CALL becomes
SYSLOG_FROM_READER, and SYSLOG_FROM_FILE becomes SYSLOG_FROM_PROC).
SYSLOG_FROM_READER allows non-destructive actions, and SYSLOG_FROM_PROC
allows destructive actions after a capabilities-constrained
SYSLOG_ACTION_OPEN check.

- /dev/kmsg allows:
- open if CAP_SYSLOG or dmesg_restrict==0
- reading/polling, after open

Addresses https://bugzilla.redhat.com/show_bug.cgi?id=903192

[akpm@linux-foundation.org: use pr_warn_once()]
Signed-off-by: Kees Cook <keescook@chromium.org>
Reported-by: Christian Kujau <lists@nerdbynature.de>
Tested-by: Josh Boyer <jwboyer@redhat.com>
Cc: Kay Sievers <kay@vrfy.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kees Cook and committed by
Linus Torvalds
637241a9 cf7df378

+57 -48
+5 -5
fs/proc/kmsg.c
··· 21 21 22 22 static int kmsg_open(struct inode * inode, struct file * file) 23 23 { 24 - return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE); 24 + return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_PROC); 25 25 } 26 26 27 27 static int kmsg_release(struct inode * inode, struct file * file) 28 28 { 29 - (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE); 29 + (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_PROC); 30 30 return 0; 31 31 } 32 32 ··· 34 34 size_t count, loff_t *ppos) 35 35 { 36 36 if ((file->f_flags & O_NONBLOCK) && 37 - !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) 37 + !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_PROC)) 38 38 return -EAGAIN; 39 - return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_FILE); 39 + return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_PROC); 40 40 } 41 41 42 42 static unsigned int kmsg_poll(struct file *file, poll_table *wait) 43 43 { 44 44 poll_wait(file, &log_wait, wait); 45 - if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) 45 + if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_PROC)) 46 46 return POLLIN | POLLRDNORM; 47 47 return 0; 48 48 }
+2 -2
include/linux/syslog.h
··· 44 44 /* Return size of the log buffer */ 45 45 #define SYSLOG_ACTION_SIZE_BUFFER 10 46 46 47 - #define SYSLOG_FROM_CALL 0 48 - #define SYSLOG_FROM_FILE 1 47 + #define SYSLOG_FROM_READER 0 48 + #define SYSLOG_FROM_PROC 1 49 49 50 50 int do_syslog(int type, char __user *buf, int count, bool from_file); 51 51
+50 -41
kernel/printk.c
··· 363 363 log_next_seq++; 364 364 } 365 365 366 + #ifdef CONFIG_SECURITY_DMESG_RESTRICT 367 + int dmesg_restrict = 1; 368 + #else 369 + int dmesg_restrict; 370 + #endif 371 + 372 + static int syslog_action_restricted(int type) 373 + { 374 + if (dmesg_restrict) 375 + return 1; 376 + /* 377 + * Unless restricted, we allow "read all" and "get buffer size" 378 + * for everybody. 379 + */ 380 + return type != SYSLOG_ACTION_READ_ALL && 381 + type != SYSLOG_ACTION_SIZE_BUFFER; 382 + } 383 + 384 + static int check_syslog_permissions(int type, bool from_file) 385 + { 386 + /* 387 + * If this is from /proc/kmsg and we've already opened it, then we've 388 + * already done the capabilities checks at open time. 389 + */ 390 + if (from_file && type != SYSLOG_ACTION_OPEN) 391 + return 0; 392 + 393 + if (syslog_action_restricted(type)) { 394 + if (capable(CAP_SYSLOG)) 395 + return 0; 396 + /* 397 + * For historical reasons, accept CAP_SYS_ADMIN too, with 398 + * a warning. 399 + */ 400 + if (capable(CAP_SYS_ADMIN)) { 401 + pr_warn_once("%s (%d): Attempt to access syslog with " 402 + "CAP_SYS_ADMIN but no CAP_SYSLOG " 403 + "(deprecated).\n", 404 + current->comm, task_pid_nr(current)); 405 + return 0; 406 + } 407 + return -EPERM; 408 + } 409 + return security_syslog(type); 410 + } 411 + 412 + 366 413 /* /dev/kmsg - userspace message inject/listen interface */ 367 414 struct devkmsg_user { 368 415 u64 seq; ··· 667 620 if ((file->f_flags & O_ACCMODE) == O_WRONLY) 668 621 return 0; 669 622 670 - err = security_syslog(SYSLOG_ACTION_READ_ALL); 623 + err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL, 624 + SYSLOG_FROM_READER); 671 625 if (err) 672 626 return err; 673 627 ··· 860 812 { 861 813 } 862 814 #endif 863 - 864 - #ifdef CONFIG_SECURITY_DMESG_RESTRICT 865 - int dmesg_restrict = 1; 866 - #else 867 - int dmesg_restrict; 868 - #endif 869 - 870 - static int syslog_action_restricted(int type) 871 - { 872 - if (dmesg_restrict) 873 - return 1; 874 - /* Unless restricted, we allow "read all" and "get buffer size" for everybody */ 875 - return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER; 876 - } 877 - 878 - static int check_syslog_permissions(int type, bool from_file) 879 - { 880 - /* 881 - * If this is from /proc/kmsg and we've already opened it, then we've 882 - * already done the capabilities checks at open time. 883 - */ 884 - if (from_file && type != SYSLOG_ACTION_OPEN) 885 - return 0; 886 - 887 - if (syslog_action_restricted(type)) { 888 - if (capable(CAP_SYSLOG)) 889 - return 0; 890 - /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ 891 - if (capable(CAP_SYS_ADMIN)) { 892 - printk_once(KERN_WARNING "%s (%d): " 893 - "Attempt to access syslog with CAP_SYS_ADMIN " 894 - "but no CAP_SYSLOG (deprecated).\n", 895 - current->comm, task_pid_nr(current)); 896 - return 0; 897 - } 898 - return -EPERM; 899 - } 900 - return 0; 901 - } 902 815 903 816 #if defined(CONFIG_PRINTK_TIME) 904 817 static bool printk_time = 1; ··· 1258 1249 1259 1250 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) 1260 1251 { 1261 - return do_syslog(type, buf, len, SYSLOG_FROM_CALL); 1252 + return do_syslog(type, buf, len, SYSLOG_FROM_READER); 1262 1253 } 1263 1254 1264 1255 /*