aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorSerge E. Hallyn <serge@hallyn.com>2011-03-23 19:43:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 22:47:08 -0400
commitb0e77598f87107001a00b8a4ece9c95e4254ccc4 (patch)
tree2738276570e4faa7c92a64521c192f04dca93801 /ipc
parentb515498f5bb5f38fc0e390b4ff7d00b6077de127 (diff)
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')
-rw-r--r--ipc/msg.c8
-rw-r--r--ipc/namespace.c13
-rw-r--r--ipc/sem.c10
-rw-r--r--ipc/shm.c9
-rw-r--r--ipc/util.c26
-rw-r--r--ipc/util.h5
6 files changed, 42 insertions, 29 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 747b65507a91..0e732e92e22f 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -421,7 +421,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
421 return -EFAULT; 421 return -EFAULT;
422 } 422 }
423 423
424 ipcp = ipcctl_pre_down(&msg_ids(ns), msqid, cmd, 424 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
425 &msqid64.msg_perm, msqid64.msg_qbytes); 425 &msqid64.msg_perm, msqid64.msg_qbytes);
426 if (IS_ERR(ipcp)) 426 if (IS_ERR(ipcp))
427 return PTR_ERR(ipcp); 427 return PTR_ERR(ipcp);
@@ -539,7 +539,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
539 success_return = 0; 539 success_return = 0;
540 } 540 }
541 err = -EACCES; 541 err = -EACCES;
542 if (ipcperms(&msq->q_perm, S_IRUGO)) 542 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
543 goto out_unlock; 543 goto out_unlock;
544 544
545 err = security_msg_queue_msgctl(msq, cmd); 545 err = security_msg_queue_msgctl(msq, cmd);
@@ -664,7 +664,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
664 struct msg_sender s; 664 struct msg_sender s;
665 665
666 err = -EACCES; 666 err = -EACCES;
667 if (ipcperms(&msq->q_perm, S_IWUGO)) 667 if (ipcperms(ns, &msq->q_perm, S_IWUGO))
668 goto out_unlock_free; 668 goto out_unlock_free;
669 669
670 err = security_msg_queue_msgsnd(msq, msg, msgflg); 670 err = security_msg_queue_msgsnd(msq, msg, msgflg);
@@ -774,7 +774,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
774 struct list_head *tmp; 774 struct list_head *tmp;
775 775
776 msg = ERR_PTR(-EACCES); 776 msg = ERR_PTR(-EACCES);
777 if (ipcperms(&msq->q_perm, S_IRUGO)) 777 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
778 goto out_unlock; 778 goto out_unlock;
779 779
780 msg = ERR_PTR(-EAGAIN); 780 msg = ERR_PTR(-EAGAIN);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index aa1889962693..3c3e5223e7e5 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -15,7 +15,8 @@
15 15
16#include "util.h" 16#include "util.h"
17 17
18static struct ipc_namespace *create_ipc_ns(struct ipc_namespace *old_ns) 18static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
19 struct ipc_namespace *old_ns)
19{ 20{
20 struct ipc_namespace *ns; 21 struct ipc_namespace *ns;
21 int err; 22 int err;
@@ -44,17 +45,19 @@ static struct ipc_namespace *create_ipc_ns(struct ipc_namespace *old_ns)
44 ipcns_notify(IPCNS_CREATED); 45 ipcns_notify(IPCNS_CREATED);
45 register_ipcns_notifier(ns); 46 register_ipcns_notifier(ns);
46 47
47 ns->user_ns = old_ns->user_ns; 48 ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
48 get_user_ns(ns->user_ns);
49 49
50 return ns; 50 return ns;
51} 51}
52 52
53struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) 53struct ipc_namespace *copy_ipcs(unsigned long flags,
54 struct task_struct *tsk)
54{ 55{
56 struct ipc_namespace *ns = tsk->nsproxy->ipc_ns;
57
55 if (!(flags & CLONE_NEWIPC)) 58 if (!(flags & CLONE_NEWIPC))
56 return get_ipc_ns(ns); 59 return get_ipc_ns(ns);
57 return create_ipc_ns(ns); 60 return create_ipc_ns(tsk, ns);
58} 61}
59 62
60/* 63/*
diff --git a/ipc/sem.c b/ipc/sem.c
index 0e0d49bbb867..ae040a0727c2 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -817,7 +817,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
817 } 817 }
818 818
819 err = -EACCES; 819 err = -EACCES;
820 if (ipcperms (&sma->sem_perm, S_IRUGO)) 820 if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
821 goto out_unlock; 821 goto out_unlock;
822 822
823 err = security_sem_semctl(sma, cmd); 823 err = security_sem_semctl(sma, cmd);
@@ -862,7 +862,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
862 nsems = sma->sem_nsems; 862 nsems = sma->sem_nsems;
863 863
864 err = -EACCES; 864 err = -EACCES;
865 if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) 865 if (ipcperms(ns, &sma->sem_perm,
866 (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
866 goto out_unlock; 867 goto out_unlock;
867 868
868 err = security_sem_semctl(sma, cmd); 869 err = security_sem_semctl(sma, cmd);
@@ -1047,7 +1048,8 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1047 return -EFAULT; 1048 return -EFAULT;
1048 } 1049 }
1049 1050
1050 ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0); 1051 ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
1052 &semid64.sem_perm, 0);
1051 if (IS_ERR(ipcp)) 1053 if (IS_ERR(ipcp))
1052 return PTR_ERR(ipcp); 1054 return PTR_ERR(ipcp);
1053 1055
@@ -1386,7 +1388,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1386 goto out_unlock_free; 1388 goto out_unlock_free;
1387 1389
1388 error = -EACCES; 1390 error = -EACCES;
1389 if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) 1391 if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
1390 goto out_unlock_free; 1392 goto out_unlock_free;
1391 1393
1392 error = security_sem_semop(sma, sops, nsops, alter); 1394 error = security_sem_semop(sma, sops, nsops, alter);
diff --git a/ipc/shm.c b/ipc/shm.c
index 7d3bb22a9302..8644452f5c4c 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -623,7 +623,8 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
623 return -EFAULT; 623 return -EFAULT;
624 } 624 }
625 625
626 ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0); 626 ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
627 &shmid64.shm_perm, 0);
627 if (IS_ERR(ipcp)) 628 if (IS_ERR(ipcp))
628 return PTR_ERR(ipcp); 629 return PTR_ERR(ipcp);
629 630
@@ -737,7 +738,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
737 result = 0; 738 result = 0;
738 } 739 }
739 err = -EACCES; 740 err = -EACCES;
740 if (ipcperms (&shp->shm_perm, S_IRUGO)) 741 if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
741 goto out_unlock; 742 goto out_unlock;
742 err = security_shm_shmctl(shp, cmd); 743 err = security_shm_shmctl(shp, cmd);
743 if (err) 744 if (err)
@@ -773,7 +774,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
773 774
774 audit_ipc_obj(&(shp->shm_perm)); 775 audit_ipc_obj(&(shp->shm_perm));
775 776
776 if (!capable(CAP_IPC_LOCK)) { 777 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
777 uid_t euid = current_euid(); 778 uid_t euid = current_euid();
778 err = -EPERM; 779 err = -EPERM;
779 if (euid != shp->shm_perm.uid && 780 if (euid != shp->shm_perm.uid &&
@@ -888,7 +889,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
888 } 889 }
889 890
890 err = -EACCES; 891 err = -EACCES;
891 if (ipcperms(&shp->shm_perm, acc_mode)) 892 if (ipcperms(ns, &shp->shm_perm, acc_mode))
892 goto out_unlock; 893 goto out_unlock;
893 894
894 err = security_shm_shmat(shp, shmaddr, shmflg); 895 err = security_shm_shmat(shp, shmaddr, shmflg);
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:
329 * 329 *
330 * It is called with ipc_ids.rw_mutex and ipcp->lock held. 330 * It is called with ipc_ids.rw_mutex and ipcp->lock held.
331 */ 331 */
332static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, 332static int ipc_check_perms(struct ipc_namespace *ns,
333 struct ipc_params *params) 333 struct kern_ipc_perm *ipcp,
334 struct ipc_ops *ops,
335 struct ipc_params *params)
334{ 336{
335 int err; 337 int err;
336 338
337 if (ipcperms(ipcp, params->flg)) 339 if (ipcperms(ns, ipcp, params->flg))
338 err = -EACCES; 340 err = -EACCES;
339 else { 341 else {
340 err = ops->associate(ipcp, params->flg); 342 err = ops->associate(ipcp, params->flg);
@@ -396,7 +398,7 @@ retry:
396 * ipc_check_perms returns the IPC id on 398 * ipc_check_perms returns the IPC id on
397 * success 399 * success
398 */ 400 */
399 err = ipc_check_perms(ipcp, ops, params); 401 err = ipc_check_perms(ns, ipcp, ops, params);
400 } 402 }
401 ipc_unlock(ipcp); 403 ipc_unlock(ipcp);
402 } 404 }
@@ -610,10 +612,12 @@ void ipc_rcu_putref(void *ptr)
610 * 612 *
611 * Check user, group, other permissions for access 613 * Check user, group, other permissions for access
612 * to ipc resources. return 0 if allowed 614 * to ipc resources. return 0 if allowed
615 *
616 * @flag will most probably be 0 or S_...UGO from <linux/stat.h>
613 */ 617 */
614 618
615int ipcperms (struct kern_ipc_perm *ipcp, short flag) 619int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
616{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ 620{
617 uid_t euid = current_euid(); 621 uid_t euid = current_euid();
618 int requested_mode, granted_mode; 622 int requested_mode, granted_mode;
619 623
@@ -627,7 +631,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag)
627 granted_mode >>= 3; 631 granted_mode >>= 3;
628 /* is there some bit set in requested_mode but not in granted_mode? */ 632 /* is there some bit set in requested_mode but not in granted_mode? */
629 if ((requested_mode & ~granted_mode & 0007) && 633 if ((requested_mode & ~granted_mode & 0007) &&
630 !capable(CAP_IPC_OWNER)) 634 !ns_capable(ns->user_ns, CAP_IPC_OWNER))
631 return -1; 635 return -1;
632 636
633 return security_ipc_permission(ipcp, flag); 637 return security_ipc_permission(ipcp, flag);
@@ -765,6 +769,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
765 769
766/** 770/**
767 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd 771 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
772 * @ids: the ipc namespace
768 * @ids: the table of ids where to look for the ipc 773 * @ids: the table of ids where to look for the ipc
769 * @id: the id of the ipc to retrieve 774 * @id: the id of the ipc to retrieve
770 * @cmd: the cmd to check 775 * @cmd: the cmd to check
@@ -779,7 +784,8 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
779 * - returns the ipc with both ipc and rw_mutex locks held in case of success 784 * - returns the ipc with both ipc and rw_mutex locks held in case of success
780 * or an err-code without any lock held otherwise. 785 * or an err-code without any lock held otherwise.
781 */ 786 */
782struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, 787struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
788 struct ipc_ids *ids, int id, int cmd,
783 struct ipc64_perm *perm, int extra_perm) 789 struct ipc64_perm *perm, int extra_perm)
784{ 790{
785 struct kern_ipc_perm *ipcp; 791 struct kern_ipc_perm *ipcp;
@@ -799,8 +805,8 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
799 perm->gid, perm->mode); 805 perm->gid, perm->mode);
800 806
801 euid = current_euid(); 807 euid = current_euid();
802 if (euid == ipcp->cuid || 808 if (euid == ipcp->cuid || euid == ipcp->uid ||
803 euid == ipcp->uid || capable(CAP_SYS_ADMIN)) 809 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
804 return ipcp; 810 return ipcp;
805 811
806 err = -EPERM; 812 err = -EPERM;
diff --git a/ipc/util.h b/ipc/util.h
index 764b51a37a6a..6f5c20bedaab 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -103,7 +103,7 @@ int ipc_get_maxid(struct ipc_ids *);
103void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); 103void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
104 104
105/* must be called with ipcp locked */ 105/* must be called with ipcp locked */
106int ipcperms(struct kern_ipc_perm *ipcp, short flg); 106int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
107 107
108/* for rare, potentially huge allocations. 108/* for rare, potentially huge allocations.
109 * both function can sleep 109 * both function can sleep
@@ -126,7 +126,8 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
126void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 126void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
127void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); 127void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
128void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); 128void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, 129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
130 struct ipc_ids *ids, int id, int cmd,
130 struct ipc64_perm *perm, int extra_perm); 131 struct ipc64_perm *perm, int extra_perm);
131 132
132#ifndef __ARCH_WANT_IPC_PARSE_VERSION 133#ifndef __ARCH_WANT_IPC_PARSE_VERSION