Commit b0e77598f87107001a00b8a4ece9c95e4254ccc4

Authored by Serge E. Hallyn
Committed by Linus Torvalds
1 parent b515498f5b

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>

Showing 13 changed files with 75 additions and 45 deletions Side-by-side Diff

include/linux/ipc_namespace.h
... ... @@ -5,6 +5,7 @@
5 5 #include <linux/idr.h>
6 6 #include <linux/rwsem.h>
7 7 #include <linux/notifier.h>
  8 +#include <linux/nsproxy.h>
8 9  
9 10 /*
10 11 * ipc namespace events
... ... @@ -93,7 +94,7 @@
93 94  
94 95 #if defined(CONFIG_IPC_NS)
95 96 extern struct ipc_namespace *copy_ipcs(unsigned long flags,
96   - struct ipc_namespace *ns);
  97 + struct task_struct *tsk);
97 98 static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
98 99 {
99 100 if (ns)
100 101  
... ... @@ -104,12 +105,12 @@
104 105 extern void put_ipc_ns(struct ipc_namespace *ns);
105 106 #else
106 107 static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
107   - struct ipc_namespace *ns)
  108 + struct task_struct *tsk)
108 109 {
109 110 if (flags & CLONE_NEWIPC)
110 111 return ERR_PTR(-EINVAL);
111 112  
112   - return ns;
  113 + return tsk->nsproxy->ipc_ns;
113 114 }
114 115  
115 116 static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
... ... @@ -421,7 +421,7 @@
421 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 425 &msqid64.msg_perm, msqid64.msg_qbytes);
426 426 if (IS_ERR(ipcp))
427 427 return PTR_ERR(ipcp);
... ... @@ -539,7 +539,7 @@
539 539 success_return = 0;
540 540 }
541 541 err = -EACCES;
542   - if (ipcperms(&msq->q_perm, S_IRUGO))
  542 + if (ipcperms(ns, &msq->q_perm, S_IRUGO))
543 543 goto out_unlock;
544 544  
545 545 err = security_msg_queue_msgctl(msq, cmd);
... ... @@ -664,7 +664,7 @@
664 664 struct msg_sender s;
665 665  
666 666 err = -EACCES;
667   - if (ipcperms(&msq->q_perm, S_IWUGO))
  667 + if (ipcperms(ns, &msq->q_perm, S_IWUGO))
668 668 goto out_unlock_free;
669 669  
670 670 err = security_msg_queue_msgsnd(msq, msg, msgflg);
... ... @@ -774,7 +774,7 @@
774 774 struct list_head *tmp;
775 775  
776 776 msg = ERR_PTR(-EACCES);
777   - if (ipcperms(&msq->q_perm, S_IRUGO))
  777 + if (ipcperms(ns, &msq->q_perm, S_IRUGO))
778 778 goto out_unlock;
779 779  
780 780 msg = ERR_PTR(-EAGAIN);
... ... @@ -15,7 +15,8 @@
15 15  
16 16 #include "util.h"
17 17  
18   -static struct ipc_namespace *create_ipc_ns(struct ipc_namespace *old_ns)
  18 +static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
  19 + struct ipc_namespace *old_ns)
19 20 {
20 21 struct ipc_namespace *ns;
21 22 int err;
22 23  
23 24  
24 25  
... ... @@ -44,17 +45,19 @@
44 45 ipcns_notify(IPCNS_CREATED);
45 46 register_ipcns_notifier(ns);
46 47  
47   - ns->user_ns = old_ns->user_ns;
48   - get_user_ns(ns->user_ns);
  48 + ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
49 49  
50 50 return ns;
51 51 }
52 52  
53   -struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
  53 +struct 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 58 if (!(flags & CLONE_NEWIPC))
56 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 /*
... ... @@ -817,7 +817,7 @@
817 817 }
818 818  
819 819 err = -EACCES;
820   - if (ipcperms (&sma->sem_perm, S_IRUGO))
  820 + if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
821 821 goto out_unlock;
822 822  
823 823 err = security_sem_semctl(sma, cmd);
... ... @@ -862,7 +862,8 @@
862 862 nsems = sma->sem_nsems;
863 863  
864 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 867 goto out_unlock;
867 868  
868 869 err = security_sem_semctl(sma, cmd);
... ... @@ -1047,7 +1048,8 @@
1047 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 1053 if (IS_ERR(ipcp))
1052 1054 return PTR_ERR(ipcp);
1053 1055  
... ... @@ -1386,7 +1388,7 @@
1386 1388 goto out_unlock_free;
1387 1389  
1388 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 1392 goto out_unlock_free;
1391 1393  
1392 1394 error = security_sem_semop(sma, sops, nsops, alter);
... ... @@ -623,7 +623,8 @@
623 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 628 if (IS_ERR(ipcp))
628 629 return PTR_ERR(ipcp);
629 630  
... ... @@ -737,7 +738,7 @@
737 738 result = 0;
738 739 }
739 740 err = -EACCES;
740   - if (ipcperms (&shp->shm_perm, S_IRUGO))
  741 + if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
741 742 goto out_unlock;
742 743 err = security_shm_shmctl(shp, cmd);
743 744 if (err)
... ... @@ -773,7 +774,7 @@
773 774  
774 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 778 uid_t euid = current_euid();
778 779 err = -EPERM;
779 780 if (euid != shp->shm_perm.uid &&
... ... @@ -888,7 +889,7 @@
888 889 }
889 890  
890 891 err = -EACCES;
891   - if (ipcperms(&shp->shm_perm, acc_mode))
  892 + if (ipcperms(ns, &shp->shm_perm, acc_mode))
892 893 goto out_unlock;
893 894  
894 895 err = security_shm_shmat(shp, shmaddr, shmflg);
... ... @@ -329,12 +329,14 @@
329 329 *
330 330 * It is called with ipc_ids.rw_mutex and ipcp->lock held.
331 331 */
332   -static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
333   - struct ipc_params *params)
  332 +static int ipc_check_perms(struct ipc_namespace *ns,
  333 + struct kern_ipc_perm *ipcp,
  334 + struct ipc_ops *ops,
  335 + struct ipc_params *params)
