aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 14:11:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 14:11:09 -0400
commit437589a74b6a590d175f86cf9f7b2efcee7765e7 (patch)
tree37bf8635b1356d80ef002b00e84f3faf3d555a63 /ipc
parent68d47a137c3bef754923bccf73fb639c9b0bbd5e (diff)
parent72235465864d84cedb2d9f26f8e1de824ee20339 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace changes from Eric Biederman: "This is a mostly modest set of changes to enable basic user namespace support. This allows the code to code to compile with user namespaces enabled and removes the assumption there is only the initial user namespace. Everything is converted except for the most complex of the filesystems: autofs4, 9p, afs, ceph, cifs, coda, fuse, gfs2, ncpfs, nfs, ocfs2 and xfs as those patches need a bit more review. The strategy is to push kuid_t and kgid_t values are far down into subsystems and filesystems as reasonable. Leaving the make_kuid and from_kuid operations to happen at the edge of userspace, as the values come off the disk, and as the values come in from the network. Letting compile type incompatible compile errors (present when user namespaces are enabled) guide me to find the issues. The most tricky areas have been the places where we had an implicit union of uid and gid values and were storing them in an unsigned int. Those places were converted into explicit unions. I made certain to handle those places with simple trivial patches. Out of that work I discovered we have generic interfaces for storing quota by projid. I had never heard of the project identifiers before. Adding full user namespace support for project identifiers accounts for most of the code size growth in my git tree. Ultimately there will be work to relax privlige checks from "capable(FOO)" to "ns_capable(user_ns, FOO)" where it is safe allowing root in a user names to do those things that today we only forbid to non-root users because it will confuse suid root applications. While I was pushing kuid_t and kgid_t changes deep into the audit code I made a few other cleanups. I capitalized on the fact we process netlink messages in the context of the message sender. I removed usage of NETLINK_CRED, and started directly using current->tty. Some of these patches have also made it into maintainer trees, with no problems from identical code from different trees showing up in linux-next. After reading through all of this code I feel like I might be able to win a game of kernel trivial pursuit." Fix up some fairly trivial conflicts in netfilter uid/git logging code. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (107 commits) userns: Convert the ufs filesystem to use kuid/kgid where appropriate userns: Convert the udf filesystem to use kuid/kgid where appropriate userns: Convert ubifs to use kuid/kgid userns: Convert squashfs to use kuid/kgid where appropriate userns: Convert reiserfs to use kuid and kgid where appropriate userns: Convert jfs to use kuid/kgid where appropriate userns: Convert jffs2 to use kuid and kgid where appropriate userns: Convert hpfs to use kuid and kgid where appropriate userns: Convert btrfs to use kuid/kgid where appropriate userns: Convert bfs to use kuid/kgid where appropriate userns: Convert affs to use kuid/kgid wherwe appropriate userns: On alpha modify linux_to_osf_stat to use convert from kuids and kgids userns: On ia64 deal with current_uid and current_gid being kuid and kgid userns: On ppc convert current_uid from a kuid before printing. userns: Convert s390 getting uid and gid system calls to use kuid and kgid userns: Convert s390 hypfs to use kuid and kgid where appropriate userns: Convert binder ipc to use kuids userns: Teach security_path_chown to take kuids and kgids userns: Add user namespace support to IMA userns: Convert EVM to deal with kuids and kgids in it's hmac computation ...
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c14
-rw-r--r--ipc/sem.c13
-rw-r--r--ipc/shm.c19
-rw-r--r--ipc/util.c35
-rw-r--r--ipc/util.h2
5 files changed, 50 insertions, 33 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 7385de25788a..a71af5a65abf 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -443,9 +443,12 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
443 goto out_unlock; 443 goto out_unlock;
444 } 444 }
445 445
446 err = ipc_update_perm(&msqid64.msg_perm, ipcp);
447 if (err)
448 goto out_unlock;
449
446 msq->q_qbytes = msqid64.msg_qbytes; 450 msq->q_qbytes = msqid64.msg_qbytes;
447 451
448 ipc_update_perm(&msqid64.msg_perm, ipcp);
449 msq->q_ctime = get_seconds(); 452 msq->q_ctime = get_seconds();
450 /* sleeping receivers might be excluded by 453 /* sleeping receivers might be excluded by
451 * stricter permissions. 454 * stricter permissions.
@@ -922,6 +925,7 @@ out:
922#ifdef CONFIG_PROC_FS 925#ifdef CONFIG_PROC_FS
923static int sysvipc_msg_proc_show(struct seq_file *s, void *it) 926static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
924{ 927{
928 struct user_namespace *user_ns = seq_user_ns(s);
925 struct msg_queue *msq = it; 929 struct msg_queue *msq = it;
926 930
927 return seq_printf(s, 931 return seq_printf(s,
@@ -933,10 +937,10 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
933 msq->q_qnum, 937 msq->q_qnum,
934 msq->q_lspid, 938 msq->q_lspid,
935 msq->q_lrpid, 939 msq->q_lrpid,
936 msq->q_perm.uid, 940 from_kuid_munged(user_ns, msq->q_perm.uid),
937 msq->q_perm.gid, 941 from_kgid_munged(user_ns, msq->q_perm.gid),
938 msq->q_perm.cuid, 942 from_kuid_munged(user_ns, msq->q_perm.cuid),
939 msq->q_perm.cgid, 943 from_kgid_munged(user_ns, msq->q_perm.cgid),
940 msq->q_stime, 944 msq->q_stime,
941 msq->q_rtime, 945 msq->q_rtime,
942 msq->q_ctime); 946 msq->q_ctime);
diff --git a/ipc/sem.c b/ipc/sem.c
index 5215a81420df..58d31f1c1eb5 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1104,7 +1104,9 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1104 freeary(ns, ipcp); 1104 freeary(ns, ipcp);
1105 goto out_up; 1105 goto out_up;
1106 case IPC_SET: 1106 case IPC_SET:
1107 ipc_update_perm(&semid64.sem_perm, ipcp); 1107 err = ipc_update_perm(&semid64.sem_perm, ipcp);
1108 if (err)
1109 goto out_unlock;
1108 sma->sem_ctime = get_seconds(); 1110 sma->sem_ctime = get_seconds();
1109 break; 1111 break;
1110 default: 1112 default:
@@ -1677,6 +1679,7 @@ void exit_sem(struct task_struct *tsk)
1677#ifdef CONFIG_PROC_FS 1679#ifdef CONFIG_PROC_FS
1678static int sysvipc_sem_proc_show(struct seq_file *s, void *it) 1680static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
1679{ 1681{
1682 struct user_namespace *user_ns = seq_user_ns(s);
1680 struct sem_array *sma = it; 1683 struct sem_array *sma = it;
1681 1684
1682 return seq_printf(s, 1685 return seq_printf(s,
@@ -1685,10 +1688,10 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
1685 sma->sem_perm.id, 1688 sma->sem_perm.id,
1686 sma->sem_perm.mode, 1689 sma->sem_perm.mode,
1687 sma->sem_nsems, 1690 sma->sem_nsems,
1688 sma->sem_perm.uid, 1691 from_kuid_munged(user_ns, sma->sem_perm.uid),
1689 sma->sem_perm.gid, 1692 from_kgid_munged(user_ns, sma->sem_perm.gid),
1690 sma->sem_perm.cuid, 1693 from_kuid_munged(user_ns, sma->sem_perm.cuid),
1691 sma->sem_perm.cgid, 1694 from_kgid_munged(user_ns, sma->sem_perm.cgid),
1692 sma->sem_otime, 1695 sma->sem_otime,
1693 sma->sem_ctime); 1696 sma->sem_ctime);
1694} 1697}
diff --git a/ipc/shm.c b/ipc/shm.c
index 00faa05cf72a..dff40c9f73c9 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -758,7 +758,9 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
758 do_shm_rmid(ns, ipcp); 758 do_shm_rmid(ns, ipcp);
759 goto out_up; 759 goto out_up;
760 case IPC_SET: 760 case IPC_SET:
761 ipc_update_perm(&shmid64.shm_perm, ipcp); 761 err = ipc_update_perm(&shmid64.shm_perm, ipcp);
762 if (err)
763 goto out_unlock;
762 shp->shm_ctim = get_seconds(); 764 shp->shm_ctim = get_seconds();
763 break; 765 break;
764 default: 766 default:
@@ -893,10 +895,10 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
893 audit_ipc_obj(&(shp->shm_perm)); 895 audit_ipc_obj(&(shp->shm_perm));
894 896
895 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { 897 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
896 uid_t euid = current_euid(); 898 kuid_t euid = current_euid();
897 err = -EPERM; 899 err = -EPERM;
898 if (euid != shp->shm_perm.uid && 900 if (!uid_eq(euid, shp->shm_perm.uid) &&
899 euid != shp->shm_perm.cuid) 901 !uid_eq(euid, shp->shm_perm.cuid))
900 goto out_unlock; 902 goto out_unlock;
901 if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) 903 if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
902 goto out_unlock; 904 goto out_unlock;
@@ -1220,6 +1222,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1220#ifdef CONFIG_PROC_FS 1222#ifdef CONFIG_PROC_FS
1221static int sysvipc_shm_proc_show(struct seq_file *s, void *it) 1223static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1222{ 1224{
1225 struct user_namespace *user_ns = seq_user_ns(s);
1223 struct shmid_kernel *shp = it; 1226 struct shmid_kernel *shp = it;
1224 unsigned long rss = 0, swp = 0; 1227 unsigned long rss = 0, swp = 0;
1225 1228
@@ -1242,10 +1245,10 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1242 shp->shm_cprid, 1245 shp->shm_cprid,
1243 shp->shm_lprid, 1246 shp->shm_lprid,
1244 shp->shm_nattch, 1247 shp->shm_nattch,
1245 shp->shm_perm.uid, 1248 from_kuid_munged(user_ns, shp->shm_perm.uid),
1246 shp->shm_perm.gid, 1249 from_kgid_munged(user_ns, shp->shm_perm.gid),
1247 shp->shm_perm.cuid, 1250 from_kuid_munged(user_ns, shp->shm_perm.cuid),
1248 shp->shm_perm.cgid, 1251 from_kgid_munged(user_ns, shp->shm_perm.cgid),
1249 shp->shm_atim, 1252 shp->shm_atim,
1250 shp->shm_dtim, 1253 shp->shm_dtim,
1251 shp->shm_ctim, 1254 shp->shm_ctim,
diff --git a/ipc/util.c b/ipc/util.c
index eb07fd356f27..72fd0785ac94 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -249,8 +249,8 @@ int ipc_get_maxid(struct ipc_ids *ids)
249 249
250int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) 250int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
251{ 251{
252 uid_t euid; 252 kuid_t euid;
253 gid_t egid; 253 kgid_t egid;
254 int id, err; 254 int id, err;
255 255
256 if (size > IPCMNI) 256 if (size > IPCMNI)
@@ -606,14 +606,14 @@ void ipc_rcu_putref(void *ptr)
606 606
607int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) 607int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
608{ 608{
609 uid_t euid = current_euid(); 609 kuid_t euid = current_euid();
610 int requested_mode, granted_mode; 610 int requested_mode, granted_mode;
611 611
612 audit_ipc_obj(ipcp); 612 audit_ipc_obj(ipcp);
613 requested_mode = (flag >> 6) | (flag >> 3) | flag; 613 requested_mode = (flag >> 6) | (flag >> 3) | flag;
614 granted_mode = ipcp->mode; 614 granted_mode = ipcp->mode;
615 if (euid == ipcp->cuid || 615 if (uid_eq(euid, ipcp->cuid) ||
616 euid == ipcp->uid) 616 uid_eq(euid, ipcp->uid))
617 granted_mode >>= 6; 617 granted_mode >>= 6;
618 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) 618 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
619 granted_mode >>= 3; 619 granted_mode >>= 3;
@@ -643,10 +643,10 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
643void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) 643void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
644{ 644{
645 out->key = in->key; 645 out->key = in->key;
646 out->uid = in->uid; 646 out->uid = from_kuid_munged(current_user_ns(), in->uid);
647 out->gid = in->gid; 647 out->gid = from_kgid_munged(current_user_ns(), in->gid);
648 out->cuid = in->cuid; 648 out->cuid = from_kuid_munged(current_user_ns(), in->cuid);
649 out->cgid = in->cgid; 649 out->cgid = from_kgid_munged(current_user_ns(), in->cgid);
650 out->mode = in->mode; 650 out->mode = in->mode;
651 out->seq = in->seq; 651 out->seq = in->seq;
652} 652}
@@ -747,12 +747,19 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
747 * @in: the permission given as input. 747 * @in: the permission given as input.
748 * @out: the permission of the ipc to set. 748 * @out: the permission of the ipc to set.
749 */ 749 */
750void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) 750int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
751{ 751{
752 out->uid = in->uid; 752 kuid_t uid = make_kuid(current_user_ns(), in->uid);
753 out->gid = in->gid; 753 kgid_t gid = make_kgid(current_user_ns(), in->gid);
754 if (!uid_valid(uid) || !gid_valid(gid))
755 return -EINVAL;
756
757 out->uid = uid;
758 out->gid = gid;
754 out->mode = (out->mode & ~S_IRWXUGO) 759 out->mode = (out->mode & ~S_IRWXUGO)
755 | (in->mode & S_IRWXUGO); 760 | (in->mode & S_IRWXUGO);
761
762 return 0;
756} 763}
757 764
758/** 765/**
@@ -777,7 +784,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
777 struct ipc64_perm *perm, int extra_perm) 784 struct ipc64_perm *perm, int extra_perm)
778{ 785{
779 struct kern_ipc_perm *ipcp; 786 struct kern_ipc_perm *ipcp;
780 uid_t euid; 787 kuid_t euid;
781 int err; 788 int err;
782 789
783 down_write(&ids->rw_mutex); 790 down_write(&ids->rw_mutex);
@@ -793,7 +800,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
793 perm->gid, perm->mode); 800 perm->gid, perm->mode);
794 801
795 euid = current_euid(); 802 euid = current_euid();
796 if (euid == ipcp->cuid || euid == ipcp->uid || 803 if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
797 ns_capable(ns->user_ns, CAP_SYS_ADMIN)) 804 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
798 return ipcp; 805 return ipcp;
799 806
diff --git a/ipc/util.h b/ipc/util.h
index 850ef3e962cb..c8fe2f7631e9 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -125,7 +125,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
125 125
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); 128int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns, 129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
130 struct ipc_ids *ids, int id, int cmd, 130 struct ipc_ids *ids, int id, int cmd,
131 struct ipc64_perm *perm, int extra_perm); 131 struct ipc64_perm *perm, int extra_perm);