diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-08 22:52:47 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-15 20:46:42 -0400 |
commit | 553f770ef71b27ee053bd241bef0998a15f43467 (patch) | |
tree | b23887b5e7d6ce16c9bc0627f26748e500ad5177 /ipc/shm.c | |
parent | 9ba720c18622b250c0abeccbcea1b03531a92277 (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.c | 209 |
1 files changed, 204 insertions, 5 deletions
@@ -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 | |||
1085 | struct 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 | |||
1099 | struct 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 | |||
1111 | struct 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 | |||
1117 | static 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 | |||
1143 | static 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 | |||
1158 | static 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 | |||
1200 | static 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 | |||
1224 | COMPAT_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 | * |