aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/security.h
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 /include/linux/security.h
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>
Diffstat (limited to 'include/linux/security.h')
-rw-r--r--include/linux/security.h41
1 files changed, 32 insertions, 9 deletions
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)