334 336 {
335 337 int err;
336 338  
337   - if (ipcperms(ipcp, params->flg))
  339 + if (ipcperms(ns, ipcp, params->flg))
338 340 err = -EACCES;
339 341 else {
340 342 err = ops->associate(ipcp, params->flg);
... ... @@ -396,7 +398,7 @@
396 398 * ipc_check_perms returns the IPC id on
397 399 * success
398 400 */
399   - err = ipc_check_perms(ipcp, ops, params);
  401 + err = ipc_check_perms(ns, ipcp, ops, params);
400 402 }
401 403 ipc_unlock(ipcp);
402 404 }
403 405  
... ... @@ -610,10 +612,12 @@
610 612 *
611 613 * Check user, group, other permissions for access
612 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  
615   -int ipcperms (struct kern_ipc_perm *ipcp, short flag)
616   -{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
  619 +int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
  620 +{
617 621 uid_t euid = current_euid();
618 622 int requested_mode, granted_mode;
619 623  
... ... @@ -627,7 +631,7 @@
627 631 granted_mode >>= 3;
628 632 /* is there some bit set in requested_mode but not in granted_mode? */
629 633 if ((requested_mode & ~granted_mode & 0007) &&
630   - !capable(CAP_IPC_OWNER))
  634 + !ns_capable(ns->user_ns, CAP_IPC_OWNER))
631 635 return -1;
632 636  
633 637 return security_ipc_permission(ipcp, flag);
... ... @@ -765,6 +769,7 @@
765 769  
766 770 /**
767 771 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
  772 + * @ids: the ipc namespace
768 773 * @ids: the table of ids where to look for the ipc
769 774 * @id: the id of the ipc to retrieve
770 775 * @cmd: the cmd to check
... ... @@ -779,7 +784,8 @@
779 784 * - returns the ipc with both ipc and rw_mutex locks held in case of success
780 785 * or an err-code without any lock held otherwise.
781 786 */
782   -struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
  787 +struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
  788 + struct ipc_ids *ids, int id, int cmd,
783 789 struct ipc64_perm *perm, int extra_perm)
784 790 {
785 791 struct kern_ipc_perm *ipcp;
... ... @@ -799,8 +805,8 @@
799 805 perm->gid, perm->mode);
800 806  
801 807 euid = current_euid();
802   - if (euid == ipcp->cuid ||
803   - euid == ipcp->uid || capable(CAP_SYS_ADMIN))
  808 + if (euid == ipcp->cuid || euid == ipcp->uid ||
  809 + ns_capable(ns->user_ns, CAP_SYS_ADMIN))
804 810 return ipcp;
805 811  
806 812 err = -EPERM;
... ... @@ -103,7 +103,7 @@
103 103 void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
104 104  
105 105 /* must be called with ipcp locked */
106   -int ipcperms(struct kern_ipc_perm *ipcp, short flg);
  106 +int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
