aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/security.h
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 /include/linux/security.h
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 'include/linux/security.h')
-rw-r--r--include/linux/security.h49
1 files changed, 40 insertions, 9 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index 3416cb85e77b..76989b8bc34f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -48,7 +48,9 @@ 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(int cap, int audit);
52extern int cap_task_capable(struct task_struct *tsk, const struct cred *cred,
53 int cap, int audit);
52extern int cap_settime(struct timespec *ts, struct timezone *tz); 54extern int cap_settime(struct timespec *ts, struct timezone *tz);
53extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); 55extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
54extern int cap_ptrace_traceme(struct task_struct *parent); 56extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -1195,9 +1197,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
1195 * @permitted contains the permitted capability set. 1197 * @permitted contains the permitted capability set.
1196 * Return 0 and update @new if permission is granted. 1198 * Return 0 and update @new if permission is granted.
1197 * @capable: 1199 * @capable:
1198 * Check whether the @tsk process has the @cap capability. 1200 * Check whether the current process has the @cap capability in its
1201 * subjective/effective credentials.
1202 * @cap contains the capability <include/linux/capability.h>.
1203 * @audit: Whether to write an audit message or not
1204 * Return 0 if the capability is granted for @tsk.
1205 * @task_capable:
1206 * Check whether the @tsk process has the @cap capability in its
1207 * objective/real credentials.
1199 * @tsk contains the task_struct for the process. 1208 * @tsk contains the task_struct for the process.
1209 * @cred contains the credentials to use.
1200 * @cap contains the capability <include/linux/capability.h>. 1210 * @cap contains the capability <include/linux/capability.h>.
1211 * @audit: Whether to write an audit message or not
1201 * Return 0 if the capability is granted for @tsk. 1212 * Return 0 if the capability is granted for @tsk.
1202 * @acct: 1213 * @acct:
1203 * Check permission before enabling or disabling process accounting. If 1214 * Check permission before enabling or disabling process accounting. If
@@ -1290,7 +1301,9 @@ struct security_operations {
1290 const kernel_cap_t *effective, 1301 const kernel_cap_t *effective,
1291 const kernel_cap_t *inheritable, 1302 const kernel_cap_t *inheritable,
1292 const kernel_cap_t *permitted); 1303 const kernel_cap_t *permitted);
1293 int (*capable) (struct task_struct *tsk, int cap, int audit); 1304 int (*capable) (int cap, int audit);
1305 int (*task_capable) (struct task_struct *tsk, const struct cred *cred,
1306 int cap, int audit);
1294 int (*acct) (struct file *file); 1307 int (*acct) (struct file *file);
1295 int (*sysctl) (struct ctl_table *table, int op); 1308 int (*sysctl) (struct ctl_table *table, int op);
1296 int (*quotactl) (int cmds, int type, int id, struct super_block *sb); 1309 int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
@@ -1556,8 +1569,9 @@ int security_capset(struct cred *new, const struct cred *old,
1556 const kernel_cap_t *effective, 1569 const kernel_cap_t *effective,
1557 const kernel_cap_t *inheritable, 1570 const kernel_cap_t *inheritable,
1558 const kernel_cap_t *permitted); 1571 const kernel_cap_t *permitted);
1559int security_capable(struct task_struct *tsk, int cap); 1572int security_capable(int cap);
1560int security_capable_noaudit(struct task_struct *tsk, int cap); 1573int security_task_capable(struct task_struct *tsk, int cap);
1574int security_task_capable_noaudit(struct task_struct *tsk, int cap);
1561int security_acct(struct file *file); 1575int security_acct(struct file *file);
1562int security_sysctl(struct ctl_table *table, int op); 1576int security_sysctl(struct ctl_table *table, int op);
1563int security_quotactl(int cmds, int type, int id, struct super_block *sb); 1577int security_quotactl(int cmds, int type, int id, struct super_block *sb);
@@ -1754,14 +1768,31 @@ static inline int security_capset(struct cred *new,
1754 return cap_capset(new, old, effective, inheritable, permitted); 1768 return cap_capset(new, old, effective, inheritable, permitted);
1755} 1769}
1756 1770
1757static inline int security_capable(struct task_struct *tsk, int cap) 1771static inline int security_capable(int cap)
1758{ 1772{
1759 return cap_capable(tsk, cap, SECURITY_CAP_AUDIT); 1773 return cap_capable(cap, SECURITY_CAP_AUDIT);
1760} 1774}
1761 1775
1762static inline int security_capable_noaudit(struct task_struct *tsk, int cap) 1776static inline int security_task_capable(struct task_struct *tsk, int cap)
1763{ 1777{
1764 return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT); 1778 int ret;
1779
1780 rcu_read_lock();
1781 ret = cap_task_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
1782 rcu_read_unlock();
1783 return ret;
1784}
1785
1786static inline
1787int security_task_capable_noaudit(struct task_struct *tsk, int cap)
1788{
1789 int ret;
1790
1791 rcu_read_lock();
1792 ret = cap_task_capable(tsk, __task_cred(tsk), cap,
1793 SECURITY_CAP_NOAUDIT);
1794 rcu_read_unlock();
1795 return ret;
1765} 1796}
1766 1797
1767static inline int security_acct(struct file *file) 1798static inline int security_acct(struct file *file)