Commit 002345925e6c45861f60db6f4fc6236713fd8847

Authored by Kees Cook
Committed by James Morris
1 parent 0719aaf5ea

syslog: distinguish between /proc/kmsg and syscalls

This allows the LSM to distinguish between syslog functions originating
from /proc/kmsg access and direct syscalls.  By default, the commoncaps
will now no longer require CAP_SYS_ADMIN to read an opened /proc/kmsg
file descriptor.  For example the kernel syslog reader can now drop
privileges after opening /proc/kmsg, instead of staying privileged with
CAP_SYS_ADMIN.  MAC systems that implement security_syslog have unchanged
behavior.

Signed-off-by: Kees Cook <kees.cook@canonical.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>

Showing 8 changed files with 59 additions and 22 deletions Side-by-side Diff

... ... @@ -12,37 +12,37 @@
12 12 #include <linux/poll.h>
13 13 #include <linux/proc_fs.h>
14 14 #include <linux/fs.h>
  15 +#include <linux/syslog.h>
15 16  
16 17 #include <asm/uaccess.h>
17 18 #include <asm/io.h>
18 19  
19 20 extern wait_queue_head_t log_wait;
20 21  
21   -extern int do_syslog(int type, char __user *bug, int count);
22   -
23 22 static int kmsg_open(struct inode * inode, struct file * file)
24 23 {
25   - return do_syslog(1,NULL,0);
  24 + return do_syslog(1, NULL, 0, SYSLOG_FROM_FILE);
26 25 }
27 26  
28 27 static int kmsg_release(struct inode * inode, struct file * file)
29 28 {
30   - (void) do_syslog(0,NULL,0);
  29 + (void) do_syslog(0, NULL, 0, SYSLOG_FROM_FILE);
31 30 return 0;
32 31 }
33 32  
34 33 static ssize_t kmsg_read(struct file *file, char __user *buf,
35 34 size_t count, loff_t *ppos)
36 35 {
37   - if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0))
  36 + if ((file->f_flags & O_NONBLOCK) &&
  37 + !do_syslog(9, NULL, 0, SYSLOG_FROM_FILE))
38 38 return -EAGAIN;
39   - return do_syslog(2, buf, count);
  39 + return do_syslog(2, buf, count, SYSLOG_FROM_FILE);
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(9, NULL, 0))
  45 + if (do_syslog(9, NULL, 0, SYSLOG_FROM_FILE))
46 46 return POLLIN | POLLRDNORM;
47 47 return 0;
48 48 }
include/linux/security.h
... ... @@ -76,7 +76,7 @@
76 76 extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
77 77 extern int cap_task_setioprio(struct task_struct *p, int ioprio);
78 78 extern int cap_task_setnice(struct task_struct *p, int nice);
79   -extern int cap_syslog(int type);
  79 +extern int cap_syslog(int type, bool from_file);
80 80 extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
81 81  
82 82 struct msghdr;
... ... @@ -1349,6 +1349,7 @@
1349 1349 * logging to the console.
1350 1350 * See the syslog(2) manual page for an explanation of the @type values.
1351 1351 * @type contains the type of action.
  1352 + * @from_file indicates the context of action (if it came from /proc).
1352 1353 * Return 0 if permission is granted.
1353 1354 * @settime:
1354 1355 * Check permission to change the system time.
... ... @@ -1463,7 +1464,7 @@
1463 1464 int (*sysctl) (struct ctl_table *table, int op);
1464 1465 int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
1465 1466 int (*quota_on) (struct dentry *dentry);
1466   - int (*syslog) (int type);
  1467 + int (*syslog) (int type, bool from_file);
1467 1468 int (*settime) (struct timespec *ts, struct timezone *tz);
1468 1469 int (*vm_enough_memory) (struct mm_struct *mm, long pages);
1469 1470  
... ... @@ -1762,7 +1763,7 @@
1762 1763 int security_sysctl(struct ctl_table *table, int op);
1763 1764 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
1764 1765 int security_quota_on(struct dentry *dentry);
1765   -int security_syslog(int type);
  1766 +int security_syslog(int type, bool from_file);
1766 1767 int security_settime(struct timespec *ts, struct timezone *tz);
1767 1768 int security_vm_enough_memory(long pages);
1768 1769 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
1769 1770  
... ... @@ -2008,9 +2009,9 @@
2008 2009 return 0;
2009 2010 }
2010 2011  
2011   -static inline int security_syslog(int type)
  2012 +static inline int security_syslog(int type, bool from_file)
