aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorEric W. Biederman2012-02-07 18:54:11 -0600
committerEric W. Biederman2012-09-07 00:17:20 -0500
commit1efdb69b0bb41dec8ee3e2cac0a0f167837d0919 (patch)
treea9eb64c44d773e7b4fead20a7bfa9a354abf3bfa /ipc
parent9582d90196aa879e6acf866f02a1adead08707b5 (diff)
downloadkernel-common-1efdb69b0bb41dec8ee3e2cac0a0f167837d0919.tar.gz
kernel-common-1efdb69b0bb41dec8ee3e2cac0a0f167837d0919.tar.xz
kernel-common-1efdb69b0bb41dec8ee3e2cac0a0f167837d0919.zip
userns: Convert ipc to use kuid and kgid where appropriate
- Store the ipc owner and creator with a kuid - Store the ipc group and the crators group with a kgid. - Add error handling to ipc_update_perms, allowing it to fail if the uids and gids can not be converted to kuids or kgids. - Modify the proc files to display the ipc creator and owner in the user namespace of the opener of the proc file. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
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 7385de25788..a71af5a65ab 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 5215a81420d..58d31f1c1eb 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 00faa05cf72..dff40c9f73c 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 eb07fd356f2..72fd0785ac9 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 850ef3e962c..c8fe2f7631e 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);