107 107  
108 108 /* for rare, potentially huge allocations.
109 109 * both function can sleep
... ... @@ -126,7 +126,8 @@
126 126 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
127 127 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
128 128 void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
129   -struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
  129 +struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
  130 + struct ipc_ids *ids, int id, int cmd,
130 131 struct ipc64_perm *perm, int extra_perm);
131 132  
132 133 #ifndef __ARCH_WANT_IPC_PARSE_VERSION
... ... @@ -2418,10 +2418,19 @@
2418 2418 goto err_unlock;
2419 2419 ret = -EPERM;
2420 2420 pcred = __task_cred(p);
  2421 + /* If victim is in different user_ns, then uids are not
  2422 + comparable, so we must have CAP_SYS_PTRACE */
  2423 + if (cred->user->user_ns != pcred->user->user_ns) {
  2424 + if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
  2425 + goto err_unlock;
  2426 + goto ok;
  2427 + }
  2428 + /* If victim is in same user_ns, then uids are comparable */
2421 2429 if (cred->euid != pcred->euid &&
2422 2430 cred->euid != pcred->uid &&
2423   - !capable(CAP_SYS_PTRACE))
  2431 + !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
2424 2432 goto err_unlock;
  2433 +ok:
2425 2434 head = p->robust_list;
2426 2435 rcu_read_unlock();
2427 2436 }
kernel/futex_compat.c
... ... @@ -153,10 +153,19 @@
153 153 goto err_unlock;
154 154 ret = -EPERM;
155 155 pcred = __task_cred(p);
  156 + /* If victim is in different user_ns, then uids are not
  157 + comparable, so we must have CAP_SYS_PTRACE */
  158 + if (cred->user->user_ns != pcred->user->user_ns) {
  159 + if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
  160 + goto err_unlock;
  161 + goto ok;
  162 + }
  163 + /* If victim is in same user_ns, then uids are comparable */
156 164 if (cred->euid != pcred->euid &&
157 165 cred->euid != pcred->uid &&
158   - !capable(CAP_SYS_PTRACE))
  166 + !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
159 167 goto err_unlock;
  168 +ok:
160 169 head = p->compat_robust_list;
161 170 rcu_read_unlock();
162 171 }
... ... @@ -233,7 +233,7 @@
233 233 struct group_info *group_info;
234 234 int retval;
235 235  
236   - if (!capable(CAP_SETGID))
  236 + if (!nsown_capable(CAP_SETGID))
237 237 return -EPERM;
238 238 if ((unsigned)gidsetsize > NGROUPS_MAX)
239 239 return -EINVAL;
... ... @@ -75,15 +75,10 @@
75 75 goto out_uts;
76 76 }
77 77  
78   - new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
  78 + new_nsp->ipc_ns = copy_ipcs(flags, tsk);
79 79 if (IS_ERR(new_nsp->ipc_ns)) {
80 80 err = PTR_ERR(new_nsp->ipc_ns);
81 81 goto out_ipc;
82   - }
83   - if (new_nsp->ipc_ns != tsk->nsproxy->ipc_ns) {
84   - put_user_ns(new_nsp->ipc_ns->user_ns);
85   - new_nsp->ipc_ns->user_ns = task_cred_xxx(tsk, user)->user_ns;
86   - get_user_ns(new_nsp->ipc_ns->user_ns);
87 82 }
88 83  
89 84 new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk));
... ... @@ -4892,8 +4892,11 @@
4892 4892  
4893 4893 rcu_read_lock();
4894 4894 pcred = __task_cred(p);
4895   - match = (cred->euid == pcred->euid ||
4896   - cred->euid == pcred->uid);
  4895 + if (cred->user->user_ns == pcred->user->user_ns)
  4896 + match = (cred->euid == pcred->euid ||
  4897 + cred->euid == pcred->uid);
  4898 + else
  4899 + match = false;
4897 4900 rcu_read_unlock();
4898 4901 return match;
4899 4902 }
... ... @@ -5221,7 +5224,7 @@
5221 5224 goto out_free_cpus_allowed;
5222 5225 }
5223 5226 retval = -EPERM;
5224   - if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
  5227 + if (!check_same_owner(p) && !task_ns_capable(p, CAP_SYS_NICE))
5225 5228 goto out_unlock;
5226 5229  
5227 5230 retval = security_task_setscheduler(p);
... ... @@ -189,7 +189,7 @@
189 189 struct group_info *group_info;
190 190 int retval;
191 191  
192   - if (!capable(CAP_SETGID))
  192 + if (!nsown_capable(CAP_SETGID))
193 193 return -EPERM;
194 194 if ((unsigned)gidsetsize > NGROUPS_MAX)
195 195 return -EINVAL;