From 94d4ef0c2b3e6c799f78d223e233254a870c4559 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 5 Oct 2011 12:19:19 +0100 Subject: SELinux: Fix RCU deref check warning in sel_netport_insert() Fix the following bug in sel_netport_insert() where rcu_dereference() should be rcu_dereference_protected() as sel_netport_lock is held. =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- security/selinux/netport.c:127 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by ossec-rootcheck/3323: #0: (sel_netport_lock){+.....}, at: [] sel_netport_sid+0xbb/0x226 stack backtrace: Pid: 3323, comm: ossec-rootcheck Not tainted 3.1.0-rc8-fsdevel+ #1095 Call Trace: [] lockdep_rcu_dereference+0xa7/0xb0 [] sel_netport_sid+0x1b7/0x226 [] ? sel_netport_avc_callback+0xbc/0xbc [] selinux_socket_bind+0x115/0x230 [] ? might_fault+0x4e/0x9e [] ? might_fault+0x97/0x9e [] security_socket_bind+0x11/0x13 [] sys_bind+0x56/0x95 [] ? sysret_check+0x27/0x62 [] ? trace_hardirqs_on_caller+0x11e/0x155 [] ? audit_syscall_entry+0x17b/0x1ae [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Signed-off-by: David Howells Acked-by: Eric Dumazet Acked-by: Paul Moore Signed-off-by: Eric Paris --- security/selinux/netport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 0b62bd11246..7b9eb1faf68 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -123,7 +123,9 @@ static void sel_netport_insert(struct sel_netport *port) if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { struct sel_netport *tail; tail = list_entry( - rcu_dereference(sel_netport_hash[idx].list.prev), + rcu_dereference_protected( + sel_netport_hash[idx].list.prev, + lockdep_is_held(&sel_netport_lock)), struct sel_netport, list); list_del_rcu(&tail->list); kfree_rcu(tail, rcu); -- cgit v1.2.3 From b46610caba4bd9263afd07c7ef7a79974550554a Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:11:24 +1000 Subject: selinux: sparse fix: make selinux_secmark_refcount static Sparse fix: make selinux_secmark_refcount static. Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 266a2292451..e07cf7fcdce 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -96,7 +96,7 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern struct security_operations *security_ops; /* SECMARK reference count */ -atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); +static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); #ifdef CONFIG_SECURITY_SELINUX_DEVELOP int selinux_enforcing; -- cgit v1.2.3 From 5c884c1d4ac955987e84acf2d36c0f160536aca4 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:16:24 +1000 Subject: selinux: sparse fix: move selinux_complete_init Sparse fix: move selinux_complete_init Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/include/security.h | 1 + security/selinux/ss/services.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 3ba4feba048..8556e1a263c 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -216,6 +216,7 @@ struct selinux_kernel_status { extern void selinux_status_update_setenforce(int enforcing); extern void selinux_status_update_policyload(int seqno); +extern void selinux_complete_init(void); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index f6917bc0aa0..37c50c602f1 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1790,7 +1790,6 @@ static void security_load_policycaps(void) POLICYDB_CAPABILITY_OPENPERM); } -extern void selinux_complete_init(void); static int security_preserve_bools(struct policydb *p); /** -- cgit v1.2.3 From 6063c0461b947c26a77674f33a3409eb99e15d2f Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:12:13 +1000 Subject: selinux: sparse fix: declare selinux_disable() in security.h Sparse fix: declare selinux_disable() in security.h Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/include/security.h | 1 + security/selinux/selinuxfs.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 8556e1a263c..30002c43436 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -217,6 +217,7 @@ struct selinux_kernel_status { extern void selinux_status_update_setenforce(int enforcing); extern void selinux_status_update_policyload(int seqno); extern void selinux_complete_init(void); +extern int selinux_disable(void); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 55d92cbb177..d3677c6c12c 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -278,7 +278,6 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, char *page = NULL; ssize_t length; int new_value; - extern int selinux_disable(void); length = -ENOMEM; if (count >= PAGE_SIZE) -- cgit v1.2.3 From e8a65a3f67f8a85802c0a0250e48c4c4652d0da0 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:17:34 +1000 Subject: selinux: sparse fix: eliminate warnings for selinuxfs Fixes several sparse warnings for selinuxfs.c Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/hooks.c | 5 ----- security/selinux/include/security.h | 3 +++ security/selinux/selinuxfs.c | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e07cf7fcdce..4a176b46871 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2097,9 +2097,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm) return (atsecure || cap_bprm_secureexec(bprm)); } -extern struct vfsmount *selinuxfs_mount; -extern struct dentry *selinux_null; - /* Derived from fs/exec.c:flush_old_files. */ static inline void flush_unauthorized_files(const struct cred *cred, struct files_struct *files) @@ -5803,8 +5800,6 @@ static int selinux_disabled; int selinux_disable(void) { - extern void exit_sel_fs(void); - if (ss_initialized) { /* Not permitted after initial policy load. */ return -EINVAL; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 30002c43436..13b626352f0 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -218,6 +218,9 @@ extern void selinux_status_update_setenforce(int enforcing); extern void selinux_status_update_policyload(int seqno); extern void selinux_complete_init(void); extern int selinux_disable(void); +extern void exit_sel_fs(void); +extern struct dentry *selinux_null; +extern struct vfsmount *selinuxfs_mount; #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d3677c6c12c..ba2ada5f16a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -477,7 +477,7 @@ static struct vm_operations_struct sel_mmap_policy_ops = { .page_mkwrite = sel_mmap_policy_fault, }; -int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) +static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) { if (vma->vm_flags & VM_SHARED) { /* do not allow mprotect to make mapping writable */ -- cgit v1.2.3 From 02f5daa563456c1ff3c3422aa3ec00e67460f762 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:18:06 +1000 Subject: selinux: sparse fix: fix warnings in netlink code Fix sparse warnings in SELinux Netlink code. Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/hooks.c | 1 - security/selinux/include/security.h | 3 +++ security/selinux/netlink.c | 2 ++ security/selinux/nlmsgtab.c | 1 + security/selinux/selinuxfs.c | 2 -- security/selinux/ss/services.c | 2 -- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4a176b46871..1206cee31c7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -92,7 +92,6 @@ #define NUM_SEL_MNT_OPTS 5 -extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern struct security_operations *security_ops; /* SECMARK reference count */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 13b626352f0..d871e8ad210 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -221,6 +221,9 @@ extern int selinux_disable(void); extern void exit_sel_fs(void); extern struct dentry *selinux_null; extern struct vfsmount *selinuxfs_mount; +extern void selnl_notify_setenforce(int val); +extern void selnl_notify_policyload(u32 seqno); +extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index 36ac257cec9..ce3f481558d 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -19,6 +19,8 @@ #include #include +#include "security.h" + static struct sock *selnl; static int selnl_msglen(int msgtype) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 8b02b2137da..0920ea3bf59 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -21,6 +21,7 @@ #include "flask.h" #include "av_permissions.h" +#include "security.h" struct nlmsg_perm { u16 nlmsg_type; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ba2ada5f16a..f46658722c7 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -75,8 +75,6 @@ static char policy_opened; /* global data for policy capabilities */ static struct dentry *policycap_dir; -extern void selnl_notify_setenforce(int val); - /* Check whether a task is allowed to use a security operation. */ static int task_has_security(struct task_struct *tsk, u32 perms) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 37c50c602f1..185f849a26f 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -70,8 +70,6 @@ #include "ebitmap.h" #include "audit.h" -extern void selnl_notify_policyload(u32 seqno); - int selinux_policycap_netpeer; int selinux_policycap_openperm; -- cgit v1.2.3 From 2653812e14f4e16688ec8247d7fd290bdbbc4747 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 30 Aug 2011 14:19:02 +1000 Subject: selinux: sparse fix: fix several warnings in the security server cod Fix several sparse warnings in the SELinux security server code. Signed-off-by: James Morris Signed-off-by: Eric Paris --- security/selinux/hooks.c | 5 +---- security/selinux/include/avc_ss.h | 6 ++++++ security/selinux/ss/conditional.c | 2 +- security/selinux/ss/conditional.h | 1 + security/selinux/ss/policydb.c | 2 -- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1206cee31c7..e545b9f6707 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -89,6 +89,7 @@ #include "xfrm.h" #include "netlabel.h" #include "audit.h" +#include "avc_ss.h" #define NUM_SEL_MNT_OPTS 5 @@ -278,10 +279,6 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } -/* The security server must be initialized before - any labeling or access decisions can be provided. */ -extern int ss_initialized; - /* The file system's label must be initialized prior to use. */ static const char *labeling_behaviors[6] = { diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index 4677aa519b0..d5c328452df 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -18,5 +18,11 @@ struct security_class_mapping { extern struct security_class_mapping secclass_map[]; +/* + * The security server must be initialized before + * any labeling or access decisions can be provided. + */ +extern int ss_initialized; + #endif /* _SELINUX_AVC_SS_H_ */ diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index a53373207fb..2ec904177fe 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -555,7 +555,7 @@ static int cond_write_av_list(struct policydb *p, return 0; } -int cond_write_node(struct policydb *p, struct cond_node *node, +static int cond_write_node(struct policydb *p, struct cond_node *node, struct policy_file *fp) { struct cond_expr *cur_expr; diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 3f209c63529..4d1f8746650 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -13,6 +13,7 @@ #include "avtab.h" #include "symtab.h" #include "policydb.h" +#include "../include/conditional.h" #define COND_EXPR_MAXDEPTH 10 diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2381d0ded22..a7f61d52f05 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1743,8 +1743,6 @@ static int policydb_bounds_sanity_check(struct policydb *p) return 0; } -extern int ss_initialized; - u16 string_to_security_class(struct policydb *p, const char *name) { struct class_datum *cladatum; -- cgit v1.2.3 From 6a9de49115d5ff9871d953af1a5c8249e1585731 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:14 -0500 Subject: capabilities: remove the task from capable LSM hook entirely The capabilities framework is based around credentials, not necessarily the current task. Yet we still passed the current task down into LSMs from the security_capable() LSM hook as if it was a meaningful portion of the security decision. This patch removes the 'generic' passing of current and instead forces individual LSMs to use current explicitly if they think it is appropriate. In our case those LSMs are SELinux and AppArmor. I believe the AppArmor use of current is incorrect, but that is wholely unrelated to this patch. This patch does not change what AppArmor does, it just makes it clear in the AppArmor code that it is doing it. The SELinux code still uses current in it's audit message, which may also be wrong and needs further investigation. Again this is NOT a change, it may have always been wrong, this patch just makes it clear what is happening. Signed-off-by: Eric Paris --- include/linux/security.h | 16 +++++++--------- security/apparmor/lsm.c | 8 ++++---- security/commoncap.c | 16 +++++++--------- security/security.c | 7 +++---- security/selinux/hooks.c | 23 ++++++++++------------- 5 files changed, 31 insertions(+), 39 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index ebd2a53a3d0..4921163b275 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -53,8 +53,8 @@ struct user_namespace; * These functions are in security/capability.c and are used * as the default capabilities functions */ -extern int cap_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit); +extern int cap_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit); extern int cap_settime(const struct timespec *ts, const struct timezone *tz); extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); @@ -1261,7 +1261,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @capable: * Check whether the @tsk process has the @cap capability in the indicated * credentials. - * @tsk contains the task_struct for the process. * @cred contains the credentials to use. * @ns contains the user namespace we want the capability in * @cap contains the capability . @@ -1385,8 +1384,8 @@ struct security_operations { const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); - int (*capable) (struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit); + int (*capable) (const struct cred *cred, struct user_namespace *ns, + int cap, int audit); int (*quotactl) (int cmds, int type, int id, struct super_block *sb); int (*quota_on) (struct dentry *dentry); int (*syslog) (int type); @@ -1867,7 +1866,7 @@ static inline int security_capset(struct cred *new, static inline int security_capable(struct user_namespace *ns, const struct cred *cred, int cap) { - return cap_capable(current, cred, ns, cap, SECURITY_CAP_AUDIT); + return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); } static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap) @@ -1875,7 +1874,7 @@ static inline int security_real_capable(struct task_struct *tsk, struct user_nam int ret; rcu_read_lock(); - ret = cap_capable(tsk, __task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT); + ret = cap_capable(__task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT); rcu_read_unlock(); return ret; } @@ -1886,8 +1885,7 @@ int security_real_capable_noaudit(struct task_struct *tsk, struct user_namespace int ret; rcu_read_lock(); - ret = cap_capable(tsk, __task_cred(tsk), ns, cap, - SECURITY_CAP_NOAUDIT); + ret = cap_capable(__task_cred(tsk), ns, cap, SECURITY_CAP_NOAUDIT); rcu_read_unlock(); return ret; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 37832026e58..ef4e2a8a33a 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -136,16 +136,16 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, return 0; } -static int apparmor_capable(struct task_struct *task, const struct cred *cred, - struct user_namespace *ns, int cap, int audit) +static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit) { struct aa_profile *profile; /* cap_capable returns 0 on success, else -EPERM */ - int error = cap_capable(task, cred, ns, cap, audit); + int error = cap_capable(cred, ns, cap, audit); if (!error) { profile = aa_cred_profile(cred); if (!unconfined(profile)) - error = aa_capable(task, profile, cap, audit); + error = aa_capable(current, profile, cap, audit); } return error; } diff --git a/security/commoncap.c b/security/commoncap.c index a93b3b73307..89f02ff66af 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -66,7 +66,6 @@ EXPORT_SYMBOL(cap_netlink_recv); /** * cap_capable - Determine whether a task has a particular effective capability - * @tsk: The task to query * @cred: The credentials to use * @ns: The user namespace in which we need the capability * @cap: The capability to check for @@ -80,8 +79,8 @@ EXPORT_SYMBOL(cap_netlink_recv); * cap_has_capability() returns 0 when a task has a capability, but the * kernel's capable() and has_capability() returns 1 for this case. */ -int cap_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *targ_ns, int cap, int audit) +int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, + int cap, int audit) { for (;;) { /* The creator of the user namespace has all caps. */ @@ -222,9 +221,8 @@ static inline int cap_inh_is_capped(void) /* they are so limited unless the current task has the CAP_SETPCAP * capability */ - if (cap_capable(current, current_cred(), - current_cred()->user->user_ns, CAP_SETPCAP, - SECURITY_CAP_AUDIT) == 0) + if (cap_capable(current_cred(), current_cred()->user->user_ns, + CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) return 0; return 1; } @@ -870,7 +868,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, & (new->securebits ^ arg2)) /*[1]*/ || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ - || (cap_capable(current, current_cred(), + || (cap_capable(current_cred(), current_cred()->user->user_ns, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ /* @@ -936,7 +934,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) { int cap_sys_admin = 0; - if (cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_ADMIN, + if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); @@ -963,7 +961,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, int ret = 0; if (addr < dac_mmap_min_addr) { - ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO, + ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, SECURITY_CAP_AUDIT); /* set PF_SUPERPRIV if it turns out we allow the low mmap */ if (ret == 0) diff --git a/security/security.c b/security/security.c index d9e15339092..9ae68c64455 100644 --- a/security/security.c +++ b/security/security.c @@ -157,8 +157,7 @@ int security_capset(struct cred *new, const struct cred *old, int security_capable(struct user_namespace *ns, const struct cred *cred, int cap) { - return security_ops->capable(current, cred, ns, cap, - SECURITY_CAP_AUDIT); + return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); } int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, @@ -168,7 +167,7 @@ int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int ret; cred = get_task_cred(tsk); - ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_AUDIT); + ret = security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); put_cred(cred); return ret; } @@ -180,7 +179,7 @@ int security_real_capable_noaudit(struct task_struct *tsk, int ret; cred = get_task_cred(tsk); - ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_NOAUDIT); + ret = security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); put_cred(cred); return ret; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e545b9f6707..c9605c4a2e0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1414,8 +1414,7 @@ static int current_has_perm(const struct task_struct *tsk, #endif /* Check whether a task is allowed to use a capability. */ -static int task_has_capability(struct task_struct *tsk, - const struct cred *cred, +static int cred_has_capability(const struct cred *cred, int cap, int audit) { struct common_audit_data ad; @@ -1426,7 +1425,7 @@ static int task_has_capability(struct task_struct *tsk, int rc; COMMON_AUDIT_DATA_INIT(&ad, CAP); - ad.tsk = tsk; + ad.tsk = current; ad.u.cap = cap; switch (CAP_TO_INDEX(cap)) { @@ -1867,16 +1866,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. */ -static int selinux_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit) +static int selinux_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit) { int rc; - rc = cap_capable(tsk, cred, ns, cap, audit); + rc = cap_capable(cred, ns, cap, audit); if (rc) return rc; - return task_has_capability(tsk, cred, cap, audit); + return cred_has_capability(cred, cap, audit); } static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) @@ -1953,8 +1952,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) { int rc, cap_sys_admin = 0; - rc = selinux_capable(current, current_cred(), - &init_user_ns, CAP_SYS_ADMIN, + rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); if (rc == 0) cap_sys_admin = 1; @@ -2858,8 +2856,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name * and lack of permission just means that we fall back to the * in-core context value, not a denial. */ - error = selinux_capable(current, current_cred(), - &init_user_ns, CAP_MAC_ADMIN, + error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); if (!error) error = security_sid_to_context_force(isec->sid, &context, @@ -2992,8 +2989,8 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, case KDSKBENT: case KDSKBSENT: - error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, - SECURITY_CAP_AUDIT); + error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, + SECURITY_CAP_AUDIT); break; /* default case assumes that the command will go -- cgit v1.2.3 From b7e724d303b684655e4ca3dabd5a6840ad19012d Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: reverse arguments to security_capable security_capable takes ns, cred, cap. But the LSM capable() hook takes cred, ns, cap. The capability helper functions also take cred, ns, cap. Rather than flip argument order just to flip it back, leave them alone. Heck, this should be a little faster since argument will be in the right place! Signed-off-by: Eric Paris --- drivers/pci/pci-sysfs.c | 2 +- include/linux/security.h | 6 +++--- kernel/capability.c | 2 +- security/security.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7bcf12adced..a4457ab6134 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -431,7 +431,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { + if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; diff --git a/include/linux/security.h b/include/linux/security.h index 4921163b275..ee969ff40a2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1666,7 +1666,7 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); -int security_capable(struct user_namespace *ns, const struct cred *cred, +int security_capable(const struct cred *cred, struct user_namespace *ns, int cap); int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap); @@ -1863,8 +1863,8 @@ static inline int security_capset(struct cred *new, return cap_capset(new, old, effective, inheritable, permitted); } -static inline int security_capable(struct user_namespace *ns, - const struct cred *cred, int cap) +static inline int security_capable(const struct cred *cred, + struct user_namespace *ns, int cap) { return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); } diff --git a/kernel/capability.c b/kernel/capability.c index 283c529f8b1..d98392719ad 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -374,7 +374,7 @@ bool ns_capable(struct user_namespace *ns, int cap) BUG(); } - if (security_capable(ns, current_cred(), cap) == 0) { + if (security_capable(current_cred(), ns, cap) == 0) { current->flags |= PF_SUPERPRIV; return true; } diff --git a/security/security.c b/security/security.c index 9ae68c64455..b9e57f4fc44 100644 --- a/security/security.c +++ b/security/security.c @@ -154,7 +154,7 @@ int security_capset(struct cred *new, const struct cred *old, effective, inheritable, permitted); } -int security_capable(struct user_namespace *ns, const struct cred *cred, +int security_capable(const struct cred *cred, struct user_namespace *ns, int cap) { return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); -- cgit v1.2.3 From c7eba4a97563fd8b431787f7ad623444f2da80c6 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: introduce security_capable_noaudit Exactly like security_capable except don't audit any denials. This is for places where the kernel may make decisions about what to do if a task has a given capability, but which failing that capability is not a sign of a security policy violation. An example is checking if a task has CAP_SYS_ADMIN to lower it's likelyhood of being killed by the oom killer. This check is not a security violation if it is denied. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- include/linux/security.h | 7 +++++++ security/security.c | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/include/linux/security.h b/include/linux/security.h index ee969ff40a2..caff54eee68 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1668,6 +1668,8 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *permitted); int security_capable(const struct cred *cred, struct user_namespace *ns, int cap); +int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, + int cap); int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap); int security_real_capable_noaudit(struct task_struct *tsk, @@ -1869,6 +1871,11 @@ static inline int security_capable(const struct cred *cred, return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); } +static inline int security_capable_noaudit(const struct cred *cred, + struct user_namespace *ns, int cap) { + return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); +} + static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap) { int ret; diff --git a/security/security.c b/security/security.c index b9e57f4fc44..b7edaae77d1 100644 --- a/security/security.c +++ b/security/security.c @@ -160,6 +160,12 @@ int security_capable(const struct cred *cred, struct user_namespace *ns, return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); } +int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, + int cap) +{ + return security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); +} + int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap) { -- cgit v1.2.3 From 2920a8409de5a51575d03deca07e5bb2be6fc98d Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: remove all _real_ interfaces The name security_real_capable and security_real_capable_noaudit just don't make much sense to me. Convert them to use security_capable and security_capable_noaudit. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- include/linux/security.h | 25 ------------------------- kernel/capability.c | 18 +++++++++++++++--- security/security.c | 24 ------------------------ 3 files changed, 15 insertions(+), 52 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index caff54eee68..e345a9313a6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1670,10 +1670,6 @@ int security_capable(const struct cred *cred, struct user_namespace *ns, int cap); int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, int cap); -int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, - int cap); -int security_real_capable_noaudit(struct task_struct *tsk, - struct user_namespace *ns, int cap); int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); @@ -1876,27 +1872,6 @@ static inline int security_capable_noaudit(const struct cred *cred, return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); } -static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap) -{ - int ret; - - rcu_read_lock(); - ret = cap_capable(__task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT); - rcu_read_unlock(); - return ret; -} - -static inline -int security_real_capable_noaudit(struct task_struct *tsk, struct user_namespace *ns, int cap) -{ - int ret; - - rcu_read_lock(); - ret = cap_capable(__task_cred(tsk), ns, cap, SECURITY_CAP_NOAUDIT); - rcu_read_unlock(); - return ret; -} - static inline int security_quotactl(int cmds, int type, int id, struct super_block *sb) { diff --git a/kernel/capability.c b/kernel/capability.c index d98392719ad..ff50ab62cfc 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -298,7 +298,11 @@ error: */ bool has_capability(struct task_struct *t, int cap) { - int ret = security_real_capable(t, &init_user_ns, cap); + int ret; + + rcu_read_lock(); + ret = security_capable(__task_cred(t), &init_user_ns, cap); + rcu_read_unlock(); return (ret == 0); } @@ -317,7 +321,11 @@ bool has_capability(struct task_struct *t, int cap) bool has_ns_capability(struct task_struct *t, struct user_namespace *ns, int cap) { - int ret = security_real_capable(t, ns, cap); + int ret; + + rcu_read_lock(); + ret = security_capable(__task_cred(t), ns, cap); + rcu_read_unlock(); return (ret == 0); } @@ -335,7 +343,11 @@ bool has_ns_capability(struct task_struct *t, */ bool has_capability_noaudit(struct task_struct *t, int cap) { - int ret = security_real_capable_noaudit(t, &init_user_ns, cap); + int ret; + + rcu_read_lock(); + ret = security_capable_noaudit(__task_cred(t), &init_user_ns, cap); + rcu_read_unlock(); return (ret == 0); } diff --git a/security/security.c b/security/security.c index b7edaae77d1..8900c5c4db5 100644 --- a/security/security.c +++ b/security/security.c @@ -166,30 +166,6 @@ int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, return security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); } -int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, - int cap) -{ - const struct cred *cred; - int ret; - - cred = get_task_cred(tsk); - ret = security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); - put_cred(cred); - return ret; -} - -int security_real_capable_noaudit(struct task_struct *tsk, - struct user_namespace *ns, int cap) -{ - const struct cred *cred; - int ret; - - cred = get_task_cred(tsk); - ret = security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); - put_cred(cred); - return ret; -} - int security_quotactl(int cmds, int type, int id, struct super_block *sb) { return security_ops->quotactl(cmds, type, id, sb); -- cgit v1.2.3 From 25e75703410a84b80623da3653db6b70282e5c6a Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: call has_ns_capability from has_capability Declare the more specific has_ns_capability first in the code and then call it from has_capability. The declaration reversal isn't stricty necessary since they are both declared in header files, but it just makes sense to put more specific functions first in the code. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- kernel/capability.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index ff50ab62cfc..fb815d1b9ea 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -287,47 +287,41 @@ error: } /** - * has_capability - Does a task have a capability in init_user_ns + * has_ns_capability - Does a task have a capability in a specific user ns * @t: The task in question + * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to the initial user namespace, false if not. + * currently in effect to the specified user namespace, false if not. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_capability(struct task_struct *t, int cap) +bool has_ns_capability(struct task_struct *t, + struct user_namespace *ns, int cap) { int ret; rcu_read_lock(); - ret = security_capable(__task_cred(t), &init_user_ns, cap); + ret = security_capable(__task_cred(t), ns, cap); rcu_read_unlock(); return (ret == 0); } /** - * has_capability - Does a task have a capability in a specific user ns + * has_capability - Does a task have a capability in init_user_ns * @t: The task in question - * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to the specified user namespace, false if not. + * currently in effect to the initial user namespace, false if not. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_ns_capability(struct task_struct *t, - struct user_namespace *ns, int cap) +bool has_capability(struct task_struct *t, int cap) { - int ret; - - rcu_read_lock(); - ret = security_capable(__task_cred(t), ns, cap); - rcu_read_unlock(); - - return (ret == 0); + return has_ns_capability(t, &init_user_ns, cap); } /** -- cgit v1.2.3 From 7b61d648499e74dbec3d4ce645675e0ae040ae78 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilites: introduce new has_ns_capabilities_noaudit For consistency in interfaces, introduce a new interface called has_ns_capabilities_noaudit. It checks if the given task has the given capability in the given namespace. Use this new function by has_capabilities_noaudit. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- include/linux/capability.h | 2 ++ kernel/capability.c | 30 +++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index c4211235000..63f59fa8769 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -543,6 +543,8 @@ extern bool has_capability(struct task_struct *t, int cap); extern bool has_ns_capability(struct task_struct *t, struct user_namespace *ns, int cap); extern bool has_capability_noaudit(struct task_struct *t, int cap); +extern bool has_ns_capability_noaudit(struct task_struct *t, + struct user_namespace *ns, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); extern bool task_ns_capable(struct task_struct *t, int cap); diff --git a/kernel/capability.c b/kernel/capability.c index fb815d1b9ea..d8398e96247 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -325,27 +325,47 @@ bool has_capability(struct task_struct *t, int cap) } /** - * has_capability_noaudit - Does a task have a capability (unaudited) + * has_ns_capability_noaudit - Does a task have a capability (unaudited) + * in a specific user ns. * @t: The task in question + * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to init_user_ns, false if not. Don't write an - * audit message for the check. + * currently in effect to the specified user namespace, false if not. + * Do not write an audit message for the check. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_capability_noaudit(struct task_struct *t, int cap) +bool has_ns_capability_noaudit(struct task_struct *t, + struct user_namespace *ns, int cap) { int ret; rcu_read_lock(); - ret = security_capable_noaudit(__task_cred(t), &init_user_ns, cap); + ret = security_capable_noaudit(__task_cred(t), ns, cap); rcu_read_unlock(); return (ret == 0); } +/** + * has_capability_noaudit - Does a task have a capability (unaudited) in the + * initial user ns + * @t: The task in question + * @cap: The capability to be tested for + * + * Return true if the specified task has the given superior capability + * currently in effect to init_user_ns, false if not. Don't write an + * audit message for the check. + * + * Note that this does not set PF_SUPERPRIV on the task. + */ +bool has_capability_noaudit(struct task_struct *t, int cap) +{ + return has_ns_capability_noaudit(t, &init_user_ns, cap); +} + /** * capable - Determine if the current task has a superior capability in effect * @cap: The capability to be tested for -- cgit v1.2.3 From 105ddf49cd301b7929a92f269440e8e562ef19db Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: style only - move capable below ns_capable Although the current code is fine for consistency this moves the capable code below the function it calls in the c file. It doesn't actually change code. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- kernel/capability.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index d8398e96247..5f99e5d68e1 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -366,22 +366,6 @@ bool has_capability_noaudit(struct task_struct *t, int cap) return has_ns_capability_noaudit(t, &init_user_ns, cap); } -/** - * capable - Determine if the current task has a superior capability in effect - * @cap: The capability to be tested for - * - * Return true if the current task has the given superior capability currently - * available for use, false if not. - * - * This sets PF_SUPERPRIV on the task if the capability is available on the - * assumption that it's about to be used. - */ -bool capable(int cap) -{ - return ns_capable(&init_user_ns, cap); -} -EXPORT_SYMBOL(capable); - /** * ns_capable - Determine if the current task has a superior capability in effect * @ns: The usernamespace we want the capability in @@ -408,6 +392,22 @@ bool ns_capable(struct user_namespace *ns, int cap) } EXPORT_SYMBOL(ns_capable); +/** + * capable - Determine if the current task has a superior capability in effect + * @cap: The capability to be tested for + * + * Return true if the current task has the given superior capability currently + * available for use, false if not. + * + * This sets PF_SUPERPRIV on the task if the capability is available on the + * assumption that it's about to be used. + */ +bool capable(int cap) +{ + return ns_capable(&init_user_ns, cap); +} +EXPORT_SYMBOL(capable); + /** * task_ns_capable - Determine whether current task has a superior * capability targeted at a specific task's user namespace. -- cgit v1.2.3 From d2a7009f0bb03fa22ad08dd25472efa0568126b9 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabitlies: ns_capable can use the cap helpers rather than lsm call Just to reduce the number of places to change if we every change the LSM hook, use the capability helpers internally when possible. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- kernel/capability.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/capability.c b/kernel/capability.c index 5f99e5d68e1..47626446c39 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -384,7 +384,7 @@ bool ns_capable(struct user_namespace *ns, int cap) BUG(); } - if (security_capable(current_cred(), ns, cap) == 0) { + if (has_ns_capability(current, ns, cap)) { current->flags |= PF_SUPERPRIV; return true; } -- cgit v1.2.3 From f1c84dae0ecc51aa35c81f19a0ebcd6c0921ddcb Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: capabilities: remove task_ns_* functions task_ in the front of a function, in the security subsystem anyway, means to me at least, that we are operating with that task as the subject of the security decision. In this case what it means is that we are using current as the subject but we use the task to get the right namespace. Who in the world would ever realize that's what task_ns_capability means just by the name? This patch eliminates the task_ns functions entirely and uses the has_ns_capability function instead. This means we explicitly open code the ns in question in the caller. I think it makes the caller a LOT more clear what is going on. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- include/linux/capability.h | 1 - include/linux/cred.h | 6 ++++-- kernel/capability.c | 14 -------------- kernel/ptrace.c | 4 ++-- kernel/sched.c | 2 +- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index 63f59fa8769..e3e8d9cb9b0 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -547,7 +547,6 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, struct user_namespace *ns, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); -extern bool task_ns_capable(struct task_struct *t, int cap); extern bool nsown_capable(int cap); /* audit system wants to get cap info from files as well */ diff --git a/include/linux/cred.h b/include/linux/cred.h index 40308969ed0..adadf71a732 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -358,10 +358,12 @@ static inline void put_cred(const struct cred *_cred) #define current_security() (current_cred_xxx(security)) #ifdef CONFIG_USER_NS -#define current_user_ns() (current_cred_xxx(user_ns)) +#define current_user_ns() (current_cred_xxx(user_ns)) +#define task_user_ns(task) (task_cred_xxx((task), user_ns)) #else extern struct user_namespace init_user_ns; -#define current_user_ns() (&init_user_ns) +#define current_user_ns() (&init_user_ns) +#define task_user_ns(task) (&init_user_ns) #endif diff --git a/kernel/capability.c b/kernel/capability.c index 47626446c39..74fb3b60304 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -408,20 +408,6 @@ bool capable(int cap) } EXPORT_SYMBOL(capable); -/** - * task_ns_capable - Determine whether current task has a superior - * capability targeted at a specific task's user namespace. - * @t: The task whose user namespace is targeted. - * @cap: The capability in question. - * - * Return true if it does, false otherwise. - */ -bool task_ns_capable(struct task_struct *t, int cap) -{ - return ns_capable(task_cred_xxx(t, user)->user_ns, cap); -} -EXPORT_SYMBOL(task_ns_capable); - /** * nsown_capable - Check superior capability to one's own user_ns * @cap: The capability in question diff --git a/kernel/ptrace.c b/kernel/ptrace.c index a70d2a5d8c7..210bbf045ee 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -196,7 +196,7 @@ ok: smp_rmb(); if (task->mm) dumpable = get_dumpable(task->mm); - if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) + if (!dumpable && !ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) return -EPERM; return security_ptrace_access_check(task, mode); @@ -266,7 +266,7 @@ static int ptrace_attach(struct task_struct *task, long request, task->ptrace = PT_PTRACED; if (seize) task->ptrace |= PT_SEIZED; - if (task_ns_capable(task, CAP_SYS_PTRACE)) + if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; __ptrace_link(task, current); diff --git a/kernel/sched.c b/kernel/sched.c index b50b0f0c9aa..5670028a9c1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -5409,7 +5409,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) goto out_free_cpus_allowed; } retval = -EPERM; - if (!check_same_owner(p) && !task_ns_capable(p, CAP_SYS_NICE)) + if (!check_same_owner(p) && !ns_capable(task_user_ns(p), CAP_SYS_NICE)) goto out_unlock; retval = security_task_setscheduler(p); -- cgit v1.2.3 From 69f594a38967f4540ce7a29b3fd214e68a8330bd Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:15 -0500 Subject: ptrace: do not audit capability check when outputing /proc/pid/stat Reading /proc/pid/stat of another process checks if one has ptrace permissions on that process. If one does have permissions it outputs some data about the process which might have security and attack implications. If the current task does not have ptrace permissions the read still works, but those fields are filled with inocuous (0) values. Since this check and a subsequent denial is not a violation of the security policy we should not audit such denials. This can be quite useful to removing ptrace broadly across a system without flooding the logs when ps is run or something which harmlessly walks proc. Signed-off-by: Eric Paris Acked-by: Serge E. Hallyn --- fs/proc/array.c | 2 +- include/linux/ptrace.h | 5 +++-- kernel/ptrace.c | 12 ++++++++++-- security/selinux/hooks.c | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 3a1dafd228d..ddffd7a88b9 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -380,7 +380,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, state = *get_task_state(task); vsize = eip = esp = 0; - permitted = ptrace_may_access(task, PTRACE_MODE_READ); + permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT); mm = get_task_mm(task); if (mm) { vsize = task_vsize(mm); diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 800f113bea6..a27e56ca41a 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -127,8 +127,9 @@ extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); extern void exit_ptrace(struct task_struct *tracer); -#define PTRACE_MODE_READ 1 -#define PTRACE_MODE_ATTACH 2 +#define PTRACE_MODE_READ 0x01 +#define PTRACE_MODE_ATTACH 0x02 +#define PTRACE_MODE_NOAUDIT 0x04 /* Returns 0 on success, -errno on denial. */ extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); /* Returns true on success, false on denial. */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 210bbf045ee..c890ac9a796 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -161,6 +161,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state) return ret; } +static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) +{ + if (mode & PTRACE_MODE_NOAUDIT) + return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); + else + return has_ns_capability(current, ns, CAP_SYS_PTRACE); +} + int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; @@ -187,7 +195,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) cred->gid == tcred->sgid && cred->gid == tcred->gid)) goto ok; - if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) + if (ptrace_has_cap(tcred->user->user_ns, mode)) goto ok; rcu_read_unlock(); return -EPERM; @@ -196,7 +204,7 @@ ok: smp_rmb(); if (task->mm) dumpable = get_dumpable(task->mm); - if (!dumpable && !ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) + if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode)) return -EPERM; return security_ptrace_access_check(task, mode); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c9605c4a2e0..14f94cd29c8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1809,7 +1809,7 @@ static int selinux_ptrace_access_check(struct task_struct *child, if (rc) return rc; - if (mode == PTRACE_MODE_READ) { + if (mode & PTRACE_MODE_READ) { u32 sid = current_sid(); u32 csid = task_sid(child); return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); -- cgit v1.2.3 From fd778461524849afd035679030ae8e8873c72b81 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:16 -0500 Subject: security: remove the security_netlink_recv hook as it is equivalent to capable() Once upon a time netlink was not sync and we had to get the effective capabilities from the skb that was being received. Today we instead get the capabilities from the current task. This has rendered the entire purpose of the hook moot as it is now functionally equivalent to the capable() call. Signed-off-by: Eric Paris --- drivers/scsi/scsi_netlink.c | 2 +- include/linux/security.h | 14 -------------- kernel/audit.c | 4 ++-- net/core/rtnetlink.c | 2 +- net/decnet/netfilter/dn_rtmsg.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv6/netfilter/ip6_queue.c | 2 +- net/netfilter/nfnetlink.c | 2 +- net/netlink/genetlink.c | 2 +- net/xfrm/xfrm_user.c | 2 +- security/capability.c | 1 - security/commoncap.c | 8 -------- security/security.c | 6 ------ security/selinux/hooks.c | 19 ------------------- 14 files changed, 10 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 26a8a45584e..feee1cc39ea 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -111,7 +111,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) goto next_msg; } - if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { err = -EPERM; goto next_msg; } diff --git a/include/linux/security.h b/include/linux/security.h index e345a9313a6..ba2d531c123 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -95,7 +95,6 @@ struct xfrm_user_sec_ctx; struct seq_file; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); -extern int cap_netlink_recv(struct sk_buff *skb, int cap); void reset_security_ops(void); @@ -792,12 +791,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @skb contains the sk_buff structure for the netlink message. * Return 0 if the information was successfully saved and message * is allowed to be transmitted. - * @netlink_recv: - * Check permission before processing the received netlink message in - * @skb. - * @skb contains the sk_buff structure for the netlink message. - * @cap indicates the capability required - * Return 0 if permission is granted. * * Security hooks for Unix domain networking. * @@ -1556,7 +1549,6 @@ struct security_operations { struct sembuf *sops, unsigned nsops, int alter); int (*netlink_send) (struct sock *sk, struct sk_buff *skb); - int (*netlink_recv) (struct sk_buff *skb, int cap); void (*d_instantiate) (struct dentry *dentry, struct inode *inode); @@ -1803,7 +1795,6 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode); int security_getprocattr(struct task_struct *p, char *name, char **value); int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size); int security_netlink_send(struct sock *sk, struct sk_buff *skb); -int security_netlink_recv(struct sk_buff *skb, int cap); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); void security_release_secctx(char *secdata, u32 seclen); @@ -2478,11 +2469,6 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb) return cap_netlink_send(sk, skb); } -static inline int security_netlink_recv(struct sk_buff *skb, int cap) -{ - return cap_netlink_recv(skb, cap); -} - static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { return -EOPNOTSUPP; diff --git a/kernel/audit.c b/kernel/audit.c index 0a1355ca3d7..f3ba55fa0b7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -601,13 +601,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) case AUDIT_TTY_SET: case AUDIT_TRIM: case AUDIT_MAKE_EQUIV: - if (security_netlink_recv(skb, CAP_AUDIT_CONTROL)) + if (!capable(CAP_AUDIT_CONTROL)) err = -EPERM; break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: - if (security_netlink_recv(skb, CAP_AUDIT_WRITE)) + if (!capable(CAP_AUDIT_WRITE)) err = -EPERM; break; default: /* bad msg */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 99d9e953fe3..d3a62819671 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1931,7 +1931,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) sz_idx = type>>2; kind = type&3; - if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) + if (kind != 2 && !capable(CAP_NET_ADMIN)) return -EPERM; if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 69975e0bcde..1531135130d 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -108,7 +108,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); /* Eventually we might send routing messages too */ diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index e59aabd0eae..ffabb267471 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -430,7 +430,7 @@ __ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); spin_lock_bh(&queue_lock); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e63c3972a73..5e5ce778be7 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -431,7 +431,7 @@ __ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); spin_lock_bh(&queue_lock); diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 1905976b513..e6c2b8f3218 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -130,7 +130,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) const struct nfnetlink_subsystem *ss; int type, err; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* All the messages must at least contain nfgenmsg */ diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 482fa571b4e..05fedbf489a 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -516,7 +516,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EOPNOTSUPP; if ((ops->flags & GENL_ADMIN_PERM) && - security_netlink_recv(skb, CAP_NET_ADMIN)) + !capable(CAP_NET_ADMIN)) return -EPERM; if (nlh->nlmsg_flags & NLM_F_DUMP) { diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0256b8a0a7c..71de86698ef 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2290,7 +2290,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) link = &xfrm_dispatch[type]; /* All operations require privileges, even GET */ - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || diff --git a/security/capability.c b/security/capability.c index 2984ea4f776..a2c064d1044 100644 --- a/security/capability.c +++ b/security/capability.c @@ -999,7 +999,6 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, sem_semctl); set_to_cap_if_null(ops, sem_semop); set_to_cap_if_null(ops, netlink_send); - set_to_cap_if_null(ops, netlink_recv); set_to_cap_if_null(ops, d_instantiate); set_to_cap_if_null(ops, getprocattr); set_to_cap_if_null(ops, setprocattr); diff --git a/security/commoncap.c b/security/commoncap.c index 89f02ff66af..7817a763444 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -56,14 +56,6 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) return 0; } -int cap_netlink_recv(struct sk_buff *skb, int cap) -{ - if (!cap_raised(current_cap(), cap)) - return -EPERM; - return 0; -} -EXPORT_SYMBOL(cap_netlink_recv); - /** * cap_capable - Determine whether a task has a particular effective capability * @cred: The credentials to use diff --git a/security/security.c b/security/security.c index 8900c5c4db5..85481a9c563 100644 --- a/security/security.c +++ b/security/security.c @@ -922,12 +922,6 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb) return security_ops->netlink_send(sk, skb); } -int security_netlink_recv(struct sk_buff *skb, int cap) -{ - return security_ops->netlink_recv(skb, cap); -} -EXPORT_SYMBOL(security_netlink_recv); - int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { return security_ops->secid_to_secctx(secid, secdata, seclen); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 14f94cd29c8..3e37d25a9bb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4713,24 +4713,6 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) return selinux_nlmsg_perm(sk, skb); } -static int selinux_netlink_recv(struct sk_buff *skb, int capability) -{ - int err; - struct common_audit_data ad; - u32 sid; - - err = cap_netlink_recv(skb, capability); - if (err) - return err; - - COMMON_AUDIT_DATA_INIT(&ad, CAP); - ad.u.cap = capability; - - security_task_getsecid(current, &sid); - return avc_has_perm(sid, sid, SECCLASS_CAPABILITY, - CAP_TO_MASK(capability), &ad); -} - static int ipc_alloc_security(struct task_struct *task, struct kern_ipc_perm *perm, u16 sclass) @@ -5459,7 +5441,6 @@ static struct security_operations selinux_ops = { .vm_enough_memory = selinux_vm_enough_memory, .netlink_send = selinux_netlink_send, - .netlink_recv = selinux_netlink_recv, .bprm_set_creds = selinux_bprm_set_creds, .bprm_committing_creds = selinux_bprm_committing_creds, -- cgit v1.2.3 From f423e5ba76e7e4a6fcb4836b4f072d1fdebba8b5 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Jan 2012 12:25:16 -0500 Subject: capabilities: remove __cap_full_set definition In 5163b583a036b103c3cec7171d6731c125773ed6 I removed __cap_full_set but forgot to remove it from a header. Do that. Reported-by: Kornilios Kourtis Signed-off-by: Eric Paris --- include/linux/capability.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index e3e8d9cb9b0..d527b288033 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -379,7 +379,6 @@ struct user_namespace; struct user_namespace *current_user_ns(void); extern const kernel_cap_t __cap_empty_set; -extern const kernel_cap_t __cap_full_set; extern const kernel_cap_t __cap_init_eff_set; /* -- cgit v1.2.3