summaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
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/shm.c
parent9ba720c18622b250c0abeccbcea1b03531a92277 (diff)
ipc: move compat shmctl to native
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc/shm.c')
-rw-r--r--ipc/shm.c209
1 files changed, 204 insertions, 5 deletions
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 *