aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorSerge E. Hallyn <serge@hallyn.com>2011-03-23 19:43:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 22:47:02 -0400
commit3486740a4f32a6a466f5ac931654d154790ba648 (patch)
treeac5d968a66057fa84933b8f89fd3e916270dffed /security/commoncap.c
parent59607db367c57f515183cb203642291bb14d9c40 (diff)
userns: security: make capabilities relative to the user namespace
- Introduce ns_capable to test for a capability in a non-default user namespace. - Teach cap_capable to handle capabilities in a non-default user namespace. The motivation is to get to the unprivileged creation of new namespaces. It looks like this gets us 90% of the way there, with only potential uid confusion issues left. I still need to handle getting all caps after creation but otherwise I think I have a good starter patch that achieves all of your goals. Changelog: 11/05/2010: [serge] add apparmor 12/14/2010: [serge] fix capabilities to created user namespaces Without this, if user serge creates a user_ns, he won't have capabilities to the user_ns he created. THis is because we were first checking whether his effective caps had the caps he needed and returning -EPERM if not, and THEN checking whether he was the creator. Reverse those checks. 12/16/2010: [serge] security_real_capable needs ns argument in !security case 01/11/2011: [serge] add task_ns_capable helper 01/11/2011: [serge] add nsown_capable() helper per Bastian Blank suggestion 02/16/2011: [serge] fix a logic bug: the root user is always creator of init_user_ns, but should not always have capabilities to it! Fix the check in cap_capable(). 02/21/2011: Add the required user_ns parameter to security_capable, fixing a compile failure. 02/23/2011: Convert some macros to functions as per akpm comments. Some couldn't be converted because we can't easily forward-declare them (they are inline if !SECURITY, extern if SECURITY). Add a current_user_ns function so we can use it in capability.h without #including cred.h. Move all forward declarations together to the top of the #ifdef __KERNEL__ section, and use kernel-doc format. 02/23/2011: Per dhowells, clean up comment in cap_capable(). 02/23/2011: Per akpm, remove unreachable 'return -EPERM' in cap_capable. (Original written and signed off by Eric; latest, modified version acked by him) [akpm@linux-foundation.org: fix build] [akpm@linux-foundation.org: export current_user_ns() for ecryptfs] [serge.hallyn@canonical.com: remove unneeded extra argument in selinux's task_has_capability] Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Acked-by: Daniel Lezcano <daniel.lezcano@free.fr> Acked-by: David Howells <dhowells@redhat.com> Cc: James Morris <jmorris@namei.org> Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 49c57fd60aea..43a205bc7d7c 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -27,6 +27,7 @@
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/prctl.h> 28#include <linux/prctl.h>
29#include <linux/securebits.h> 29#include <linux/securebits.h>
30#include <linux/user_namespace.h>
30 31
31/* 32/*
32 * If a non-root user executes a setuid-root binary in 33 * If a non-root user executes a setuid-root binary in
@@ -67,6 +68,7 @@ EXPORT_SYMBOL(cap_netlink_recv);
67 * cap_capable - Determine whether a task has a particular effective capability 68 * cap_capable - Determine whether a task has a particular effective capability
68 * @tsk: The task to query 69 * @tsk: The task to query
69 * @cred: The credentials to use 70 * @cred: The credentials to use
71 * @ns: The user namespace in which we need the capability
70 * @cap: The capability to check for 72 * @cap: The capability to check for
71 * @audit: Whether to write an audit message or not 73 * @audit: Whether to write an audit message or not
72 * 74 *
@@ -78,10 +80,30 @@ EXPORT_SYMBOL(cap_netlink_recv);
78 * cap_has_capability() returns 0 when a task has a capability, but the 80 * cap_has_capability() returns 0 when a task has a capability, but the
79 * kernel's capable() and has_capability() returns 1 for this case. 81 * kernel's capable() and has_capability() returns 1 for this case.
80 */ 82 */
81int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap, 83int cap_capable(struct task_struct *tsk, const struct cred *cred,
82 int audit) 84 struct user_namespace *targ_ns, int cap, int audit)
83{ 85{
84 return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; 86 for (;;) {
87 /* The creator of the user namespace has all caps. */
88 if (targ_ns != &init_user_ns && targ_ns->creator == cred->user)
89 return 0;
90
91 /* Do we have the necessary capabilities? */
92 if (targ_ns == cred->user->user_ns)
93 return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
94
95 /* Have we tried all of the parent namespaces? */
96 if (targ_ns == &init_user_ns)
97 return -EPERM;
98
99 /*
100 *If you have a capability in a parent user ns, then you have
101 * it over all children user namespaces as well.
102 */
103 targ_ns = targ_ns->creator->user_ns;
104 }
105
106 /* We never get here */
85} 107}
86 108
87/** 109/**
@@ -176,7 +198,8 @@ static inline int cap_inh_is_capped(void)
176 /* they are so limited unless the current task has the CAP_SETPCAP 198 /* they are so limited unless the current task has the CAP_SETPCAP
177 * capability 199 * capability
178 */ 200 */
179 if (cap_capable(current, current_cred(), CAP_SETPCAP, 201 if (cap_capable(current, current_cred(),
202 current_cred()->user->user_ns, CAP_SETPCAP,
180 SECURITY_CAP_AUDIT) == 0) 203 SECURITY_CAP_AUDIT) == 0)
181 return 0; 204 return 0;
182 return 1; 205 return 1;
@@ -828,7 +851,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
828 & (new->securebits ^ arg2)) /*[1]*/ 851 & (new->securebits ^ arg2)) /*[1]*/
829 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ 852 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
830 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ 853 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
831 || (cap_capable(current, current_cred(), CAP_SETPCAP, 854 || (cap_capable(current, current_cred(),
855 current_cred()->user->user_ns, CAP_SETPCAP,
832 SECURITY_CAP_AUDIT) != 0) /*[4]*/ 856 SECURITY_CAP_AUDIT) != 0) /*[4]*/
833 /* 857 /*
834 * [1] no changing of bits that are locked 858 * [1] no changing of bits that are locked
@@ -893,7 +917,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
893{ 917{
894 int cap_sys_admin = 0; 918 int cap_sys_admin = 0;
895 919
896 if (cap_capable(current, current_cred(), CAP_SYS_ADMIN, 920 if (cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_ADMIN,
897 SECURITY_CAP_NOAUDIT) == 0) 921 SECURITY_CAP_NOAUDIT) == 0)
898 cap_sys_admin = 1; 922 cap_sys_admin = 1;
899 return __vm_enough_memory(mm, pages, cap_sys_admin); 923 return __vm_enough_memory(mm, pages, cap_sys_admin);
@@ -920,7 +944,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
920 int ret = 0; 944 int ret = 0;
921 945
922 if (addr < dac_mmap_min_addr) { 946 if (addr < dac_mmap_min_addr) {
923 ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, 947 ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO,
924 SECURITY_CAP_AUDIT); 948 SECURITY_CAP_AUDIT);
925 /* set PF_SUPERPRIV if it turns out we allow the low mmap */ 949 /* set PF_SUPERPRIV if it turns out we allow the low mmap */
926 if (ret == 0) 950 if (ret == 0)