blob: c83099a3b265d0a8ef96c8fb36f3da055e651db6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * 32 bit compatibility code for System V IPC
3 *
4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
7 * Copyright (C) 2000 VA Linux Co
8 * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
9 * Copyright (C) 2000 Hewlett-Packard Co.
10 * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
11 * Copyright (C) 2000 Gerhard Tonn (ton@de.ibm.com)
12 * Copyright (C) 2000-2002 Andi Kleen, SuSE Labs (x86-64 port)
13 * Copyright (C) 2000 Silicon Graphics, Inc.
14 * Copyright (C) 2001 IBM
15 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
16 * Copyright (C) 2004 Arnd Bergmann (arnd@arndb.de)
17 *
18 * This code is collected from the versions for sparc64, mips64, s390x, ia64,
19 * ppc64 and x86_64, all of which are based on the original sparc64 version
20 * by Jakub Jelinek.
21 *
22 */
23#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/errno.h>
25#include <linux/highuid.h>
26#include <linux/init.h>
27#include <linux/msg.h>
28#include <linux/shm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/syscalls.h>
Chris Metcalf48b25c42012-03-15 13:13:38 -040030#include <linux/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Ingo Molnar5f921ae2006-03-26 01:37:17 -080032#include <linux/mutex.h>
Paul McQuade7153e402014-06-06 14:37:37 -070033#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#include "util.h"
36
37struct compat_msgbuf {
38 compat_long_t mtype;
39 char mtext[1];
40};
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042struct compat_semid_ds {
43 struct compat_ipc_perm sem_perm;
44 compat_time_t sem_otime;
45 compat_time_t sem_ctime;
46 compat_uptr_t sem_base;
47 compat_uptr_t sem_pending;
48 compat_uptr_t sem_pending_last;
49 compat_uptr_t undo;
50 unsigned short sem_nsems;
51};
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053struct compat_ipc_kludge {
54 compat_uptr_t msgp;
55 compat_long_t msgtyp;
56};
57
Al Viro553f7702017-07-08 22:52:47 -040058static inline int __compat_ipc_parse_version(int *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
Will Deaconc1d7e012012-07-30 14:42:46 -070060#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 int version = *cmd & IPC_64;
62
63 /* this is tricky: architectures that have support for the old
64 * ipc structures in 64 bit binaries need to have IPC_64 set
65 * in cmd, the others need to have it cleared */
66#ifndef ipc_parse_version
67 *cmd |= IPC_64;
68#else
69 *cmd &= ~IPC_64;
70#endif
71 return version;
Chris Metcalf48b25c42012-03-15 13:13:38 -040072#else
73 /* With the asm-generic APIs, we always use the 64-bit versions. */
74 return IPC_64;
75#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
77
78static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
79 struct compat_ipc64_perm __user *up64)
80{
81 int err;
82
83 err = __get_user(p64->uid, &up64->uid);
84 err |= __get_user(p64->gid, &up64->gid);
85 err |= __get_user(p64->mode, &up64->mode);
86 return err;
87}
88
89static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
90 struct compat_ipc_perm __user *up)
91{
92 int err;
93
94 err = __get_user(p->uid, &up->uid);
95 err |= __get_user(p->gid, &up->gid);
96 err |= __get_user(p->mode, &up->mode);
97 return err;
98}
99
100static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
101 struct compat_ipc64_perm __user *up64)
102{
103 int err;
104
105 err = __put_user(p64->key, &up64->key);
106 err |= __put_user(p64->uid, &up64->uid);
107 err |= __put_user(p64->gid, &up64->gid);
108 err |= __put_user(p64->cuid, &up64->cuid);
109 err |= __put_user(p64->cgid, &up64->cgid);
110 err |= __put_user(p64->mode, &up64->mode);
111 err |= __put_user(p64->seq, &up64->seq);
112 return err;
113}
114
115static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
Mark Rustad0d5e7582014-10-13 15:54:16 -0700116 struct compat_ipc_perm __user *uip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
118 int err;
Stephen Rothwell202e5972005-09-06 15:16:40 -0700119 __compat_uid_t u;
120 __compat_gid_t g;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Mark Rustad0d5e7582014-10-13 15:54:16 -0700122 err = __put_user(p->key, &uip->key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 SET_UID(u, p->uid);
Mark Rustad0d5e7582014-10-13 15:54:16 -0700124 err |= __put_user(u, &uip->uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 SET_GID(g, p->gid);
Mark Rustad0d5e7582014-10-13 15:54:16 -0700126 err |= __put_user(g, &uip->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 SET_UID(u, p->cuid);
Mark Rustad0d5e7582014-10-13 15:54:16 -0700128 err |= __put_user(u, &uip->cuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 SET_GID(g, p->cgid);
Mark Rustad0d5e7582014-10-13 15:54:16 -0700130 err |= __put_user(g, &uip->cgid);
131 err |= __put_user(p->mode, &uip->mode);
132 err |= __put_user(p->seq, &uip->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 return err;
134}
135
Mark Rustad0d5e7582014-10-13 15:54:16 -0700136static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct compat_semid64_ds __user *up64)
138{
Manfred Spraul239521f2014-01-27 17:07:04 -0800139 if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return -EFAULT;
Mark Rustad0d5e7582014-10-13 15:54:16 -0700141 return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
144static inline int get_compat_semid_ds(struct semid64_ds *s,
145 struct compat_semid_ds __user *up)
146{
Manfred Spraul239521f2014-01-27 17:07:04 -0800147 if (!access_ok(VERIFY_READ, up, sizeof(*up)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 return -EFAULT;
149 return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
150}
151
Mark Rustad0d5e7582014-10-13 15:54:16 -0700152static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 struct compat_semid64_ds __user *up64)
154{
155 int err;
156
Manfred Spraul239521f2014-01-27 17:07:04 -0800157 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 return -EFAULT;
Mark Rustad0d5e7582014-10-13 15:54:16 -0700159 err = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
160 err |= __put_user(sem64->sem_otime, &up64->sem_otime);
161 err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
162 err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 return err;
164}
165
166static inline int put_compat_semid_ds(struct semid64_ds *s,
167 struct compat_semid_ds __user *up)
168{
169 int err;
170
Manfred Spraul239521f2014-01-27 17:07:04 -0800171 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
Alexander Grafd57d9732007-07-06 02:39:53 -0700172 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
174 err |= __put_user(s->sem_otime, &up->sem_otime);
175 err |= __put_user(s->sem_ctime, &up->sem_ctime);
176 err |= __put_user(s->sem_nsems, &up->sem_nsems);
177 return err;
178}
179
Chris Metcalf48b25c42012-03-15 13:13:38 -0400180static long do_compat_semctl(int first, int second, int third, u32 pad)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
Al Viroe1fd1f42013-03-05 15:04:55 -0500182 unsigned long fourth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 int err, err2;
Mark Rustad0d5e7582014-10-13 15:54:16 -0700184 struct semid64_ds sem64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 struct semid64_ds __user *up64;
Al Viro553f7702017-07-08 22:52:47 -0400186 int version = __compat_ipc_parse_version(&third);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Mark Rustad0d5e7582014-10-13 15:54:16 -0700188 memset(&sem64, 0, sizeof(sem64));
Dan Rosenberg03145be2010-10-27 15:34:17 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 if ((third & (~IPC_64)) == SETVAL)
Al Viroe1fd1f42013-03-05 15:04:55 -0500191#ifdef __BIG_ENDIAN
192 fourth = (unsigned long)pad << 32;
193#else
194 fourth = pad;
195#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 else
Al Viroe1fd1f42013-03-05 15:04:55 -0500197 fourth = (unsigned long)compat_ptr(pad);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 switch (third & (~IPC_64)) {
199 case IPC_INFO:
200 case IPC_RMID:
201 case SEM_INFO:
202 case GETVAL:
203 case GETPID:
204 case GETNCNT:
205 case GETZCNT:
206 case GETALL:
207 case SETVAL:
208 case SETALL:
209 err = sys_semctl(first, second, third, fourth);
210 break;
211
212 case IPC_STAT:
213 case SEM_STAT:
Mark Rustad0d5e7582014-10-13 15:54:16 -0700214 up64 = compat_alloc_user_space(sizeof(sem64));
Al Viroe1fd1f42013-03-05 15:04:55 -0500215 fourth = (unsigned long)up64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 err = sys_semctl(first, second, third, fourth);
217 if (err < 0)
218 break;
Mark Rustad0d5e7582014-10-13 15:54:16 -0700219 if (copy_from_user(&sem64, up64, sizeof(sem64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 err2 = -EFAULT;
221 else if (version == IPC_64)
Mark Rustad0d5e7582014-10-13 15:54:16 -0700222 err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 else
Mark Rustad0d5e7582014-10-13 15:54:16 -0700224 err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if (err2)
226 err = -EFAULT;
227 break;
228
229 case IPC_SET:
Davidlohr Bueso3ab08fe2014-01-27 17:07:06 -0800230 if (version == IPC_64)
Mark Rustad0d5e7582014-10-13 15:54:16 -0700231 err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
Davidlohr Bueso3ab08fe2014-01-27 17:07:06 -0800232 else
Mark Rustad0d5e7582014-10-13 15:54:16 -0700233 err = get_compat_semid_ds(&sem64, compat_ptr(pad));
Davidlohr Bueso3ab08fe2014-01-27 17:07:06 -0800234
Mark Rustad0d5e7582014-10-13 15:54:16 -0700235 up64 = compat_alloc_user_space(sizeof(sem64));
236 if (copy_to_user(up64, &sem64, sizeof(sem64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 err = -EFAULT;
238 if (err)
239 break;
240
Al Viroe1fd1f42013-03-05 15:04:55 -0500241 fourth = (unsigned long)up64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 err = sys_semctl(first, second, third, fourth);
243 break;
244
245 default:
246 err = -EINVAL;
247 break;
248 }
249 return err;
250}
251
Al Viro0e65a812013-02-03 14:36:44 -0500252static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
Stanislav Kinsburskyf9dd87f2013-01-04 15:34:52 -0800253{
254 struct compat_msgbuf __user *msgp = dest;
255 size_t msgsz;
256
257 if (put_user(msg->m_type, &msgp->mtype))
258 return -EFAULT;
259
260 msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
261 if (store_msg(msgp->mtext, msg, msgsz))
262 return -EFAULT;
263 return msgsz;
264}
265
Al Viro0e65a812013-02-03 14:36:44 -0500266#ifndef COMPAT_SHMLBA
267#define COMPAT_SHMLBA SHMLBA
268#endif
269
Chris Metcalf48b25c42012-03-15 13:13:38 -0400270#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
Al Viro56e41d32013-01-21 23:15:25 -0500271COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
272 u32, third, compat_uptr_t, ptr, u32, fifth)
273{
274 int version;
Al Viro0e65a812013-02-03 14:36:44 -0500275 u32 pad;
Al Viro56e41d32013-01-21 23:15:25 -0500276
277 version = call >> 16; /* hack for backward compatibility */
278 call &= 0xffff;
279
280 switch (call) {
281 case SEMOP:
282 /* struct sembuf is the same on 32 and 64bit :)) */
283 return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
284 case SEMTIMEDOP:
285 return compat_sys_semtimedop(first, compat_ptr(ptr), second,
286 compat_ptr(fifth));
287 case SEMGET:
288 return sys_semget(first, second, third);
289 case SEMCTL:
Al Viro0e65a812013-02-03 14:36:44 -0500290 if (!ptr)
291 return -EINVAL;
292 if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
293 return -EFAULT;
294 return do_compat_semctl(first, second, third, pad);
Al Viro56e41d32013-01-21 23:15:25 -0500295
Al Viro0e65a812013-02-03 14:36:44 -0500296 case MSGSND: {
297 struct compat_msgbuf __user *up = compat_ptr(ptr);
298 compat_long_t type;
299
300 if (first < 0 || second < 0)
301 return -EINVAL;
302
303 if (get_user(type, &up->mtype))
304 return -EFAULT;
305
306 return do_msgsnd(first, type, up->mtext, second, third);
307 }
308 case MSGRCV: {
309 void __user *uptr = compat_ptr(ptr);
310
311 if (first < 0 || second < 0)
312 return -EINVAL;
313
314 if (!version) {
315 struct compat_ipc_kludge ipck;
316 if (!uptr)
317 return -EINVAL;
Manfred Spraul239521f2014-01-27 17:07:04 -0800318 if (copy_from_user(&ipck, uptr, sizeof(ipck)))
Al Viro0e65a812013-02-03 14:36:44 -0500319 return -EFAULT;
320 uptr = compat_ptr(ipck.msgp);
321 fifth = ipck.msgtyp;
322 }
Mateusz Guzike7ca2552014-01-27 17:07:11 -0800323 return do_msgrcv(first, uptr, second, (s32)fifth, third,
Al Viro0e65a812013-02-03 14:36:44 -0500324 compat_do_msg_fill);
325 }
Al Viro56e41d32013-01-21 23:15:25 -0500326 case MSGGET:
327 return sys_msgget(first, second);
328 case MSGCTL:
329 return compat_sys_msgctl(first, second, compat_ptr(ptr));
330
Al Viro0e65a812013-02-03 14:36:44 -0500331 case SHMAT: {
332 int err;
333 unsigned long raddr;
334
335 if (version == 1)
336 return -EINVAL;
337 err = do_shmat(first, compat_ptr(ptr), second, &raddr,
338 COMPAT_SHMLBA);
339 if (err < 0)
340 return err;
341 return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
342 }
Al Viro56e41d32013-01-21 23:15:25 -0500343 case SHMDT:
344 return sys_shmdt(compat_ptr(ptr));
345 case SHMGET:
346 return sys_shmget(first, (unsigned)second, third);
347 case SHMCTL:
348 return compat_sys_shmctl(first, second, compat_ptr(ptr));
349 }
350
351 return -ENOSYS;
352}
Al Viro0e65a812013-02-03 14:36:44 -0500353#endif
354
355COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
Chris Metcalf48b25c42012-03-15 13:13:38 -0400356{
357 return do_compat_semctl(semid, semnum, cmd, arg);
358}
359
Al Viro0e65a812013-02-03 14:36:44 -0500360COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
361 compat_ssize_t, msgsz, int, msgflg)
Chris Metcalf48b25c42012-03-15 13:13:38 -0400362{
Al Viro0e65a812013-02-03 14:36:44 -0500363 struct compat_msgbuf __user *up = compat_ptr(msgp);
Chris Metcalf48b25c42012-03-15 13:13:38 -0400364 compat_long_t mtype;
365
Al Viro0e65a812013-02-03 14:36:44 -0500366 if (get_user(mtype, &up->mtype))
Chris Metcalf48b25c42012-03-15 13:13:38 -0400367 return -EFAULT;
Al Viro0e65a812013-02-03 14:36:44 -0500368 return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
Chris Metcalf48b25c42012-03-15 13:13:38 -0400369}
370
Al Viro0e65a812013-02-03 14:36:44 -0500371COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
Heiko Carstens291fdb02014-03-04 12:39:03 +0100372 compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
Chris Metcalf48b25c42012-03-15 13:13:38 -0400373{
Heiko Carstens291fdb02014-03-04 12:39:03 +0100374 return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
Al Viro0e65a812013-02-03 14:36:44 -0500375 msgflg, compat_do_msg_fill);
Chris Metcalf48b25c42012-03-15 13:13:38 -0400376}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Al Viro0e65a812013-02-03 14:36:44 -0500378COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
Chris Metcalf48b25c42012-03-15 13:13:38 -0400379{
380 unsigned long ret;
381 long err;
382
Will Deacon079a96a2012-07-30 14:42:38 -0700383 err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
Chris Metcalf48b25c42012-03-15 13:13:38 -0400384 if (err)
385 return err;
386 force_successful_syscall_return();
387 return (long)ret;
388}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Heiko Carstens5d70a592014-03-04 11:17:50 +0100390COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
391 unsigned, nsops,
392 const struct compat_timespec __user *, timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
H. Peter Anvin81993e82014-02-01 18:54:11 -0800394 struct timespec __user *ts64;
395 if (compat_convert_timespec(&ts64, timeout))
396 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return sys_semtimedop(semid, tsems, nsops, ts64);
398}