2012 2013 {
2013   - return cap_syslog(type);
  2014 + return cap_syslog(type, from_file);
2014 2015 }
2015 2016  
2016 2017 static inline int security_settime(struct timespec *ts, struct timezone *tz)
include/linux/syslog.h
  1 +/* Syslog internals
  2 + *
  3 + * Copyright 2010 Canonical, Ltd.
  4 + * Author: Kees Cook <kees.cook@canonical.com>
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; either version 2, or (at your option)
  9 + * any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; see the file COPYING. If not, write to
  18 + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19 + */
  20 +
  21 +#ifndef _LINUX_SYSLOG_H
  22 +#define _LINUX_SYSLOG_H
  23 +
  24 +#define SYSLOG_FROM_CALL 0
  25 +#define SYSLOG_FROM_FILE 1
  26 +
  27 +int do_syslog(int type, char __user *buf, int count, bool from_file);
  28 +
  29 +#endif /* _LINUX_SYSLOG_H */
... ... @@ -35,6 +35,7 @@
35 35 #include <linux/kexec.h>
36 36 #include <linux/ratelimit.h>
37 37 #include <linux/kmsg_dump.h>
  38 +#include <linux/syslog.h>
38 39  
39 40 #include <asm/uaccess.h>
40 41  
41 42  
... ... @@ -273,14 +274,14 @@
273 274 * 9 -- Return number of unread characters in the log buffer
274 275 * 10 -- Return size of the log buffer
275 276 */
276   -int do_syslog(int type, char __user *buf, int len)
  277 +int do_syslog(int type, char __user *buf, int len, bool from_file)
277 278 {
278 279 unsigned i, j, limit, count;
279 280 int do_clear = 0;
280 281 char c;
281 282 int error = 0;
282 283  
283   - error = security_syslog(type);
  284 + error = security_syslog(type, from_file);
284 285 if (error)
285 286 return error;
286 287  
... ... @@ -417,7 +418,7 @@
417 418  
418 419 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
419 420 {
420   - return do_syslog(type, buf, len);
  421 + return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
421 422 }
422 423  
423 424 /*
security/commoncap.c
... ... @@ -27,6 +27,7 @@
27 27 #include <linux/sched.h>
28 28 #include <linux/prctl.h>
29 29 #include <linux/securebits.h>
  30 +#include <linux/syslog.h>
30 31  
31 32 /*
32 33 * If a non-root user executes a setuid-root binary in
33 34  
34 35  
... ... @@ -888,12 +889,16 @@
888 889 /**
889 890 * cap_syslog - Determine whether syslog function is permitted
890 891 * @type: Function requested
  892 + * @from_file: Whether this request came from an open file (i.e. /proc)
891 893 *
892 894 * Determine whether the current process is permitted to use a particular
893 895 * syslog function, returning 0 if permission is granted, -ve if not.
894 896 */
895   -int cap_syslog(int type)
  897 +int cap_syslog(int type, bool from_file)
896 898 {
  899 + /* /proc/kmsg can open be opened by CAP_SYS_ADMIN */
  900 + if (type != 1 && from_file)
  901 + return 0;
897 902 if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
898 903 return -EPERM;
899 904 return 0;
... ... @@ -203,9 +203,9 @@
203 203 return security_ops->quota_on(dentry);
204 204 }
205 205  
206   -int security_syslog(int type)
  206 +int security_syslog(int type, bool from_file)
207 207 {
208   - return security_ops->syslog(type);
  208 + return security_ops->syslog(type, from_file);
209 209 }
210 210  
211 211 int security_settime(struct timespec *ts, struct timezone *tz)
security/selinux/hooks.c
... ... @@ -76,6 +76,7 @@
76 76 #include <linux/selinux.h>
77 77 #include <linux/mutex.h>
78 78 #include <linux/posix-timers.h>
  79 +#include <linux/syslog.h>
79 80  
80 81 #include "avc.h"
81 82 #include "objsec.h"
82 83  
... ... @@ -2049,11 +2050,11 @@
2049 2050 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
2050 2051 }
2051 2052  
2052   -static int selinux_syslog(int type)
  2053 +static int selinux_syslog(int type, bool from_file)
2053 2054 {
2054 2055 int rc;
2055 2056  
2056   - rc = cap_syslog(type);
  2057 + rc = cap_syslog(type, from_file);
2057 2058 if (rc)
2058 2059 return rc;
2059 2060  
security/smack/smack_lsm.c
... ... @@ -157,12 +157,12 @@
157 157 *
158 158 * Returns 0 on success, error code otherwise.
159 159 */
160   -static int smack_syslog(int type)
  160 +static int smack_syslog(int type, bool from_file)
161 161 {
162 162 int rc;
163 163 char *sp = current_security();
164 164  
165   - rc = cap_syslog(type);
  165 + rc = cap_syslog(type, from_file);
166 166 if (rc != 0)
167 167 return rc;
168 168