Skip to content

Commit 637241a

Browse files
keestorvalds
authored andcommitted
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>
1 parent cf7df37 commit 637241a

File tree

3 files changed

+57
-48
lines changed

3 files changed

+57
-48
lines changed

fs/proc/kmsg.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,28 @@ extern wait_queue_head_t log_wait;
2121

2222
static int kmsg_open(struct inode * inode, struct file * file)
2323
{
24-
return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE);
24+
return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_PROC);
2525
}
2626

2727
static int kmsg_release(struct inode * inode, struct file * file)
2828
{
29-
(void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE);
29+
(void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_PROC);
3030
return 0;
3131
}
3232

3333
static ssize_t kmsg_read(struct file *file, char __user *buf,
3434
size_t count, loff_t *ppos)
3535
{
3636
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))
3838
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);
4040
}
4141

4242
static unsigned int kmsg_poll(struct file *file, poll_table *wait)
4343
{
4444
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))
4646
return POLLIN | POLLRDNORM;
4747
return 0;
4848
}

include/linux/syslog.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
/* Return size of the log buffer */
4545
#define SYSLOG_ACTION_SIZE_BUFFER 10
4646

47-
#define SYSLOG_FROM_CALL 0
48-
#define SYSLOG_FROM_FILE 1
47+
#define SYSLOG_FROM_READER 0
48+
#define SYSLOG_FROM_PROC 1
4949

5050
int do_syslog(int type, char __user *buf, int count, bool from_file);
5151

kernel/printk.c

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,53 @@ static void log_store(int facility, int level,
363363
log_next_seq++;
364364
}
365365

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+
366413
/* /dev/kmsg - userspace message inject/listen interface */
367414
struct devkmsg_user {
368415
u64 seq;
@@ -620,7 +667,8 @@ static int devkmsg_open(struct inode *inode, struct file *file)
620667
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
621668
return 0;
622669

623-
err = security_syslog(SYSLOG_ACTION_READ_ALL);
670+
err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
671+
SYSLOG_FROM_READER);
624672
if (err)
625673
return err;
626674

@@ -813,45 +861,6 @@ static inline void boot_delay_msec(int level)
813861
}
814862
#endif
815863

816-
#ifdef CONFIG_SECURITY_DMESG_RESTRICT
817-
int dmesg_restrict = 1;
818-
#else
819-
int dmesg_restrict;
820-
#endif
821-
822-
static int syslog_action_restricted(int type)
823-
{
824-
if (dmesg_restrict)
825-
return 1;
826-
/* Unless restricted, we allow "read all" and "get buffer size" for everybody */
827-
return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
828-
}
829-
830-
static int check_syslog_permissions(int type, bool from_file)
831-
{
832-
/*
833-
* If this is from /proc/kmsg and we've already opened it, then we've
834-
* already done the capabilities checks at open time.
835-
*/
836-
if (from_file && type != SYSLOG_ACTION_OPEN)
837-
return 0;
838-
839-
if (syslog_action_restricted(type)) {
840-
if (capable(CAP_SYSLOG))
841-
return 0;
842-
/* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
843-
if (capable(CAP_SYS_ADMIN)) {
844-
printk_once(KERN_WARNING "%s (%d): "
845-
"Attempt to access syslog with CAP_SYS_ADMIN "
846-
"but no CAP_SYSLOG (deprecated).\n",
847-
current->comm, task_pid_nr(current));
848-
return 0;
849-
}
850-
return -EPERM;
851-
}
852-
return 0;
853-
}
854-
855864
#if defined(CONFIG_PRINTK_TIME)
856865
static bool printk_time = 1;
857866
#else
@@ -1249,7 +1258,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
12491258

12501259
SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
12511260
{
1252-
return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
1261+
return do_syslog(type, buf, len, SYSLOG_FROM_READER);
12531262
}
12541263

12551264
/*

0 commit comments

Comments
 (0)