aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-07-08 22:52:47 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-07-15 20:46:42 -0400
commit553f770ef71b27ee053bd241bef0998a15f43467 (patch)
treeb23887b5e7d6ce16c9bc0627f26748e500ad5177 /ipc
parent9ba720c18622b250c0abeccbcea1b03531a92277 (diff)
ipc: move compat shmctl to native
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/compat.c233
-rw-r--r--ipc/shm.c209
-rw-r--r--ipc/util.h24
3 files changed, 231 insertions, 235 deletions
diff --git a/ipc/compat.c b/ipc/compat.c
index 9b3c85f8a538..fbfd6fb0a68d 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -39,16 +39,6 @@ struct compat_msgbuf {
39 char mtext[1]; 39 char mtext[1];
40}; 40};
41 41
42struct compat_ipc_perm {
43 key_t key;
44 __compat_uid_t uid;
45 __compat_gid_t gid;
46 __compat_uid_t cuid;
47 __compat_gid_t cgid;
48 compat_mode_t mode;
49 unsigned short seq;
50};
51
52struct compat_semid_ds { 42struct compat_semid_ds {
53 struct compat_ipc_perm sem_perm; 43 struct compat_ipc_perm sem_perm;
54 compat_time_t sem_otime; 44 compat_time_t sem_otime;
@@ -76,44 +66,12 @@ struct compat_msqid_ds {
76 compat_ipc_pid_t msg_lrpid; 66 compat_ipc_pid_t msg_lrpid;
77}; 67};
78 68
79struct compat_shmid_ds {
80 struct compat_ipc_perm shm_perm;
81 int shm_segsz;
82 compat_time_t shm_atime;
83 compat_time_t shm_dtime;
84 compat_time_t shm_ctime;
85 compat_ipc_pid_t shm_cpid;
86 compat_ipc_pid_t shm_lpid;
87 unsigned short shm_nattch;
88 unsigned short shm_unused;
89 compat_uptr_t shm_unused2;
90 compat_uptr_t shm_unused3;
91};
92
93struct compat_ipc_kludge { 69struct compat_ipc_kludge {
94 compat_uptr_t msgp; 70 compat_uptr_t msgp;
95 compat_long_t msgtyp; 71 compat_long_t msgtyp;
96}; 72};
97 73
98struct compat_shminfo64 { 74static inline int __compat_ipc_parse_version(int *cmd)
99 compat_ulong_t shmmax;
100 compat_ulong_t shmmin;
101 compat_ulong_t shmmni;
102 compat_ulong_t shmseg;
103 compat_ulong_t shmall;
104 compat_ulong_t __unused1;
105 compat_ulong_t __unused2;
106 compat_ulong_t __unused3;
107 compat_ulong_t __unused4;
108};
109
110struct compat_shm_info {
111 compat_int_t used_ids;
112 compat_ulong_t shm_tot, shm_rss, shm_swp;
113 compat_ulong_t swap_attempts, swap_successes;
114};
115
116static inline int compat_ipc_parse_version(int *cmd)
117{ 75{
118#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION 76#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
119 int version = *cmd & IPC_64; 77 int version = *cmd & IPC_64;
@@ -241,7 +199,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
241 int err, err2; 199 int err, err2;
242 struct semid64_ds sem64; 200 struct semid64_ds sem64;
243 struct semid64_ds __user *up64; 201 struct semid64_ds __user *up64;
244 int version = compat_ipc_parse_version(&third); 202 int version = __compat_ipc_parse_version(&third);
245 203
246 memset(&sem64, 0, sizeof(sem64)); 204 memset(&sem64, 0, sizeof(sem64));
247 205
@@ -499,7 +457,7 @@ COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
499{ 457{
500 int err, err2; 458 int err, err2;
501 struct msqid64_ds m64; 459 struct msqid64_ds m64;
502 int version = compat_ipc_parse_version(&second); 460 int version = __compat_ipc_parse_version(&second);
503 void __user *p; 461 void __user *p;
504 462
505 memset(&m64, 0, sizeof(m64)); 463 memset(&m64, 0, sizeof(m64));
@@ -561,191 +519,6 @@ COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
561 return (long)ret; 519 return (long)ret;
562} 520}
563 521
564static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
565 struct compat_shmid64_ds __user *up64)
566{
567 if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
568 return -EFAULT;
569 return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
570}
571
572static inline int get_compat_shmid_ds(struct shmid64_ds *s,
573 struct compat_shmid_ds __user *up)
574{
575 if (!access_ok(VERIFY_READ, up, sizeof(*up)))
576 return -EFAULT;
577 return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
578}
579
580static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
581 struct compat_shmid64_ds __user *up64)
582{
583 int err;
584
585 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
586 return -EFAULT;
587 err = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
588 err |= __put_user(sem64->shm_atime, &up64->shm_atime);
589 err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
590 err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
591 err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
592 err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
593 err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
594 err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
595 return err;
596}
597
598static inline int put_compat_shmid_ds(struct shmid64_ds *s,
599 struct compat_shmid_ds __user *up)
600{
601 int err;
602
603 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
604 return -EFAULT;
605 err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
606 err |= __put_user(s->shm_atime, &up->shm_atime);
607 err |= __put_user(s->shm_dtime, &up->shm_dtime);
608 err |= __put_user(s->shm_ctime, &up->shm_ctime);
609 err |= __put_user(s->shm_segsz, &up->shm_segsz);
610 err |= __put_user(s->shm_nattch, &up->shm_nattch);
611 err |= __put_user(s->shm_cpid, &up->shm_cpid);
612 err |= __put_user(s->shm_lpid, &up->shm_lpid);
613 return err;
614}
615
616static inline int put_compat_shminfo64(struct shminfo64 *smi,
617 struct compat_shminfo64 __user *up64)
618{
619 int err;
620
621 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
622 return -EFAULT;
623 if (smi->shmmax > INT_MAX)
624 smi->shmmax = INT_MAX;
625 err = __put_user(smi->shmmax, &up64->shmmax);
626 err |= __put_user(smi->shmmin, &up64->shmmin);
627 err |= __put_user(smi->shmmni, &up64->shmmni);
628 err |= __put_user(smi->shmseg, &up64->shmseg);
629 err |= __put_user(smi->shmall, &up64->shmall);
630 return err;
631}
632
633static inline int put_compat_shminfo(struct shminfo64 *smi,
634 struct shminfo __user *up)
635{
636 int err;
637
638 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
639 return -EFAULT;
640 if (smi->shmmax > INT_MAX)
641 smi->shmmax = INT_MAX;
642 err = __put_user(smi->shmmax, &up->shmmax);
643 err |= __put_user(smi->shmmin, &up->shmmin);
644 err |= __put_user(smi->shmmni, &up->shmmni);
645 err |= __put_user(smi->shmseg, &up->shmseg);
646 err |= __put_user(smi->shmall, &up->shmall);
647 return err;
648}
649
650static inline int put_compat_shm_info(struct shm_info __user *ip,
651 struct compat_shm_info __user *uip)
652{
653 int err;
654 struct shm_info si;
655
656 if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
657 copy_from_user(&si, ip, sizeof(si)))
658 return -EFAULT;
659 err = __put_user(si.used_ids, &uip->used_ids);
660 err |= __put_user(si.shm_tot, &uip->shm_tot);
661 err |= __put_user(si.shm_rss, &uip->shm_rss);
662 err |= __put_user(si.shm_swp, &uip->shm_swp);
663 err |= __put_user(si.swap_attempts, &uip->swap_attempts);
664 err |= __put_user(si.swap_successes, &uip->swap_successes);
665 return err;
666}
667
668COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
669{
670 void __user *p;
671 struct shmid64_ds sem64;
672 struct shminfo64 smi;
673 int err, err2;
674 int version = compat_ipc_parse_version(&second);
675
676 memset(&sem64, 0, sizeof(sem64));
677
678 switch (second & (~IPC_64)) {
679 case IPC_RMID:
680 case SHM_LOCK:
681 case SHM_UNLOCK:
682 err = sys_shmctl(first, second, uptr);
683 break;
684
685 case IPC_INFO:
686 p = compat_alloc_user_space(sizeof(smi));
687 err = sys_shmctl(first, second, p);
688 if (err < 0)
689 break;
690 if (copy_from_user(&smi, p, sizeof(smi)))
691 err2 = -EFAULT;
692 else if (version == IPC_64)
693 err2 = put_compat_shminfo64(&smi, uptr);
694 else
695 err2 = put_compat_shminfo(&smi, uptr);
696 if (err2)
697 err = -EFAULT;
698 break;
699
700
701 case IPC_SET:
702 if (version == IPC_64)
703 err = get_compat_shmid64_ds(&sem64, uptr);
704 else
705 err = get_compat_shmid_ds(&sem64, uptr);
706
707 if (err)
708 break;
709 p = compat_alloc_user_space(sizeof(sem64));
710 if (copy_to_user(p, &sem64, sizeof(sem64)))
711 err = -EFAULT;
712 else
713 err = sys_shmctl(first, second, p);
714 break;
715
716 case IPC_STAT:
717 case SHM_STAT:
718 p = compat_alloc_user_space(sizeof(sem64));
719 err = sys_shmctl(first, second, p);
720 if (err < 0)
721 break;
722 if (copy_from_user(&sem64, p, sizeof(sem64)))
723 err2 = -EFAULT;
724 else if (version == IPC_64)
725 err2 = put_compat_shmid64_ds(&sem64, uptr);
726 else
727 err2 = put_compat_shmid_ds(&sem64, uptr);
728 if (err2)
729 err = -EFAULT;
730 break;
731
732 case SHM_INFO:
733 p = compat_alloc_user_space(sizeof(struct shm_info));
734 err = sys_shmctl(first, second, p);
735 if (err < 0)
736 break;
737 err2 = put_compat_shm_info(p, uptr);
738 if (err2)
739 err = -EFAULT;
740 break;
741
742 default:
743 err = -EINVAL;
744 break;
745 }
746 return err;
747}
748
749COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, 522COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
750 unsigned, nsops, 523 unsigned, nsops,
751 const struct compat_timespec __user *, timeout) 524 const struct compat_timespec __user *, timeout)
diff --git a/ipc/shm.c b/ipc/shm.c
index b4073c08d0e8..87334ee3acb3 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1030,7 +1030,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
1030{ 1030{
1031 int err, version; 1031 int err, version;
1032 struct ipc_namespace *ns; 1032 struct ipc_namespace *ns;
1033 struct shmid64_ds tbuf; 1033 struct shmid64_ds sem64;
1034 1034
1035 if (cmd < 0 || shmid < 0) 1035 if (cmd < 0 || shmid < 0)
1036 return -EINVAL; 1036 return -EINVAL;
@@ -1059,18 +1059,19 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
1059 } 1059 }
1060 case SHM_STAT: 1060 case SHM_STAT:
1061 case IPC_STAT: { 1061 case IPC_STAT: {
1062 err = shmctl_stat(ns, shmid, cmd, &tbuf); 1062 err = shmctl_stat(ns, shmid, cmd, &sem64);
1063 if (err < 0) 1063 if (err < 0)
1064 return err; 1064 return err;
1065 if (copy_shmid_to_user(buf, &tbuf, version)) 1065 if (copy_shmid_to_user(buf, &sem64, version))
1066 err = -EFAULT; 1066 err = -EFAULT;
1067 return err; 1067 return err;
1068 } 1068 }
1069 case IPC_SET: 1069 case IPC_SET:
1070 if (copy_shmid_from_user(&tbuf, buf, version)) 1070 if (copy_shmid_from_user(&sem64, buf, version))
1071 return -EFAULT; 1071 return -EFAULT;
1072 /* fallthru */
1072 case IPC_RMID: 1073 case IPC_RMID:
1073 return shmctl_down(ns, shmid, cmd, &tbuf); 1074 return shmctl_down(ns, shmid, cmd, &sem64);
1074 case SHM_LOCK: 1075 case SHM_LOCK:
1075 case SHM_UNLOCK: 1076 case SHM_UNLOCK:
1076 return shmctl_do_lock(ns, shmid, cmd); 1077 return shmctl_do_lock(ns, shmid, cmd);
@@ -1079,6 +1080,204 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
1079 } 1080 }
1080} 1081}
1081 1082
1083#ifdef CONFIG_COMPAT
1084
1085struct compat_shmid_ds {
1086 struct compat_ipc_perm shm_perm;
1087 int shm_segsz;
1088 compat_time_t shm_atime;
1089 compat_time_t shm_dtime;
1090 compat_time_t shm_ctime;
1091 compat_ipc_pid_t shm_cpid;
1092 compat_ipc_pid_t shm_lpid;
1093 unsigned short shm_nattch;
1094 unsigned short shm_unused;
1095 compat_uptr_t shm_unused2;
1096 compat_uptr_t shm_unused3;
1097};
1098
1099struct compat_shminfo64 {
1100 compat_ulong_t shmmax;
1101 compat_ulong_t shmmin;
1102 compat_ulong_t shmmni;
1103 compat_ulong_t shmseg;
1104 compat_ulong_t shmall;
1105 compat_ulong_t __unused1;
1106 compat_ulong_t __unused2;
1107 compat_ulong_t __unused3;
1108 compat_ulong_t __unused4;
1109};
1110
1111struct compat_shm_info {
1112 compat_int_t used_ids;
1113 compat_ulong_t shm_tot, shm_rss, shm_swp;
1114 compat_ulong_t swap_attempts, swap_successes;
1115};
1116
1117static int copy_compat_shminfo_to_user(void __user *buf, struct shminfo64 *in,
1118 int version)
1119{
1120 if (in->shmmax > INT_MAX)
1121 in->shmmax = INT_MAX;
1122 if (version == IPC_64) {
1123 struct compat_shminfo64 info;
1124 memset(&info, 0, sizeof(info));
1125 info.shmmax = in->shmmax;
1126 info.shmmin = in->shmmin;
1127 info.shmmni = in->shmmni;
1128 info.shmseg = in->shmseg;
1129 info.shmall = in->shmall;
1130 return copy_to_user(buf, &info, sizeof(info));
1131 } else {
1132 struct shminfo info;
1133 memset(&info, 0, sizeof(info));
1134 info.shmmax = in->shmmax;
1135 info.shmmin = in->shmmin;
1136 info.shmmni = in->shmmni;
1137 info.shmseg = in->shmseg;
1138 info.shmall = in->shmall;
1139 return copy_to_user(buf, &info, sizeof(info));
1140 }
1141}
1142
1143static int put_compat_shm_info(struct shm_info *ip,
1144 struct compat_shm_info __user *uip)
1145{
1146 struct compat_shm_info info;
1147
1148 memset(&info, 0, sizeof(info));
1149 info.used_ids = ip->used_ids;
1150 info.shm_tot = ip->shm_tot;
1151 info.shm_rss = ip->shm_rss;
1152 info.shm_swp = ip->shm_swp;
1153 info.swap_attempts = ip->swap_attempts;
1154 info.swap_successes = ip->swap_successes;
1155 return copy_to_user(up, &info, sizeof(info));
1156}
1157
1158static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in,
1159 int version)
1160{
1161 if (version == IPC_64) {
1162 struct compat_shmid64_ds v;
1163 memset(&v, 0, sizeof(v));
1164 v.shm_perm.key = in->shm_perm.key;
1165 v.shm_perm.uid = in->shm_perm.uid;
1166 v.shm_perm.gid = in->shm_perm.gid;
1167 v.shm_perm.cuid = in->shm_perm.cuid;
1168 v.shm_perm.cgid = in->shm_perm.cgid;
1169 v.shm_perm.mode = in->shm_perm.mode;
1170 v.shm_perm.seq = in->shm_perm.seq;
1171 v.shm_atime = in->shm_atime;
1172 v.shm_dtime = in->shm_dtime;
1173 v.shm_ctime = in->shm_ctime;
1174 v.shm_segsz = in->shm_segsz;
1175 v.shm_nattch = in->shm_nattch;
1176 v.shm_cpid = in->shm_cpid;
1177 v.shm_lpid = in->shm_lpid;
1178 return copy_to_user(buf, &v, sizeof(v));
1179 } else {
1180 struct compat_shmid_ds v;
1181 memset(&v, 0, sizeof(v));
1182 v.shm_perm.key = in->shm_perm.key;
1183 SET_UID(v.shm_perm.uid, in->shm_perm.uid);
1184 SET_GID(v.shm_perm.gid, in->shm_perm.gid);
1185 SET_UID(v.shm_perm.cuid, in->shm_perm.cuid);
1186 SET_GID(v.shm_perm.cgid, in->shm_perm.cgid);
1187 v.shm_perm.mode = in->shm_perm.mode;
1188 v.shm_perm.seq = in->shm_perm.seq;
1189 v.shm_atime = in->shm_atime;
1190 v.shm_dtime = in->shm_dtime;
1191 v.shm_ctime = in->shm_ctime;
1192 v.shm_segsz = in->shm_segsz;
1193 v.shm_nattch = in->shm_nattch;
1194 v.shm_cpid = in->shm_cpid;
1195 v.shm_lpid = in->shm_lpid;
1196 return copy_to_user(buf, &v, sizeof(v));
1197 }
1198}
1199
1200static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf,
1201 int version)
1202{
1203 memset(out, 0, sizeof(*out));
1204 if (version == IPC_64) {
1205 struct compat_shmid64_ds *p = buf;
1206 struct compat_ipc64_perm v;
1207 if (copy_from_user(&v, &p->shm_perm, sizeof(v)))
1208 return -EFAULT;
1209 out->shm_perm.uid = v.uid;
1210 out->shm_perm.gid = v.gid;
1211 out->shm_perm.mode = v.mode;
1212 } else {
1213 struct compat_shmid_ds *p = buf;
1214 struct compat_ipc_perm v;
1215 if (copy_from_user(&v, &p->shm_perm, sizeof(v)))
1216 return -EFAULT;
1217 out->shm_perm.uid = v.uid;
1218 out->shm_perm.gid = v.gid;
1219 out->shm_perm.mode = v.mode;
1220 }
1221 return 0;
1222}
1223
1224COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr)
1225{
1226 struct ipc_namespace *ns;
1227 struct shmid64_ds sem64;
1228 int version = compat_ipc_parse_version(&cmd);
1229 int err;
1230
1231 ns = current->nsproxy->ipc_ns;
1232
1233 if (cmd < 0 || shmid < 0)
1234 return -EINVAL;
1235
1236 switch (cmd) {
1237 case IPC_INFO: {
1238 struct shminfo64 shminfo;
1239 err = shmctl_ipc_info(ns, &shminfo);
1240 if (err < 0)
1241 return err;
1242 if (copy_compat_shminfo_to_user(uptr, &shminfo, version))
1243 err = -EFAULT;
1244 return err;
1245 }
1246 case SHM_INFO: {
1247 struct shm_info shm_info;
1248 err = shmctl_shm_info(ns, &shm_info);
1249 if (err < 0)
1250 return err;
1251 if (put_compat_shm_info(&shm_info, uptr))
1252 err = -EFAULT;
1253 return err;
1254 }
1255 case IPC_STAT:
1256 case SHM_STAT:
1257 err = shmctl_stat(ns, shmid, cmd, &sem64);
1258 if (err < 0)
1259 return err;
1260 if (copy_compat_shmid_to_user(&sem64, uptr, version))
1261 err = -EFAULT;
1262 return err;
1263
1264 case IPC_SET:
1265 if (copy_compat_shmid_from_user(&sem64, uptr, version))
1266 return -EFAULT;
1267 /* fallthru */
1268 case IPC_RMID:
1269 return shmctl_down(ns, shmid, cmd, &sem64);
1270 case SHM_LOCK:
1271 case SHM_UNLOCK:
1272 return shmctl_do_lock(ns, shmid, cmd);
1273 break;
1274 default:
1275 return -EINVAL;
1276 }
1277 return err;
1278}
1279#endif
1280
1082/* 1281/*
1083 * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. 1282 * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
1084 * 1283 *
diff --git a/ipc/util.h b/ipc/util.h
index c692010e6f0a..3a3dfe137bee 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -191,4 +191,28 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
191 const struct ipc_ops *ops, struct ipc_params *params); 191 const struct ipc_ops *ops, struct ipc_params *params);
192void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, 192void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
193 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); 193 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
194
195#ifdef CONFIG_COMPAT
196#include <linux/compat.h>
197struct compat_ipc_perm {
198 key_t key;
199 __compat_uid_t uid;
200 __compat_gid_t gid;
201 __compat_uid_t cuid;
202 __compat_gid_t cgid;
203 compat_mode_t mode;
204 unsigned short seq;
205};
206
207static inline int compat_ipc_parse_version(int *cmd)
208{
209#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
210 int version = *cmd & IPC_64;
211 *cmd &= ~IPC_64;
212 return version;
213#else
214 return IPC_64;
215#endif
216}
217#endif
194#endif 218#endif