aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-12-31 10:15:42 -0500
committerJames Morris <jmorris@namei.org>2009-01-04 19:17:04 -0500
commit14eaddc967b16017d4a1a24d2be6c28ecbe06ed8 (patch)
treece10216d592f0fa89ae02c4e4e9e9497010e7714 /security
parent5c8c40be4b5a2944483bfc1a45d6c3fa02551af3 (diff)
CRED: Fix regression in cap_capable() as shown up by sys_faccessat() [ver #2]
Fix a regression in cap_capable() due to: commit 5ff7711e635b32f0a1e558227d030c7e45b4a465 Author: David Howells <dhowells@redhat.com> Date: Wed Dec 31 02:52:28 2008 +0000 CRED: Differentiate objective and effective subjective credentials on a task The problem is that the above patch allows a process to have two sets of credentials, and for the most part uses the subjective credentials when accessing current's creds. There is, however, one exception: cap_capable(), and thus capable(), uses the real/objective credentials of the target task, whether or not it is the current task. Ordinarily this doesn't matter, since usually the two cred pointers in current point to the same set of creds. However, sys_faccessat() makes use of this facility to override the credentials of the calling process to make its test, without affecting the creds as seen from other processes. One of the things sys_faccessat() does is to make an adjustment to the effective capabilities mask, which cap_capable(), as it stands, then ignores. The affected capability check is in generic_permission(): if (!(mask & MAY_EXEC) || execute_ok(inode)) if (capable(CAP_DAC_OVERRIDE)) return 0; This change splits capable() from has_capability() down into the commoncap and SELinux code. The capable() security op now only deals with the current process, and uses the current process's subjective creds. A new security op - task_capable() - is introduced that can check any task's objective creds. strictly the capable() security op is superfluous with the presence of the task_capable() op, however it should be faster to call the capable() op since two fewer arguments need be passed down through the various layers. This can be tested by compiling the following program from the XFS testsuite: /* * t_access_root.c - trivial test program to show permission bug. * * Written by Michael Kerrisk - copyright ownership not pursued. * Sourced from: http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-10/6030.html */ #include <limits.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h> #define UID 500 #define GID 100 #define PERM 0 #define TESTPATH "/tmp/t_access" static void errExit(char *msg) { perror(msg); exit(EXIT_FAILURE); } /* errExit */ static void accessTest(char *file, int mask, char *mstr) { printf("access(%s, %s) returns %d\n", file, mstr, access(file, mask)); } /* accessTest */ int main(int argc, char *argv[]) { int fd, perm, uid, gid; char *testpath; char cmd[PATH_MAX + 20]; testpath = (argc > 1) ? argv[1] : TESTPATH; perm = (argc > 2) ? strtoul(argv[2], NULL, 8) : PERM; uid = (argc > 3) ? atoi(argv[3]) : UID; gid = (argc > 4) ? atoi(argv[4]) : GID; unlink(testpath); fd = open(testpath, O_RDWR | O_CREAT, 0); if (fd == -1) errExit("open"); if (fchown(fd, uid, gid) == -1) errExit("fchown"); if (fchmod(fd, perm) == -1) errExit("fchmod"); close(fd); snprintf(cmd, sizeof(cmd), "ls -l %s", testpath); system(cmd); if (seteuid(uid) == -1) errExit("seteuid"); accessTest(testpath, 0, "0"); accessTest(testpath, R_OK, "R_OK"); accessTest(testpath, W_OK, "W_OK"); accessTest(testpath, X_OK, "X_OK"); accessTest(testpath, R_OK | W_OK, "R_OK | W_OK"); accessTest(testpath, R_OK | X_OK, "R_OK | X_OK"); accessTest(testpath, W_OK | X_OK, "W_OK | X_OK"); accessTest(testpath, R_OK | W_OK | X_OK, "R_OK | W_OK | X_OK"); exit(EXIT_SUCCESS); } /* main */ This can be run against an Ext3 filesystem as well as against an XFS filesystem. If successful, it will show: [root@andromeda src]# ./t_access_root /tmp/xxx 0 4043 4043 ---------- 1 dhowells dhowells 0 2008-12-31 03:00 /tmp/xxx access(/tmp/xxx, 0) returns 0 access(/tmp/xxx, R_OK) returns 0 access(/tmp/xxx, W_OK) returns 0 access(/tmp/xxx, X_OK) returns -1 access(/tmp/xxx, R_OK | W_OK) returns 0 access(/tmp/xxx, R_OK | X_OK) returns -1 access(/tmp/xxx, W_OK | X_OK) returns -1 access(/tmp/xxx, R_OK | W_OK | X_OK) returns -1 If unsuccessful, it will show: [root@andromeda src]# ./t_access_root /tmp/xxx 0 4043 4043 ---------- 1 dhowells dhowells 0 2008-12-31 02:56 /tmp/xxx access(/tmp/xxx, 0) returns 0 access(/tmp/xxx, R_OK) returns -1 access(/tmp/xxx, W_OK) returns -1 access(/tmp/xxx, X_OK) returns -1 access(/tmp/xxx, R_OK | W_OK) returns -1 access(/tmp/xxx, R_OK | X_OK) returns -1 access(/tmp/xxx, W_OK | X_OK) returns -1 access(/tmp/xxx, R_OK | W_OK | X_OK) returns -1 I've also tested the fix with the SELinux and syscalls LTP testsuites. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/capability.c1
-rw-r--r--security/commoncap.c42
-rw-r--r--security/root_plug.c1
-rw-r--r--security/security.c25
-rw-r--r--security/selinux/hooks.c26
-rw-r--r--security/smack/smack_lsm.c1
6 files changed, 73 insertions, 23 deletions
diff --git a/security/capability.c b/security/capability.c
index 2dce66fcb992..fd1493da4f8d 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -826,6 +826,7 @@ void security_fixup_ops(struct security_operations *ops)
826 set_to_cap_if_null(ops, capset); 826 set_to_cap_if_null(ops, capset);
827 set_to_cap_if_null(ops, acct); 827 set_to_cap_if_null(ops, acct);
828 set_to_cap_if_null(ops, capable); 828 set_to_cap_if_null(ops, capable);
829 set_to_cap_if_null(ops, task_capable);
829 set_to_cap_if_null(ops, quotactl); 830 set_to_cap_if_null(ops, quotactl);
830 set_to_cap_if_null(ops, quota_on); 831 set_to_cap_if_null(ops, quota_on);
831 set_to_cap_if_null(ops, sysctl); 832 set_to_cap_if_null(ops, sysctl);
diff --git a/security/commoncap.c b/security/commoncap.c
index 79713545cd63..7f0b2a68717d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -43,28 +43,44 @@ int cap_netlink_recv(struct sk_buff *skb, int cap)
43EXPORT_SYMBOL(cap_netlink_recv); 43EXPORT_SYMBOL(cap_netlink_recv);
44 44
45/** 45/**
46 * cap_capable - Determine whether a task has a particular effective capability 46 * cap_capable - Determine whether current has a particular effective capability
47 * @tsk: The task to query
48 * @cap: The capability to check for 47 * @cap: The capability to check for
49 * @audit: Whether to write an audit message or not 48 * @audit: Whether to write an audit message or not
50 * 49 *
51 * Determine whether the nominated task has the specified capability amongst 50 * Determine whether the nominated task has the specified capability amongst
52 * its effective set, returning 0 if it does, -ve if it does not. 51 * its effective set, returning 0 if it does, -ve if it does not. Note that
52 * this uses current's subjective/effective credentials.
53 * 53 *
54 * NOTE WELL: cap_capable() cannot be used like the kernel's capable() 54 * NOTE WELL: cap_capable() cannot be used like the kernel's capable()
55 * function. That is, it has the reverse semantics: cap_capable() returns 0 55 * function. That is, it has the reverse semantics: cap_capable() returns 0
56 * when a task has a capability, but the kernel's capable() returns 1 for this 56 * when a task has a capability, but the kernel's capable() returns 1 for this
57 * case. 57 * case.
58 */ 58 */
59int cap_capable(struct task_struct *tsk, int cap, int audit) 59int cap_capable(int cap, int audit)
60{ 60{
61 __u32 cap_raised; 61 return cap_raised(current_cap(), cap) ? 0 : -EPERM;
62}
62 63
63 /* Derived from include/linux/sched.h:capable. */ 64/**
64 rcu_read_lock(); 65 * cap_has_capability - Determine whether a task has a particular effective capability
65 cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap); 66 * @tsk: The task to query
66 rcu_read_unlock(); 67 * @cred: The credentials to use
67 return cap_raised ? 0 : -EPERM; 68 * @cap: The capability to check for
69 * @audit: Whether to write an audit message or not
70 *
71 * Determine whether the nominated task has the specified capability amongst
72 * its effective set, returning 0 if it does, -ve if it does not. Note that
73 * this uses the task's objective/real credentials.
74 *
75 * NOTE WELL: cap_has_capability() cannot be used like the kernel's
76 * has_capability() function. That is, it has the reverse semantics:
77 * cap_has_capability() returns 0 when a task has a capability, but the
78 * kernel's has_capability() returns 1 for this case.
79 */
80int cap_task_capable(struct task_struct *tsk, const struct cred *cred, int cap,
81 int audit)
82{
83 return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
68} 84}
69 85
70/** 86/**
@@ -160,7 +176,7 @@ static inline int cap_inh_is_capped(void)
160 /* they are so limited unless the current task has the CAP_SETPCAP 176 /* they are so limited unless the current task has the CAP_SETPCAP
161 * capability 177 * capability
162 */ 178 */
163 if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) 179 if (cap_capable(CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
164 return 0; 180 return 0;
165#endif 181#endif
166 return 1; 182 return 1;
@@ -869,7 +885,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
869 & (new->securebits ^ arg2)) /*[1]*/ 885 & (new->securebits ^ arg2)) /*[1]*/
870 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ 886 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
871 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ 887 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
872 || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ 888 || (cap_capable(CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
873 /* 889 /*
874 * [1] no changing of bits that are locked 890 * [1] no changing of bits that are locked
875 * [2] no unlocking of locks 891 * [2] no unlocking of locks
@@ -950,7 +966,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
950{ 966{
951 int cap_sys_admin = 0; 967 int cap_sys_admin = 0;
952 968
953 if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) 969 if (cap_capable(CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
954 cap_sys_admin = 1; 970 cap_sys_admin = 1;
955 return __vm_enough_memory(mm, pages, cap_sys_admin); 971 return __vm_enough_memory(mm, pages, cap_sys_admin);
956} 972}
diff --git a/security/root_plug.c b/security/root_plug.c
index 40fb4f15e27b..559578f8ac66 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -77,6 +77,7 @@ static struct security_operations rootplug_security_ops = {
77 .capget = cap_capget, 77 .capget = cap_capget,
78 .capset = cap_capset, 78 .capset = cap_capset,
79 .capable = cap_capable, 79 .capable = cap_capable,
80 .task_capable = cap_task_capable,
80 81
81 .bprm_set_creds = cap_bprm_set_creds, 82 .bprm_set_creds = cap_bprm_set_creds,
82 83
diff --git a/security/security.c b/security/security.c
index d85dbb37c972..9bbc8e57b8c6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -154,14 +154,31 @@ int security_capset(struct cred *new, const struct cred *old,
154 effective, inheritable, permitted); 154 effective, inheritable, permitted);
155} 155}
156 156
157int security_capable(struct task_struct *tsk, int cap) 157int security_capable(int cap)
158{ 158{
159 return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT); 159 return security_ops->capable(cap, SECURITY_CAP_AUDIT);
160} 160}
161 161
162int security_capable_noaudit(struct task_struct *tsk, int cap) 162int security_task_capable(struct task_struct *tsk, int cap)
163{ 163{
164 return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT); 164 const struct cred *cred;
165 int ret;
166
167 cred = get_task_cred(tsk);
168 ret = security_ops->task_capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
169 put_cred(cred);
170 return ret;
171}
172
173int security_task_capable_noaudit(struct task_struct *tsk, int cap)
174{
175 const struct cred *cred;
176 int ret;
177
178 cred = get_task_cred(tsk);
179 ret = security_ops->task_capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
180 put_cred(cred);
181 return ret;
165} 182}
166 183
167int security_acct(struct file *file) 184int security_acct(struct file *file)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index df30a7555d8a..eb6c45107a05 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1433,12 +1433,13 @@ static int current_has_perm(const struct task_struct *tsk,
1433 1433
1434/* Check whether a task is allowed to use a capability. */ 1434/* Check whether a task is allowed to use a capability. */
1435static int task_has_capability(struct task_struct *tsk, 1435static int task_has_capability(struct task_struct *tsk,
1436 const struct cred *cred,
1436 int cap, int audit) 1437 int cap, int audit)
1437{ 1438{
1438 struct avc_audit_data ad; 1439 struct avc_audit_data ad;
1439 struct av_decision avd; 1440 struct av_decision avd;
1440 u16 sclass; 1441 u16 sclass;
1441 u32 sid = task_sid(tsk); 1442 u32 sid = cred_sid(cred);
1442 u32 av = CAP_TO_MASK(cap); 1443 u32 av = CAP_TO_MASK(cap);
1443 int rc; 1444 int rc;
1444 1445
@@ -1865,15 +1866,27 @@ static int selinux_capset(struct cred *new, const struct cred *old,
1865 return cred_has_perm(old, new, PROCESS__SETCAP); 1866 return cred_has_perm(old, new, PROCESS__SETCAP);
1866} 1867}
1867 1868
1868static int selinux_capable(struct task_struct *tsk, int cap, int audit) 1869static int selinux_capable(int cap, int audit)
1870{
1871 int rc;
1872
1873 rc = secondary_ops->capable(cap, audit);
1874 if (rc)
1875 return rc;
1876
1877 return task_has_capability(current, current_cred(), cap, audit);
1878}
1879
1880static int selinux_task_capable(struct task_struct *tsk,
1881 const struct cred *cred, int cap, int audit)
1869{ 1882{
1870 int rc; 1883 int rc;
1871 1884
1872 rc = secondary_ops->capable(tsk, cap, audit); 1885 rc = secondary_ops->task_capable(tsk, cred, cap, audit);
1873 if (rc) 1886 if (rc)
1874 return rc; 1887 return rc;
1875 1888
1876 return task_has_capability(tsk, cap, audit); 1889 return task_has_capability(tsk, cred, cap, audit);
1877} 1890}
1878 1891
1879static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) 1892static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -2037,7 +2050,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
2037{ 2050{
2038 int rc, cap_sys_admin = 0; 2051 int rc, cap_sys_admin = 0;
2039 2052
2040 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); 2053 rc = selinux_capable(CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
2041 if (rc == 0) 2054 if (rc == 0)
2042 cap_sys_admin = 1; 2055 cap_sys_admin = 1;
2043 2056
@@ -2880,7 +2893,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
2880 * and lack of permission just means that we fall back to the 2893 * and lack of permission just means that we fall back to the
2881 * in-core context value, not a denial. 2894 * in-core context value, not a denial.
2882 */ 2895 */
2883 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); 2896 error = selinux_capable(CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
2884 if (!error) 2897 if (!error)
2885 error = security_sid_to_context_force(isec->sid, &context, 2898 error = security_sid_to_context_force(isec->sid, &context,
2886 &size); 2899 &size);
@@ -5568,6 +5581,7 @@ static struct security_operations selinux_ops = {
5568 .capset = selinux_capset, 5581 .capset = selinux_capset,
5569 .sysctl = selinux_sysctl, 5582 .sysctl = selinux_sysctl,
5570 .capable = selinux_capable, 5583 .capable = selinux_capable,
5584 .task_capable = selinux_task_capable,
5571 .quotactl = selinux_quotactl, 5585 .quotactl = selinux_quotactl,
5572 .quota_on = selinux_quota_on, 5586 .quota_on = selinux_quota_on,
5573 .syslog = selinux_syslog, 5587 .syslog = selinux_syslog,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6bfaba6177c2..7f12cc7015b6 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2827,6 +2827,7 @@ struct security_operations smack_ops = {
2827 .capget = cap_capget, 2827 .capget = cap_capget,
2828 .capset = cap_capset, 2828 .capset = cap_capset,
2829 .capable = cap_capable, 2829 .capable = cap_capable,
2830 .task_capable = cap_task_capable,
2830 .syslog = smack_syslog, 2831 .syslog = smack_syslog,
2831 .settime = cap_settime, 2832 .settime = cap_settime,
2832 .vm_enough_memory = cap_vm_enough_memory, 2833 .vm_enough_memory = cap_vm_enough_memory,