aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-01-06 17:27:01 -0500
committerJames Morris <jmorris@namei.org>2009-01-06 17:38:48 -0500
commit3699c53c485bf0168e6500d0ed18bf931584dd7c (patch)
treeeee63a8ddbdb0665bc6a4a053a2405ca7a5b867f
parent29881c4502ba05f46bc12ae8053d4e08d7e2615c (diff)
CRED: Fix regression in cap_capable() as shown up by sys_faccessat() [ver #3]
Fix a regression in cap_capable() due to: commit 3b11a1decef07c19443d24ae926982bc8ec9f4c0 Author: David Howells <dhowells@redhat.com> Date: Fri Nov 14 10:39:26 2008 +1100 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 passes the set of credentials to be tested down into the commoncap and SELinux code. The security functions called by capable() and has_capability() select the appropriate set of credentials from the process being checked. 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> Tested-by: J. Bruce Fields <bfields@citi.umich.edu> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/linux/capability.h17
-rw-r--r--include/linux/security.h41
-rw-r--r--kernel/capability.c2
-rw-r--r--security/commoncap.c29
-rw-r--r--security/security.c26
-rw-r--r--security/selinux/hooks.c16
6 files changed, 94 insertions, 37 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h
index e22f48c2a46f..02bdb768d43b 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -529,8 +529,21 @@ extern const kernel_cap_t __cap_init_eff_set;
529 * 529 *
530 * Note that this does not set PF_SUPERPRIV on the task. 530 * Note that this does not set PF_SUPERPRIV on the task.
531 */ 531 */
532#define has_capability(t, cap) (security_capable((t), (cap)) == 0) 532#define has_capability(t, cap) (security_real_capable((t), (cap)) == 0)
533#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0) 533
534/**
535 * has_capability_noaudit - Determine if a task has a superior capability available (unaudited)
536 * @t: The task in question
537 * @cap: The capability to be tested for
538 *
539 * Return true if the specified task has the given superior capability
540 * currently in effect, false if not, but don't write an audit message for the
541 * check.
542 *
543 * Note that this does not set PF_SUPERPRIV on the task.
544 */
545#define has_capability_noaudit(t, cap) \
546 (security_real_capable_noaudit((t), (cap)) == 0)
534 547
535extern int capable(int cap); 548extern int capable(int cap);
536 549
diff --git a/include/linux/security.h b/include/linux/security.h
index 3416cb85e77b..f9c390494f18 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -48,7 +48,8 @@ struct audit_krule;
48 * These functions are in security/capability.c and are used 48 * These functions are in security/capability.c and are used
49 * as the default capabilities functions 49 * as the default capabilities functions
50 */ 50 */
51extern int cap_capable(struct task_struct *tsk, int cap, int audit); 51extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
52 int cap, int audit);
52extern int cap_settime(struct timespec *ts, struct timezone *tz); 53extern int cap_settime(struct timespec *ts, struct timezone *tz);
53extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); 54extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
54extern int cap_ptrace_traceme(struct task_struct *parent); 55extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -1195,9 +1196,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
1195 * @permitted contains the permitted capability set. 1196 * @permitted contains the permitted capability set.
1196 * Return 0 and update @new if permission is granted. 1197 * Return 0 and update @new if permission is granted.
1197 * @capable: 1198 * @capable:
1198 * Check whether the @tsk process has the @cap capability. 1199 * Check whether the @tsk process has the @cap capability in the indicated
1200 * credentials.
1199 * @tsk contains the task_struct for the process. 1201 * @tsk contains the task_struct for the process.
1202 * @cred contains the credentials to use.
1200 * @cap contains the capability <include/linux/capability.h>. 1203 * @cap contains the capability <include/linux/capability.h>.
1204 * @audit: Whether to write an audit message or not
1201 * Return 0 if the capability is granted for @tsk. 1205 * Return 0 if the capability is granted for @tsk.
1202 * @acct: 1206 * @acct:
1203 * Check permission before enabling or disabling process accounting. If 1207 * Check permission before enabling or disabling process accounting. If
@@ -1290,7 +1294,8 @@ struct security_operations {
1290 const kernel_cap_t *effective, 1294 const kernel_cap_t *effective,
1291 const kernel_cap_t *inheritable, 1295 const kernel_cap_t *inheritable,
1292 const kernel_cap_t *permitted); 1296 const kernel_cap_t *permitted);
1293 int (*capable) (struct task_struct *tsk, int cap, int audit); 1297 int (*capable) (struct task_struct *tsk, const struct cred *cred,
1298 int cap, int audit);
1294 int (*acct) (struct file *file); 1299 int (*acct) (struct file *file);
1295 int (*sysctl) (struct ctl_table *table, int op); 1300 int (*sysctl) (struct ctl_table *table, int op);
1296 int (*quotactl) (int cmds, int type, int id, struct super_block *sb); 1301 int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
@@ -1556,8 +1561,9 @@ int security_capset(struct cred *new, const struct cred *old,
1556 const kernel_cap_t *effective, 1561 const kernel_cap_t *effective,
1557 const kernel_cap_t *inheritable, 1562 const kernel_cap_t *inheritable,
1558 const kernel_cap_t *permitted); 1563 const kernel_cap_t *permitted);
1559int security_capable(struct task_struct *tsk, int cap); 1564int security_capable(int cap);
1560int security_capable_noaudit(struct task_struct *tsk, int cap); 1565int security_real_capable(struct task_struct *tsk, int cap);
1566int security_real_capable_noaudit(struct task_struct *tsk, int cap);
1561int security_acct(struct file *file); 1567int security_acct(struct file *file);
1562int security_sysctl(struct ctl_table *table, int op); 1568int security_sysctl(struct ctl_table *table, int op);
1563int security_quotactl(int cmds, int type, int id, struct super_block *sb); 1569int security_quotactl(int cmds, int type, int id, struct super_block *sb);
@@ -1754,14 +1760,31 @@ static inline int security_capset(struct cred *new,
1754 return cap_capset(new, old, effective, inheritable, permitted); 1760 return cap_capset(new, old, effective, inheritable, permitted);
1755} 1761}
1756 1762
1757static inline int security_capable(struct task_struct *tsk, int cap) 1763static inline int security_capable(int cap)
1758{ 1764{
1759 return cap_capable(tsk, cap, SECURITY_CAP_AUDIT); 1765 return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
1760} 1766}
1761 1767
1762static inline int security_capable_noaudit(struct task_struct *tsk, int cap) 1768static inline int security_real_capable(struct task_struct *tsk, int cap)
1763{ 1769{
1764 return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT); 1770 int ret;
1771
1772 rcu_read_lock();
1773 ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
1774 rcu_read_unlock();
1775 return ret;
1776}
1777
1778static inline
1779int security_real_capable_noaudit(struct task_struct *tsk, int cap)
1780{
1781 int ret;
1782
1783 rcu_read_lock();
1784 ret = cap_capable(tsk, __task_cred(tsk), cap,
1785 SECURITY_CAP_NOAUDIT);
1786 rcu_read_unlock();
1787 return ret;
1765} 1788}
1766 1789
1767static inline int security_acct(struct file *file) 1790static inline int security_acct(struct file *file)
diff --git a/kernel/capability.c b/kernel/capability.c
index 36b4b4daebec..df62f53f84ac 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -308,7 +308,7 @@ int capable(int cap)
308 BUG(); 308 BUG();
309 } 309 }
310 310
311 if (has_capability(current, cap)) { 311 if (security_capable(cap) == 0) {
312 current->flags |= PF_SUPERPRIV; 312 current->flags |= PF_SUPERPRIV;
313 return 1; 313 return 1;
314 } 314 }
diff --git a/security/commoncap.c b/security/commoncap.c
index 79713545cd63..f0e671dcfff0 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -45,26 +45,22 @@ EXPORT_SYMBOL(cap_netlink_recv);
45/** 45/**
46 * cap_capable - Determine whether a task has a particular effective capability 46 * cap_capable - Determine whether a task has a particular effective capability
47 * @tsk: The task to query 47 * @tsk: The task to query
48 * @cred: The credentials to use
48 * @cap: The capability to check for 49 * @cap: The capability to check for
49 * @audit: Whether to write an audit message or not 50 * @audit: Whether to write an audit message or not
50 * 51 *
51 * Determine whether the nominated task has the specified capability amongst 52 * Determine whether the nominated task has the specified capability amongst
52 * its effective set, returning 0 if it does, -ve if it does not. 53 * its effective set, returning 0 if it does, -ve if it does not.
53 * 54 *
54 * NOTE WELL: cap_capable() cannot be used like the kernel's capable() 55 * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable()
55 * function. That is, it has the reverse semantics: cap_capable() returns 0 56 * and has_capability() functions. That is, it has the reverse semantics:
56 * when a task has a capability, but the kernel's capable() returns 1 for this 57 * cap_has_capability() returns 0 when a task has a capability, but the
57 * case. 58 * kernel's capable() and has_capability() returns 1 for this case.
58 */ 59 */
59int cap_capable(struct task_struct *tsk, int cap, int audit) 60int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
61 int audit)
60{ 62{
61 __u32 cap_raised; 63 return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
62
63 /* Derived from include/linux/sched.h:capable. */
64 rcu_read_lock();
65 cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
66 rcu_read_unlock();
67 return cap_raised ? 0 : -EPERM;
68} 64}
69 65
70/** 66/**
@@ -160,7 +156,8 @@ static inline int cap_inh_is_capped(void)
160 /* they are so limited unless the current task has the CAP_SETPCAP 156 /* they are so limited unless the current task has the CAP_SETPCAP
161 * capability 157 * capability
162 */ 158 */
163 if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) 159 if (cap_capable(current, current_cred(), CAP_SETPCAP,
160 SECURITY_CAP_AUDIT) == 0)
164 return 0; 161 return 0;
165#endif 162#endif
166 return 1; 163 return 1;
@@ -869,7 +866,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
869 & (new->securebits ^ arg2)) /*[1]*/ 866 & (new->securebits ^ arg2)) /*[1]*/
870 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ 867 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
871 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ 868 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
872 || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ 869 || (cap_capable(current, current_cred(), CAP_SETPCAP,
870 SECURITY_CAP_AUDIT) != 0) /*[4]*/
873 /* 871 /*
874 * [1] no changing of bits that are locked 872 * [1] no changing of bits that are locked
875 * [2] no unlocking of locks 873 * [2] no unlocking of locks
@@ -950,7 +948,8 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
950{ 948{
951 int cap_sys_admin = 0; 949 int cap_sys_admin = 0;
952 950
953 if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) 951 if (cap_capable(current, current_cred(), CAP_SYS_ADMIN,
952 SECURITY_CAP_NOAUDIT) == 0)
954 cap_sys_admin = 1; 953 cap_sys_admin = 1;
955 return __vm_enough_memory(mm, pages, cap_sys_admin); 954 return __vm_enough_memory(mm, pages, cap_sys_admin);
956} 955}
diff --git a/security/security.c b/security/security.c
index d85dbb37c972..a02f243f09c0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -154,14 +154,32 @@ 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(current, current_cred(), cap,
160 SECURITY_CAP_AUDIT);
160} 161}
161 162
162int security_capable_noaudit(struct task_struct *tsk, int cap) 163int security_real_capable(struct task_struct *tsk, int cap)
163{ 164{
164 return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT); 165 const struct cred *cred;
166 int ret;
167
168 cred = get_task_cred(tsk);
169 ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
170 put_cred(cred);
171 return ret;
172}
173
174int security_real_capable_noaudit(struct task_struct *tsk, int cap)
175{
176 const struct cred *cred;
177 int ret;
178
179 cred = get_task_cred(tsk);
180 ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
181 put_cred(cred);
182 return ret;
165} 183}
166 184
167int security_acct(struct file *file) 185int security_acct(struct file *file)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index df30a7555d8a..00815973d412 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,16 @@ 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(struct task_struct *tsk, const struct cred *cred,
1870 int cap, int audit)
1869{ 1871{
1870 int rc; 1872 int rc;
1871 1873
1872 rc = secondary_ops->capable(tsk, cap, audit); 1874 rc = secondary_ops->capable(tsk, cred, cap, audit);
1873 if (rc) 1875 if (rc)
1874 return rc; 1876 return rc;
1875 1877
1876 return task_has_capability(tsk, cap, audit); 1878 return task_has_capability(tsk, cred, cap, audit);
1877} 1879}
1878 1880
1879static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) 1881static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -2037,7 +2039,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
2037{ 2039{
2038 int rc, cap_sys_admin = 0; 2040 int rc, cap_sys_admin = 0;
2039 2041
2040 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); 2042 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
2043 SECURITY_CAP_NOAUDIT);
2041 if (rc == 0) 2044 if (rc == 0)
2042 cap_sys_admin = 1; 2045 cap_sys_admin = 1;
2043 2046
@@ -2880,7 +2883,8 @@ 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 2883 * and lack of permission just means that we fall back to the
2881 * in-core context value, not a denial. 2884 * in-core context value, not a denial.
2882 */ 2885 */
2883 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); 2886 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
2887 SECURITY_CAP_NOAUDIT);
2884 if (!error) 2888 if (!error)
2885 error = security_sid_to_context_force(isec->sid, &context, 2889 error = security_sid_to_context_force(isec->sid, &context,
2886 &size); 2890 &size);