aboutsummaryrefslogtreecommitdiffstats
path: root/security
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
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')
-rw-r--r--security/apparmor/lsm.c5
-rw-r--r--security/commoncap.c38
-rw-r--r--security/security.c16
-rw-r--r--security/selinux/hooks.c13
4 files changed, 52 insertions, 20 deletions
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index d21a427a35ae..ae3a698415e6 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -22,6 +22,7 @@
22#include <linux/ctype.h> 22#include <linux/ctype.h>
23#include <linux/sysctl.h> 23#include <linux/sysctl.h>
24#include <linux/audit.h> 24#include <linux/audit.h>
25#include <linux/user_namespace.h>
25#include <net/sock.h> 26#include <net/sock.h>
26 27
27#include "include/apparmor.h" 28#include "include/apparmor.h"
@@ -136,11 +137,11 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
136} 137}
137 138
138static int apparmor_capable(struct task_struct *task, const struct cred *cred, 139static int apparmor_capable(struct task_struct *task, const struct cred *cred,
139 int cap, int audit) 140 struct user_namespace *ns, int cap, int audit)
140{ 141{
141 struct aa_profile *profile; 142 struct aa_profile *profile;
142 /* cap_capable returns 0 on success, else -EPERM */ 143 /* cap_capable returns 0 on success, else -EPERM */
143 int error = cap_capable(task, cred, cap, audit); 144 int error = cap_capable(task, cred, ns, cap, audit);
144 if (!error) { 145 if (!error) {
145 profile = aa_cred_profile(cred); 146 profile = aa_cred_profile(cred);
146 if (!unconfined(profile)) 147 if (!unconfined(profile))
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)
diff --git a/security/security.c b/security/security.c
index 9187665a3fdd..101142369db4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -154,29 +154,33 @@ 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(const struct cred *cred, int cap) 157int security_capable(struct user_namespace *ns, const struct cred *cred,
158 int cap)
158{ 159{
159 return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT); 160 return security_ops->capable(current, cred, ns, cap,
161 SECURITY_CAP_AUDIT);
160} 162}
161 163
162int security_real_capable(struct task_struct *tsk, int cap) 164int security_real_capable(struct task_struct *tsk, struct user_namespace *ns,
165 int cap)
163{ 166{
164 const struct cred *cred; 167 const struct cred *cred;
165 int ret; 168 int ret;
166 169
167 cred = get_task_cred(tsk); 170 cred = get_task_cred(tsk);
168 ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT); 171 ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_AUDIT);
169 put_cred(cred); 172 put_cred(cred);
170 return ret; 173 return ret;
171} 174}
172 175
173int security_real_capable_noaudit(struct task_struct *tsk, int cap) 176int security_real_capable_noaudit(struct task_struct *tsk,
177 struct user_namespace *ns, int cap)
174{ 178{
175 const struct cred *cred; 179 const struct cred *cred;
176 int ret; 180 int ret;
177 181
178 cred = get_task_cred(tsk); 182 cred = get_task_cred(tsk);
179 ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT); 183 ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_NOAUDIT);
180 put_cred(cred); 184 put_cred(cred);
181 return ret; 185 return ret;
182} 186}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6475e1f0223e..c67f863d3546 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -79,6 +79,7 @@
79#include <linux/mutex.h> 79#include <linux/mutex.h>
80#include <linux/posix-timers.h> 80#include <linux/posix-timers.h>
81#include <linux/syslog.h> 81#include <linux/syslog.h>
82#include <linux/user_namespace.h>
82 83
83#include "avc.h" 84#include "avc.h"
84#include "objsec.h" 85#include "objsec.h"
@@ -1846,11 +1847,11 @@ static int selinux_capset(struct cred *new, const struct cred *old,
1846 */ 1847 */
1847 1848
1848static int selinux_capable(struct task_struct *tsk, const struct cred *cred, 1849static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
1849 int cap, int audit) 1850 struct user_namespace *ns, int cap, int audit)
1850{ 1851{
1851 int rc; 1852 int rc;
1852 1853
1853 rc = cap_capable(tsk, cred, cap, audit); 1854 rc = cap_capable(tsk, cred, ns, cap, audit);
1854 if (rc) 1855 if (rc)
1855 return rc; 1856 return rc;
1856 1857
@@ -1931,7 +1932,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
1931{ 1932{
1932 int rc, cap_sys_admin = 0; 1933 int rc, cap_sys_admin = 0;
1933 1934
1934 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN, 1935 rc = selinux_capable(current, current_cred(),
1936 &init_user_ns, CAP_SYS_ADMIN,
1935 SECURITY_CAP_NOAUDIT); 1937 SECURITY_CAP_NOAUDIT);
1936 if (rc == 0) 1938 if (rc == 0)
1937 cap_sys_admin = 1; 1939 cap_sys_admin = 1;
@@ -2834,7 +2836,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
2834 * and lack of permission just means that we fall back to the 2836 * and lack of permission just means that we fall back to the
2835 * in-core context value, not a denial. 2837 * in-core context value, not a denial.
2836 */ 2838 */
2837 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN, 2839 error = selinux_capable(current, current_cred(),
2840 &init_user_ns, CAP_MAC_ADMIN,
2838 SECURITY_CAP_NOAUDIT); 2841 SECURITY_CAP_NOAUDIT);
2839 if (!error) 2842 if (!error)
2840 error = security_sid_to_context_force(isec->sid, &context, 2843 error = security_sid_to_context_force(isec->sid, &context,
@@ -2968,7 +2971,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2968 case KDSKBENT: 2971 case KDSKBENT:
2969 case KDSKBSENT: 2972 case KDSKBSENT:
2970 error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, 2973 error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
2971 SECURITY_CAP_AUDIT); 2974 SECURITY_CAP_AUDIT);
2972 break; 2975 break;
2973 2976
2974 /* default case assumes that the command will go 2977 /* default case assumes that the command will go