diff options
author | Serge E. Hallyn <serge@hallyn.com> | 2011-03-23 16:43:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 19:47:08 -0700 |
commit | b0e77598f87107001a00b8a4ece9c95e4254ccc4 (patch) | |
tree | 2738276570e4faa7c92a64521c192f04dca93801 /ipc/util.c | |
parent | b515498f5bb5f38fc0e390b4ff7d00b6077de127 (diff) | |
download | lwn-b0e77598f87107001a00b8a4ece9c95e4254ccc4.tar.gz lwn-b0e77598f87107001a00b8a4ece9c95e4254ccc4.zip |
userns: user namespaces: convert several capable() calls
CAP_IPC_OWNER and CAP_IPC_LOCK can be checked against current_user_ns(),
because the resource comes from current's own ipc namespace.
setuid/setgid are to uids in own namespace, so again checks can be against
current_user_ns().
Changelog:
Jan 11: Use task_ns_capable() in place of sched_capable().
Jan 11: Use nsown_capable() as suggested by Bastian Blank.
Jan 11: Clarify (hopefully) some logic in futex and sched.c
Feb 15: use ns_capable for ipc, not nsown_capable
Feb 23: let copy_ipcs handle setting ipc_ns->user_ns
Feb 23: pass ns down rather than taking it from current
[akpm@linux-foundation.org: coding-style fixes]
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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc/util.c')
-rw-r--r-- | ipc/util.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/ipc/util.c b/ipc/util.c index 69a0cc13d966..8fd1b891ec0c 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -329,12 +329,14 @@ retry: * * It is called with ipc_ids.rw_mutex and ipcp->lock held. */ -static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, - struct ipc_params *params) +static int ipc_check_perms(struct ipc_namespace *ns, + struct kern_ipc_perm *ipcp, + struct ipc_ops *ops, + struct ipc_params *params) { int err; - if (ipcperms(ipcp, params->flg)) + if (ipcperms(ns, ipcp, params->flg)) err = -EACCES; else { err = ops->associate(ipcp, params->flg); @@ -396,7 +398,7 @@ retry: * ipc_check_perms returns the IPC id on * success */ - err = ipc_check_perms(ipcp, ops, params); + err = ipc_check_perms(ns, ipcp, ops, params); } ipc_unlock(ipcp); } @@ -610,10 +612,12 @@ void ipc_rcu_putref(void *ptr) * * Check user, group, other permissions for access * to ipc resources. return 0 if allowed + * + * @flag will most probably be 0 or S_...UGO from <linux/stat.h> */ -int ipcperms (struct kern_ipc_perm *ipcp, short flag) -{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ +int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) +{ uid_t euid = current_euid(); int requested_mode, granted_mode; @@ -627,7 +631,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag) granted_mode >>= 3; /* is there some bit set in requested_mode but not in granted_mode? */ if ((requested_mode & ~granted_mode & 0007) && - !capable(CAP_IPC_OWNER)) + !ns_capable(ns->user_ns, CAP_IPC_OWNER)) return -1; return security_ipc_permission(ipcp, flag); @@ -765,6 +769,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) /** * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd + * @ids: the ipc namespace * @ids: the table of ids where to look for the ipc * @id: the id of the ipc to retrieve * @cmd: the cmd to check @@ -779,7 +784,8 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) * - returns the ipc with both ipc and rw_mutex locks held in case of success * or an err-code without any lock held otherwise. */ -struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, +struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns, + struct ipc_ids *ids, int id, int cmd, struct ipc64_perm *perm, int extra_perm) { struct kern_ipc_perm *ipcp; @@ -799,8 +805,8 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, perm->gid, perm->mode); euid = current_euid(); - if (euid == ipcp->cuid || - euid == ipcp->uid || capable(CAP_SYS_ADMIN)) + if (euid == ipcp->cuid || euid == ipcp->uid || + ns_capable(ns->user_ns, CAP_SYS_ADMIN)) return ipcp; err = -EPERM; |