diff options
author | Serge E. Hallyn <serge@hallyn.com> | 2011-03-23 19:43:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 22:47:08 -0400 |
commit | b0e77598f87107001a00b8a4ece9c95e4254ccc4 (patch) | |
tree | 2738276570e4faa7c92a64521c192f04dca93801 | |
parent | b515498f5bb5f38fc0e390b4ff7d00b6077de127 (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>
-rw-r--r-- | include/linux/ipc_namespace.h | 7 | ||||
-rw-r--r-- | ipc/msg.c | 8 | ||||
-rw-r--r-- | ipc/namespace.c | 13 | ||||
-rw-r--r-- | ipc/sem.c | 10 | ||||
-rw-r--r-- | ipc/shm.c | 9 | ||||
-rw-r--r-- | ipc/util.c | 26 | ||||
-rw-r--r-- | ipc/util.h | 5 | ||||
-rw-r--r-- | kernel/futex.c | 11 | ||||
-rw-r--r-- | kernel/futex_compat.c | 11 | ||||
-rw-r--r-- | kernel/groups.c | 2 | ||||
-rw-r--r-- | kernel/nsproxy.c | 7 | ||||
-rw-r--r-- | kernel/sched.c | 9 | ||||
-rw-r--r-- | kernel/uid16.c | 2 |
13 files changed, 75 insertions, 45 deletions
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index d3c32dcec623..a6d1655f9607 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/idr.h> | 5 | #include <linux/idr.h> |
6 | #include <linux/rwsem.h> | 6 | #include <linux/rwsem.h> |
7 | #include <linux/notifier.h> | 7 | #include <linux/notifier.h> |
8 | #include <linux/nsproxy.h> | ||
8 | 9 | ||
9 | /* | 10 | /* |
10 | * ipc namespace events | 11 | * ipc namespace events |
@@ -93,7 +94,7 @@ static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; } | |||
93 | 94 | ||
94 | #if defined(CONFIG_IPC_NS) | 95 | #if defined(CONFIG_IPC_NS) |
95 | extern struct ipc_namespace *copy_ipcs(unsigned long flags, | 96 | extern struct ipc_namespace *copy_ipcs(unsigned long flags, |
96 | struct ipc_namespace *ns); | 97 | struct task_struct *tsk); |
97 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | 98 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) |
98 | { | 99 | { |
99 | if (ns) | 100 | if (ns) |
@@ -104,12 +105,12 @@ static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | |||
104 | extern void put_ipc_ns(struct ipc_namespace *ns); | 105 | extern void put_ipc_ns(struct ipc_namespace *ns); |
105 | #else | 106 | #else |
106 | static inline struct ipc_namespace *copy_ipcs(unsigned long flags, | 107 | static inline struct ipc_namespace *copy_ipcs(unsigned long flags, |
107 | struct ipc_namespace *ns) | 108 | struct task_struct *tsk) |
108 | { | 109 | { |
109 | if (flags & CLONE_NEWIPC) | 110 | if (flags & CLONE_NEWIPC) |
110 | return ERR_PTR(-EINVAL); | 111 | return ERR_PTR(-EINVAL); |
111 | 112 | ||
112 | return ns; | 113 | return tsk->nsproxy->ipc_ns; |
113 | } | 114 | } |
114 | 115 | ||
115 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | 116 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) |
@@ -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 | ||
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 | 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 | ||
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 | 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 | /* |
@@ -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); |
@@ -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 | */ |
332 | static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, | 332 | static 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 | ||
615 | int ipcperms (struct kern_ipc_perm *ipcp, short flag) | 619 | int 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 | */ |
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 | 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 *); | |||
103 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); | 103 | void 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 */ |
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 | /* 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); | |||
126 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); | 126 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); |
127 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); | 127 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); |
128 | void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); | 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 | 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 |
diff --git a/kernel/futex.c b/kernel/futex.c index bda415715382..6570c459f31c 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -2418,10 +2418,19 @@ SYSCALL_DEFINE3(get_robust_list, int, pid, | |||
2418 | goto err_unlock; | 2418 | goto err_unlock; |
2419 | ret = -EPERM; | 2419 | ret = -EPERM; |
2420 | pcred = __task_cred(p); | 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 | if (cred->euid != pcred->euid && | 2429 | if (cred->euid != pcred->euid && |
2422 | cred->euid != pcred->uid && | 2430 | cred->euid != pcred->uid && |
2423 | !capable(CAP_SYS_PTRACE)) | 2431 | !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE)) |
2424 | goto err_unlock; | 2432 | goto err_unlock; |
2433 | ok: | ||
2425 | head = p->robust_list; | 2434 | head = p->robust_list; |
2426 | rcu_read_unlock(); | 2435 | rcu_read_unlock(); |
2427 | } | 2436 | } |
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index a7934ac75e5b..5f9e689dc8f0 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c | |||
@@ -153,10 +153,19 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, | |||
153 | goto err_unlock; | 153 | goto err_unlock; |
154 | ret = -EPERM; | 154 | ret = -EPERM; |
155 | pcred = __task_cred(p); | 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 | if (cred->euid != pcred->euid && | 164 | if (cred->euid != pcred->euid && |
157 | cred->euid != pcred->uid && | 165 | cred->euid != pcred->uid && |
158 | !capable(CAP_SYS_PTRACE)) | 166 | !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE)) |
159 | goto err_unlock; | 167 | goto err_unlock; |
168 | ok: | ||
160 | head = p->compat_robust_list; | 169 | head = p->compat_robust_list; |
161 | rcu_read_unlock(); | 170 | rcu_read_unlock(); |
162 | } | 171 | } |
diff --git a/kernel/groups.c b/kernel/groups.c index 253dc0f35cf4..1cc476d52dd3 100644 --- a/kernel/groups.c +++ b/kernel/groups.c | |||
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) | |||
233 | struct group_info *group_info; | 233 | struct group_info *group_info; |
234 | int retval; | 234 | int retval; |
235 | 235 | ||
236 | if (!capable(CAP_SETGID)) | 236 | if (!nsown_capable(CAP_SETGID)) |
237 | return -EPERM; | 237 | return -EPERM; |
238 | if ((unsigned)gidsetsize > NGROUPS_MAX) | 238 | if ((unsigned)gidsetsize > NGROUPS_MAX) |
239 | return -EINVAL; | 239 | return -EINVAL; |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index ac8a56e90bf8..a05d191ffdd9 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -75,16 +75,11 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
75 | goto out_uts; | 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 | if (IS_ERR(new_nsp->ipc_ns)) { | 79 | if (IS_ERR(new_nsp->ipc_ns)) { |
80 | err = PTR_ERR(new_nsp->ipc_ns); | 80 | err = PTR_ERR(new_nsp->ipc_ns); |
81 | goto out_ipc; | 81 | goto out_ipc; |
82 | } | 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 | } | ||
88 | 83 | ||
89 | new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); | 84 | new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); |
90 | if (IS_ERR(new_nsp->pid_ns)) { | 85 | if (IS_ERR(new_nsp->pid_ns)) { |
diff --git a/kernel/sched.c b/kernel/sched.c index a172494a9a63..480adeb63f8f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -4892,8 +4892,11 @@ static bool check_same_owner(struct task_struct *p) | |||
4892 | 4892 | ||
4893 | rcu_read_lock(); | 4893 | rcu_read_lock(); |
4894 | pcred = __task_cred(p); | 4894 | pcred = __task_cred(p); |
4895 | match = (cred->euid == pcred->euid || | 4895 | if (cred->user->user_ns == pcred->user->user_ns) |
4896 | cred->euid == pcred->uid); | 4896 | match = (cred->euid == pcred->euid || |
4897 | cred->euid == pcred->uid); | ||
4898 | else | ||
4899 | match = false; | ||
4897 | rcu_read_unlock(); | 4900 | rcu_read_unlock(); |
4898 | return match; | 4901 | return match; |
4899 | } | 4902 | } |
@@ -5221,7 +5224,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) | |||
5221 | goto out_free_cpus_allowed; | 5224 | goto out_free_cpus_allowed; |
5222 | } | 5225 | } |
5223 | retval = -EPERM; | 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 | goto out_unlock; | 5228 | goto out_unlock; |
5226 | 5229 | ||
5227 | retval = security_task_setscheduler(p); | 5230 | retval = security_task_setscheduler(p); |
diff --git a/kernel/uid16.c b/kernel/uid16.c index 419209893d87..51c6e89e8619 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c | |||
@@ -189,7 +189,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) | |||
189 | struct group_info *group_info; | 189 | struct group_info *group_info; |
190 | int retval; | 190 | int retval; |
191 | 191 | ||
192 | if (!capable(CAP_SETGID)) | 192 | if (!nsown_capable(CAP_SETGID)) |
193 | return -EPERM; | 193 | return -EPERM; |
194 | if ((unsigned)gidsetsize > NGROUPS_MAX) | 194 | if ((unsigned)gidsetsize > NGROUPS_MAX) |
195 | return -EINVAL; | 195 | return -EINVAL; |