aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <kees.cook@canonical.com>2010-02-03 18:36:43 -0500
committerJames Morris <jmorris@namei.org>2010-02-03 22:20:12 -0500
commit002345925e6c45861f60db6f4fc6236713fd8847 (patch)
treed7849eafe1755116597166bbebf43e2bee86cb76
parent0719aaf5ead7555b7b7a4a080ebf2826a871384e (diff)
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>
-rw-r--r--fs/proc/kmsg.c14
-rw-r--r--include/linux/security.h11
-rw-r--r--include/linux/syslog.h29
-rw-r--r--kernel/printk.c7
-rw-r--r--security/commoncap.c7
-rw-r--r--security/security.c4
-rw-r--r--security/selinux/hooks.c5
-rw-r--r--security/smack/smack_lsm.c4
8 files changed, 59 insertions, 22 deletions
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 7ca78346d3f0..6a3d843a1088 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -12,37 +12,37 @@
12#include <linux/poll.h> 12#include <linux/poll.h>
13#include <linux/proc_fs.h> 13#include <linux/proc_fs.h>
14#include <linux/fs.h> 14#include <linux/fs.h>
15#include <linux/syslog.h>
15 16
16#include <asm/uaccess.h> 17#include <asm/uaccess.h>
17#include <asm/io.h> 18#include <asm/io.h>
18 19
19extern wait_queue_head_t log_wait; 20extern wait_queue_head_t log_wait;
20 21
21extern int do_syslog(int type, char __user *bug, int count);
22
23static int kmsg_open(struct inode * inode, struct file * file) 22static 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
28static int kmsg_release(struct inode * inode, struct file * file) 27static 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 return 0; 30 return 0;
32} 31}
33 32
34static ssize_t kmsg_read(struct file *file, char __user *buf, 33static ssize_t kmsg_read(struct file *file, char __user *buf,
35 size_t count, loff_t *ppos) 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 return -EAGAIN; 38 return -EAGAIN;
39 return do_syslog(2, buf, count); 39 return do_syslog(2, buf, count, SYSLOG_FROM_FILE);
40} 40}
41 41
42static unsigned int kmsg_poll(struct file *file, poll_table *wait) 42static unsigned int kmsg_poll(struct file *file, poll_table *wait)
43{ 43{
44 poll_wait(file, &log_wait, wait); 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 return POLLIN | POLLRDNORM; 46 return POLLIN | POLLRDNORM;
47 return 0; 47 return 0;
48} 48}
diff --git a/include/linux/security.h b/include/linux/security.h
index 26eca85b2417..a4dc74d86ac6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -76,7 +76,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
76extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); 76extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
77extern int cap_task_setioprio(struct task_struct *p, int ioprio); 77extern int cap_task_setioprio(struct task_struct *p, int ioprio);
78extern int cap_task_setnice(struct task_struct *p, int nice); 78extern int cap_task_setnice(struct task_struct *p, int nice);
79extern int cap_syslog(int type); 79extern int cap_syslog(int type, bool from_file);
80extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); 80extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
81 81
82struct msghdr; 82struct msghdr;
@@ -1349,6 +1349,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
1349 * logging to the console. 1349 * logging to the console.
1350 * See the syslog(2) manual page for an explanation of the @type values. 1350 * See the syslog(2) manual page for an explanation of the @type values.
1351 * @type contains the type of action. 1351 * @type contains the type of action.
1352 * @from_file indicates the context of action (if it came from /proc).
1352 * Return 0 if permission is granted. 1353 * Return 0 if permission is granted.
1353 * @settime: 1354 * @settime:
1354 * Check permission to change the system time. 1355 * Check permission to change the system time.
@@ -1463,7 +1464,7 @@ struct security_operations {
1463 int (*sysctl) (struct ctl_table *table, int op); 1464 int (*sysctl) (struct ctl_table *table, int op);
1464 int (*quotactl) (int cmds, int type, int id, struct super_block *sb); 1465 int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
1465 int (*quota_on) (struct dentry *dentry); 1466 int (*quota_on) (struct dentry *dentry);
1466 int (*syslog) (int type); 1467 int (*syslog) (int type, bool from_file);
1467 int (*settime) (struct timespec *ts, struct timezone *tz); 1468 int (*settime) (struct timespec *ts, struct timezone *tz);
1468 int (*vm_enough_memory) (struct mm_struct *mm, long pages); 1469 int (*vm_enough_memory) (struct mm_struct *mm, long pages);
1469 1470
@@ -1762,7 +1763,7 @@ int security_acct(struct file *file);
1762int security_sysctl(struct ctl_table *table, int op); 1763int security_sysctl(struct ctl_table *table, int op);
1763int security_quotactl(int cmds, int type, int id, struct super_block *sb); 1764int security_quotactl(int cmds, int type, int id, struct super_block *sb);
1764int security_quota_on(struct dentry *dentry); 1765int security_quota_on(struct dentry *dentry);
1765int security_syslog(int type); 1766int security_syslog(int type, bool from_file);
1766int security_settime(struct timespec *ts, struct timezone *tz); 1767int security_settime(struct timespec *ts, struct timezone *tz);
1767int security_vm_enough_memory(long pages); 1768int security_vm_enough_memory(long pages);
1768int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); 1769int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
@@ -2008,9 +2009,9 @@ static inline int security_quota_on(struct dentry *dentry)
2008 return 0; 2009 return 0;
2009} 2010}
2010 2011
2011static inline int security_syslog(int type) 2012static 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
2016static inline int security_settime(struct timespec *ts, struct timezone *tz) 2017static inline int security_settime(struct timespec *ts, struct timezone *tz)
diff --git a/include/linux/syslog.h b/include/linux/syslog.h
new file mode 100644
index 000000000000..5f02b1817be1
--- /dev/null
+++ b/include/linux/syslog.h
@@ -0,0 +1,29 @@
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
27int do_syslog(int type, char __user *buf, int count, bool from_file);
28
29#endif /* _LINUX_SYSLOG_H */
diff --git a/kernel/printk.c b/kernel/printk.c
index 17463ca2e229..809cf9a258a0 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -35,6 +35,7 @@
35#include <linux/kexec.h> 35#include <linux/kexec.h>
36#include <linux/ratelimit.h> 36#include <linux/ratelimit.h>
37#include <linux/kmsg_dump.h> 37#include <linux/kmsg_dump.h>
38#include <linux/syslog.h>
38 39
39#include <asm/uaccess.h> 40#include <asm/uaccess.h>
40 41
@@ -273,14 +274,14 @@ static inline void boot_delay_msec(void)
273 * 9 -- Return number of unread characters in the log buffer 274 * 9 -- Return number of unread characters in the log buffer
274 * 10 -- Return size of the log buffer 275 * 10 -- Return size of the log buffer
275 */ 276 */
276int do_syslog(int type, char __user *buf, int len) 277int do_syslog(int type, char __user *buf, int len, bool from_file)
277{ 278{
278 unsigned i, j, limit, count; 279 unsigned i, j, limit, count;
279 int do_clear = 0; 280 int do_clear = 0;
280 char c; 281 char c;
281 int error = 0; 282 int error = 0;
282 283
283 error = security_syslog(type); 284 error = security_syslog(type, from_file);
284 if (error) 285 if (error)
285 return error; 286 return error;
286 287
@@ -417,7 +418,7 @@ out:
417 418
418SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) 419SYSCALL_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/*
diff --git a/security/commoncap.c b/security/commoncap.c
index f800fdb3de94..677fad9d5cba 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -27,6 +27,7 @@
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/prctl.h> 28#include <linux/prctl.h>
29#include <linux/securebits.h> 29#include <linux/securebits.h>
30#include <linux/syslog.h>
30 31
31/* 32/*
32 * If a non-root user executes a setuid-root binary in 33 * If a non-root user executes a setuid-root binary in
@@ -888,12 +889,16 @@ error:
888/** 889/**
889 * cap_syslog - Determine whether syslog function is permitted 890 * cap_syslog - Determine whether syslog function is permitted
890 * @type: Function requested 891 * @type: Function requested
892 * @from_file: Whether this request came from an open file (i.e. /proc)
891 * 893 *
892 * Determine whether the current process is permitted to use a particular 894 * Determine whether the current process is permitted to use a particular
893 * syslog function, returning 0 if permission is granted, -ve if not. 895 * syslog function, returning 0 if permission is granted, -ve if not.
894 */ 896 */
895int cap_syslog(int type) 897int 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 if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) 902 if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
898 return -EPERM; 903 return -EPERM;
899 return 0; 904 return 0;
diff --git a/security/security.c b/security/security.c
index 440afe5eb54c..971092c06f31 100644
--- a/security/security.c
+++ b/security/security.c
@@ -203,9 +203,9 @@ int security_quota_on(struct dentry *dentry)
203 return security_ops->quota_on(dentry); 203 return security_ops->quota_on(dentry);
204} 204}
205 205
206int security_syslog(int type) 206int 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
211int security_settime(struct timespec *ts, struct timezone *tz) 211int security_settime(struct timespec *ts, struct timezone *tz)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9a2ee845e9d4..a4862a0730fa 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -76,6 +76,7 @@
76#include <linux/selinux.h> 76#include <linux/selinux.h>
77#include <linux/mutex.h> 77#include <linux/mutex.h>
78#include <linux/posix-timers.h> 78#include <linux/posix-timers.h>
79#include <linux/syslog.h>
79 80
80#include "avc.h" 81#include "avc.h"
81#include "objsec.h" 82#include "objsec.h"
@@ -2049,11 +2050,11 @@ static int selinux_quota_on(struct dentry *dentry)
2049 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); 2050 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
2050} 2051}
2051 2052
2052static int selinux_syslog(int type) 2053static int selinux_syslog(int type, bool from_file)
2053{ 2054{
2054 int rc; 2055 int rc;
2055 2056
2056 rc = cap_syslog(type); 2057 rc = cap_syslog(type, from_file);
2057 if (rc) 2058 if (rc)
2058 return rc; 2059 return rc;
2059 2060
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 529c9ca65878..a5721b373f53 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
157 * 157 *
158 * Returns 0 on success, error code otherwise. 158 * Returns 0 on success, error code otherwise.
159 */ 159 */
160static int smack_syslog(int type) 160static int smack_syslog(int type, bool from_file)
161{ 161{
162 int rc; 162 int rc;
163 char *sp = current_security(); 163 char *sp = current_security();
164 164
165 rc = cap_syslog(type); 165 rc = cap_syslog(type, from_file);
166 if (rc != 0) 166 if (rc != 0)
167 return rc; 167 return rc;
168 168