Blame view

ipc/compat.c 19.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * 32 bit compatibility code for System V IPC
   *
   * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
   * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
   * Copyright (C) 2000		VA Linux Co
   * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
   * Copyright (C) 2000           Hewlett-Packard Co.
   * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
   * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
   * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
   * Copyright (C) 2000		Silicon Graphics, Inc.
   * Copyright (C) 2001		IBM
   * Copyright (C) 2004		IBM Deutschland Entwicklung GmbH, IBM Corporation
   * Copyright (C) 2004		Arnd Bergmann (arnd@arndb.de)
   *
   * This code is collected from the versions for sparc64, mips64, s390x, ia64,
   * ppc64 and x86_64, all of which are based on the original sparc64 version
   * by Jakub Jelinek.
   *
   */
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  #include <linux/errno.h>
  #include <linux/highuid.h>
  #include <linux/init.h>
  #include <linux/msg.h>
  #include <linux/shm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/syscalls.h>
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
30
  #include <linux/ptrace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
32
  #include <linux/mutex.h>
7153e4027   Paul McQuade   ipc, kernel: use ...
33
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
  
  #include "util.h"
  
  struct compat_msgbuf {
  	compat_long_t mtype;
  	char mtext[1];
  };
  
  struct compat_ipc_perm {
  	key_t key;
202e5979a   Stephen Rothwell   [PATCH] compat: b...
44
45
46
47
  	__compat_uid_t uid;
  	__compat_gid_t gid;
  	__compat_uid_t cuid;
  	__compat_gid_t cgid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  	compat_mode_t mode;
  	unsigned short seq;
  };
  
  struct compat_semid_ds {
  	struct compat_ipc_perm sem_perm;
  	compat_time_t sem_otime;
  	compat_time_t sem_ctime;
  	compat_uptr_t sem_base;
  	compat_uptr_t sem_pending;
  	compat_uptr_t sem_pending_last;
  	compat_uptr_t undo;
  	unsigned short sem_nsems;
  };
  
  struct compat_msqid_ds {
  	struct compat_ipc_perm msg_perm;
  	compat_uptr_t msg_first;
  	compat_uptr_t msg_last;
  	compat_time_t msg_stime;
  	compat_time_t msg_rtime;
  	compat_time_t msg_ctime;
  	compat_ulong_t msg_lcbytes;
  	compat_ulong_t msg_lqbytes;
  	unsigned short msg_cbytes;
  	unsigned short msg_qnum;
  	unsigned short msg_qbytes;
  	compat_ipc_pid_t msg_lspid;
  	compat_ipc_pid_t msg_lrpid;
  };
  
  struct compat_shmid_ds {
  	struct compat_ipc_perm shm_perm;
  	int shm_segsz;
  	compat_time_t shm_atime;
  	compat_time_t shm_dtime;
  	compat_time_t shm_ctime;
  	compat_ipc_pid_t shm_cpid;
  	compat_ipc_pid_t shm_lpid;
  	unsigned short shm_nattch;
  	unsigned short shm_unused;
  	compat_uptr_t shm_unused2;
  	compat_uptr_t shm_unused3;
  };
  
  struct compat_ipc_kludge {
  	compat_uptr_t msgp;
  	compat_long_t msgtyp;
  };
  
  struct compat_shminfo64 {
  	compat_ulong_t shmmax;
  	compat_ulong_t shmmin;
  	compat_ulong_t shmmni;
  	compat_ulong_t shmseg;
  	compat_ulong_t shmall;
  	compat_ulong_t __unused1;
  	compat_ulong_t __unused2;
  	compat_ulong_t __unused3;
  	compat_ulong_t __unused4;
  };
  
  struct compat_shm_info {
  	compat_int_t used_ids;
  	compat_ulong_t shm_tot, shm_rss, shm_swp;
  	compat_ulong_t swap_attempts, swap_successes;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  static inline int compat_ipc_parse_version(int *cmd)
  {
c1d7e01d7   Will Deacon   ipc: use Kconfig ...
117
  #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
125
126
127
128
  	int version = *cmd & IPC_64;
  
  	/* this is tricky: architectures that have support for the old
  	 * ipc structures in 64 bit binaries need to have IPC_64 set
  	 * in cmd, the others need to have it cleared */
  #ifndef ipc_parse_version
  	*cmd |= IPC_64;
  #else
  	*cmd &= ~IPC_64;
  #endif
  	return version;
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
129
130
131
132
  #else
  	/* With the asm-generic APIs, we always use the 64-bit versions. */
  	return IPC_64;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  }
  
  static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
  					  struct compat_ipc64_perm __user *up64)
  {
  	int err;
  
  	err  = __get_user(p64->uid, &up64->uid);
  	err |= __get_user(p64->gid, &up64->gid);
  	err |= __get_user(p64->mode, &up64->mode);
  	return err;
  }
  
  static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
  					struct compat_ipc_perm __user *up)
  {
  	int err;
  
  	err  = __get_user(p->uid, &up->uid);
  	err |= __get_user(p->gid, &up->gid);
  	err |= __get_user(p->mode, &up->mode);
  	return err;
  }
  
  static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
  					  struct compat_ipc64_perm __user *up64)
  {
  	int err;
  
  	err  = __put_user(p64->key, &up64->key);
  	err |= __put_user(p64->uid, &up64->uid);
  	err |= __put_user(p64->gid, &up64->gid);
  	err |= __put_user(p64->cuid, &up64->cuid);
  	err |= __put_user(p64->cgid, &up64->cgid);
  	err |= __put_user(p64->mode, &up64->mode);
  	err |= __put_user(p64->seq, &up64->seq);
  	return err;
  }
  
  static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
0d5e75802   Mark Rustad   ipc: resolve shad...
173
  					struct compat_ipc_perm __user *uip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  {
  	int err;
202e5979a   Stephen Rothwell   [PATCH] compat: b...
176
177
  	__compat_uid_t u;
  	__compat_gid_t g;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178

0d5e75802   Mark Rustad   ipc: resolve shad...
179
  	err  = __put_user(p->key, &uip->key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  	SET_UID(u, p->uid);
0d5e75802   Mark Rustad   ipc: resolve shad...
181
  	err |= __put_user(u, &uip->uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  	SET_GID(g, p->gid);
0d5e75802   Mark Rustad   ipc: resolve shad...
183
  	err |= __put_user(g, &uip->gid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  	SET_UID(u, p->cuid);
0d5e75802   Mark Rustad   ipc: resolve shad...
185
  	err |= __put_user(u, &uip->cuid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  	SET_GID(g, p->cgid);
0d5e75802   Mark Rustad   ipc: resolve shad...
187
188
189
  	err |= __put_user(g, &uip->cgid);
  	err |= __put_user(p->mode, &uip->mode);
  	err |= __put_user(p->seq, &uip->seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
  	return err;
  }
0d5e75802   Mark Rustad   ipc: resolve shad...
192
  static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  					struct compat_semid64_ds __user *up64)
  {
239521f31   Manfred Spraul   ipc: whitespace c...
195
  	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  		return -EFAULT;
0d5e75802   Mark Rustad   ipc: resolve shad...
197
  	return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
  }
  
  static inline int get_compat_semid_ds(struct semid64_ds *s,
  				      struct compat_semid_ds __user *up)
  {
239521f31   Manfred Spraul   ipc: whitespace c...
203
  	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
  		return -EFAULT;
  	return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  }
0d5e75802   Mark Rustad   ipc: resolve shad...
207
  static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  					struct compat_semid64_ds __user *up64)
  {
  	int err;
239521f31   Manfred Spraul   ipc: whitespace c...
211
  	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  		return -EFAULT;
0d5e75802   Mark Rustad   ipc: resolve shad...
213
214
215
216
  	err  = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
  	err |= __put_user(sem64->sem_otime, &up64->sem_otime);
  	err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
  	err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
223
  	return err;
  }
  
  static inline int put_compat_semid_ds(struct semid64_ds *s,
  				      struct compat_semid_ds __user *up)
  {
  	int err;
239521f31   Manfred Spraul   ipc: whitespace c...
224
  	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
d57d97310   Alexander Graf   fix logic error i...
225
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
  	err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
  	err |= __put_user(s->sem_otime, &up->sem_otime);
  	err |= __put_user(s->sem_ctime, &up->sem_ctime);
  	err |= __put_user(s->sem_nsems, &up->sem_nsems);
  	return err;
  }
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
232
  static long do_compat_semctl(int first, int second, int third, u32 pad)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
e1fd1f490   Al Viro   get rid of union ...
234
  	unsigned long fourth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	int err, err2;
0d5e75802   Mark Rustad   ipc: resolve shad...
236
  	struct semid64_ds sem64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
  	struct semid64_ds __user *up64;
  	int version = compat_ipc_parse_version(&third);
0d5e75802   Mark Rustad   ipc: resolve shad...
239
  	memset(&sem64, 0, sizeof(sem64));
03145beb4   Dan Rosenberg   ipc: initialize s...
240

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  	if ((third & (~IPC_64)) == SETVAL)
e1fd1f490   Al Viro   get rid of union ...
242
243
244
245
246
  #ifdef __BIG_ENDIAN
  		fourth = (unsigned long)pad << 32;
  #else
  		fourth = pad;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	else
e1fd1f490   Al Viro   get rid of union ...
248
  		fourth = (unsigned long)compat_ptr(pad);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	switch (third & (~IPC_64)) {
  	case IPC_INFO:
  	case IPC_RMID:
  	case SEM_INFO:
  	case GETVAL:
  	case GETPID:
  	case GETNCNT:
  	case GETZCNT:
  	case GETALL:
  	case SETVAL:
  	case SETALL:
  		err = sys_semctl(first, second, third, fourth);
  		break;
  
  	case IPC_STAT:
  	case SEM_STAT:
0d5e75802   Mark Rustad   ipc: resolve shad...
265
  		up64 = compat_alloc_user_space(sizeof(sem64));
e1fd1f490   Al Viro   get rid of union ...
266
  		fourth = (unsigned long)up64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
  		err = sys_semctl(first, second, third, fourth);
  		if (err < 0)
  			break;
0d5e75802   Mark Rustad   ipc: resolve shad...
270
  		if (copy_from_user(&sem64, up64, sizeof(sem64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
  			err2 = -EFAULT;
  		else if (version == IPC_64)
0d5e75802   Mark Rustad   ipc: resolve shad...
273
  			err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  		else
0d5e75802   Mark Rustad   ipc: resolve shad...
275
  			err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
  		if (err2)
  			err = -EFAULT;
  		break;
  
  	case IPC_SET:
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
281
  		if (version == IPC_64)
0d5e75802   Mark Rustad   ipc: resolve shad...
282
  			err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
283
  		else
0d5e75802   Mark Rustad   ipc: resolve shad...
284
  			err = get_compat_semid_ds(&sem64, compat_ptr(pad));
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
285

0d5e75802   Mark Rustad   ipc: resolve shad...
286
287
  		up64 = compat_alloc_user_space(sizeof(sem64));
  		if (copy_to_user(up64, &sem64, sizeof(sem64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
  			err = -EFAULT;
  		if (err)
  			break;
e1fd1f490   Al Viro   get rid of union ...
291
  		fourth = (unsigned long)up64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
  		err = sys_semctl(first, second, third, fourth);
  		break;
  
  	default:
  		err = -EINVAL;
  		break;
  	}
  	return err;
  }
0e65a81b1   Al Viro   get rid of compat...
301
  static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
302
303
304
305
306
307
308
309
310
311
312
313
  {
  	struct compat_msgbuf __user *msgp = dest;
  	size_t msgsz;
  
  	if (put_user(msg->m_type, &msgp->mtype))
  		return -EFAULT;
  
  	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
  	if (store_msg(msgp->mtext, msg, msgsz))
  		return -EFAULT;
  	return msgsz;
  }
0e65a81b1   Al Viro   get rid of compat...
314
315
316
  #ifndef COMPAT_SHMLBA
  #define COMPAT_SHMLBA	SHMLBA
  #endif
56e41d3c5   Al Viro   merge compat sys_...
317

0e65a81b1   Al Viro   get rid of compat...
318
  #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
56e41d3c5   Al Viro   merge compat sys_...
319
320
321
322
  COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
  	u32, third, compat_uptr_t, ptr, u32, fifth)
  {
  	int version;
0e65a81b1   Al Viro   get rid of compat...
323
  	u32 pad;
56e41d3c5   Al Viro   merge compat sys_...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  
  	version = call >> 16; /* hack for backward compatibility */
  	call &= 0xffff;
  
  	switch (call) {
  	case SEMOP:
  		/* struct sembuf is the same on 32 and 64bit :)) */
  		return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
  	case SEMTIMEDOP:
  		return compat_sys_semtimedop(first, compat_ptr(ptr), second,
  						compat_ptr(fifth));
  	case SEMGET:
  		return sys_semget(first, second, third);
  	case SEMCTL:
0e65a81b1   Al Viro   get rid of compat...
338
339
340
341
342
343
344
345
346
347
348
349
  		if (!ptr)
  			return -EINVAL;
  		if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
  			return -EFAULT;
  		return do_compat_semctl(first, second, third, pad);
  
  	case MSGSND: {
  		struct compat_msgbuf __user *up = compat_ptr(ptr);
  		compat_long_t type;
  
  		if (first < 0 || second < 0)
  			return -EINVAL;
56e41d3c5   Al Viro   merge compat sys_...
350

0e65a81b1   Al Viro   get rid of compat...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  		if (get_user(type, &up->mtype))
  			return -EFAULT;
  
  		return do_msgsnd(first, type, up->mtext, second, third);
  	}
  	case MSGRCV: {
  		void __user *uptr = compat_ptr(ptr);
  
  		if (first < 0 || second < 0)
  			return -EINVAL;
  
  		if (!version) {
  			struct compat_ipc_kludge ipck;
  			if (!uptr)
  				return -EINVAL;
239521f31   Manfred Spraul   ipc: whitespace c...
366
  			if (copy_from_user(&ipck, uptr, sizeof(ipck)))
0e65a81b1   Al Viro   get rid of compat...
367
368
369
370
  				return -EFAULT;
  			uptr = compat_ptr(ipck.msgp);
  			fifth = ipck.msgtyp;
  		}
e7ca25523   Mateusz Guzik   ipc: fix compat m...
371
  		return do_msgrcv(first, uptr, second, (s32)fifth, third,
0e65a81b1   Al Viro   get rid of compat...
372
373
  				 compat_do_msg_fill);
  	}
56e41d3c5   Al Viro   merge compat sys_...
374
375
376
377
  	case MSGGET:
  		return sys_msgget(first, second);
  	case MSGCTL:
  		return compat_sys_msgctl(first, second, compat_ptr(ptr));
0e65a81b1   Al Viro   get rid of compat...
378
379
380
381
382
383
384
385
386
387
388
389
  	case SHMAT: {
  		int err;
  		unsigned long raddr;
  
  		if (version == 1)
  			return -EINVAL;
  		err = do_shmat(first, compat_ptr(ptr), second, &raddr,
  			       COMPAT_SHMLBA);
  		if (err < 0)
  			return err;
  		return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
  	}
56e41d3c5   Al Viro   merge compat sys_...
390
391
392
393
394
395
396
397
398
399
  	case SHMDT:
  		return sys_shmdt(compat_ptr(ptr));
  	case SHMGET:
  		return sys_shmget(first, (unsigned)second, third);
  	case SHMCTL:
  		return compat_sys_shmctl(first, second, compat_ptr(ptr));
  	}
  
  	return -ENOSYS;
  }
0e65a81b1   Al Viro   get rid of compat...
400
401
402
  #endif
  
  COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
403
404
405
  {
  	return do_compat_semctl(semid, semnum, cmd, arg);
  }
0e65a81b1   Al Viro   get rid of compat...
406
407
  COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
  		       compat_ssize_t, msgsz, int, msgflg)
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
408
  {
0e65a81b1   Al Viro   get rid of compat...
409
  	struct compat_msgbuf __user *up = compat_ptr(msgp);
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
410
  	compat_long_t mtype;
0e65a81b1   Al Viro   get rid of compat...
411
  	if (get_user(mtype, &up->mtype))
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
412
  		return -EFAULT;
0e65a81b1   Al Viro   get rid of compat...
413
  	return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
414
  }
0e65a81b1   Al Viro   get rid of compat...
415
  COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
291fdb0bc   Heiko Carstens   ipc/compat_sys_ms...
416
  		       compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
417
  {
291fdb0bc   Heiko Carstens   ipc/compat_sys_ms...
418
  	return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
0e65a81b1   Al Viro   get rid of compat...
419
  			 msgflg, compat_do_msg_fill);
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
420
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
  
  static inline int get_compat_msqid64(struct msqid64_ds *m64,
  				     struct compat_msqid64_ds __user *up64)
  {
  	int err;
  
  	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  		return -EFAULT;
  	err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  	err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
  	return err;
  }
  
  static inline int get_compat_msqid(struct msqid64_ds *m,
  				   struct compat_msqid_ds __user *up)
  {
  	int err;
  
  	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  		return -EFAULT;
  	err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  	err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
  	return err;
  }
  
  static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
  				 struct compat_msqid64_ds __user *up64)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  		return -EFAULT;
  	err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
  	err |= __put_user(m64->msg_stime, &up64->msg_stime);
  	err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
  	err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
  	err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
  	err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
  	err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
  	err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
  	err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
  	return err;
  }
  
  static inline int put_compat_msqid_ds(struct msqid64_ds *m,
  				      struct compat_msqid_ds __user *up)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  		return -EFAULT;
  	err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
  	err |= __put_user(m->msg_stime, &up->msg_stime);
  	err |= __put_user(m->msg_rtime, &up->msg_rtime);
  	err |= __put_user(m->msg_ctime, &up->msg_ctime);
  	err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
  	err |= __put_user(m->msg_qnum, &up->msg_qnum);
  	err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
  	err |= __put_user(m->msg_lspid, &up->msg_lspid);
  	err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
  	return err;
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
483
  COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
  {
  	int err, err2;
  	struct msqid64_ds m64;
  	int version = compat_ipc_parse_version(&second);
  	void __user *p;
03145beb4   Dan Rosenberg   ipc: initialize s...
489
  	memset(&m64, 0, sizeof(m64));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
497
  	switch (second & (~IPC_64)) {
  	case IPC_INFO:
  	case IPC_RMID:
  	case MSG_INFO:
  		err = sys_msgctl(first, second, uptr);
  		break;
  
  	case IPC_SET:
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
498
  		if (version == IPC_64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  			err = get_compat_msqid64(&m64, uptr);
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
500
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  			err = get_compat_msqid(&m64, uptr);
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
502

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  		if (err)
  			break;
  		p = compat_alloc_user_space(sizeof(m64));
  		if (copy_to_user(p, &m64, sizeof(m64)))
  			err = -EFAULT;
  		else
  			err = sys_msgctl(first, second, p);
  		break;
  
  	case IPC_STAT:
  	case MSG_STAT:
  		p = compat_alloc_user_space(sizeof(m64));
  		err = sys_msgctl(first, second, p);
  		if (err < 0)
  			break;
  		if (copy_from_user(&m64, p, sizeof(m64)))
  			err2 = -EFAULT;
  		else if (version == IPC_64)
  			err2 = put_compat_msqid64_ds(&m64, uptr);
  		else
  			err2 = put_compat_msqid_ds(&m64, uptr);
  		if (err2)
  			err = -EFAULT;
  		break;
  
  	default:
  		err = -EINVAL;
  		break;
  	}
  	return err;
  }
0e65a81b1   Al Viro   get rid of compat...
534
  COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
535
536
537
  {
  	unsigned long ret;
  	long err;
079a96ae3   Will Deacon   ipc: add COMPAT_S...
538
  	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
48b25c43e   Chris Metcalf   [PATCH v3] ipc: p...
539
540
541
542
543
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

0d5e75802   Mark Rustad   ipc: resolve shad...
545
  static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
  					struct compat_shmid64_ds __user *up64)
  {
  	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
  		return -EFAULT;
0d5e75802   Mark Rustad   ipc: resolve shad...
550
  	return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
557
558
559
  }
  
  static inline int get_compat_shmid_ds(struct shmid64_ds *s,
  				      struct compat_shmid_ds __user *up)
  {
  	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
  		return -EFAULT;
  	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  }
0d5e75802   Mark Rustad   ipc: resolve shad...
560
  static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
  					struct compat_shmid64_ds __user *up64)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  		return -EFAULT;
0d5e75802   Mark Rustad   ipc: resolve shad...
567
568
569
570
571
572
573
574
  	err  = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
  	err |= __put_user(sem64->shm_atime, &up64->shm_atime);
  	err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
  	err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
  	err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
  	err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
  	err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
  	err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  	return err;
  }
  
  static inline int put_compat_shmid_ds(struct shmid64_ds *s,
  				      struct compat_shmid_ds __user *up)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  		return -EFAULT;
  	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
  	err |= __put_user(s->shm_atime, &up->shm_atime);
  	err |= __put_user(s->shm_dtime, &up->shm_dtime);
  	err |= __put_user(s->shm_ctime, &up->shm_ctime);
  	err |= __put_user(s->shm_segsz, &up->shm_segsz);
  	err |= __put_user(s->shm_nattch, &up->shm_nattch);
  	err |= __put_user(s->shm_cpid, &up->shm_cpid);
  	err |= __put_user(s->shm_lpid, &up->shm_lpid);
  	return err;
  }
  
  static inline int put_compat_shminfo64(struct shminfo64 *smi,
  				       struct compat_shminfo64 __user *up64)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
  		return -EFAULT;
af7c693f1   Guy Streeter   Cap shmmax at INT...
603
604
  	if (smi->shmmax > INT_MAX)
  		smi->shmmax = INT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  	err  = __put_user(smi->shmmax, &up64->shmmax);
  	err |= __put_user(smi->shmmin, &up64->shmmin);
  	err |= __put_user(smi->shmmni, &up64->shmmni);
  	err |= __put_user(smi->shmseg, &up64->shmseg);
  	err |= __put_user(smi->shmall, &up64->shmall);
  	return err;
  }
  
  static inline int put_compat_shminfo(struct shminfo64 *smi,
  				     struct shminfo __user *up)
  {
  	int err;
  
  	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
  		return -EFAULT;
af7c693f1   Guy Streeter   Cap shmmax at INT...
620
621
  	if (smi->shmmax > INT_MAX)
  		smi->shmmax = INT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
625
626
  	err  = __put_user(smi->shmmax, &up->shmmax);
  	err |= __put_user(smi->shmmin, &up->shmmin);
  	err |= __put_user(smi->shmmni, &up->shmmni);
  	err |= __put_user(smi->shmseg, &up->shmseg);
  	err |= __put_user(smi->shmall, &up->shmall);
214a627cb   Jesse Millan   [PATCH] put_compa...
627
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  }
  
  static inline int put_compat_shm_info(struct shm_info __user *ip,
  				      struct compat_shm_info __user *uip)
  {
  	int err;
  	struct shm_info si;
  
  	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
  	    copy_from_user(&si, ip, sizeof(si)))
  		return -EFAULT;
  	err  = __put_user(si.used_ids, &uip->used_ids);
  	err |= __put_user(si.shm_tot, &uip->shm_tot);
  	err |= __put_user(si.shm_rss, &uip->shm_rss);
  	err |= __put_user(si.shm_swp, &uip->shm_swp);
  	err |= __put_user(si.swap_attempts, &uip->swap_attempts);
  	err |= __put_user(si.swap_successes, &uip->swap_successes);
  	return err;
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
647
  COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  {
  	void __user *p;
0d5e75802   Mark Rustad   ipc: resolve shad...
650
  	struct shmid64_ds sem64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
  	struct shminfo64 smi;
  	int err, err2;
  	int version = compat_ipc_parse_version(&second);
0d5e75802   Mark Rustad   ipc: resolve shad...
654
  	memset(&sem64, 0, sizeof(sem64));
03145beb4   Dan Rosenberg   ipc: initialize s...
655

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  	switch (second & (~IPC_64)) {
  	case IPC_RMID:
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  		err = sys_shmctl(first, second, uptr);
  		break;
  
  	case IPC_INFO:
  		p = compat_alloc_user_space(sizeof(smi));
  		err = sys_shmctl(first, second, p);
  		if (err < 0)
  			break;
  		if (copy_from_user(&smi, p, sizeof(smi)))
  			err2 = -EFAULT;
  		else if (version == IPC_64)
  			err2 = put_compat_shminfo64(&smi, uptr);
  		else
  			err2 = put_compat_shminfo(&smi, uptr);
  		if (err2)
  			err = -EFAULT;
  		break;
  
  
  	case IPC_SET:
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
680
  		if (version == IPC_64)
0d5e75802   Mark Rustad   ipc: resolve shad...
681
  			err = get_compat_shmid64_ds(&sem64, uptr);
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
682
  		else
0d5e75802   Mark Rustad   ipc: resolve shad...
683
  			err = get_compat_shmid_ds(&sem64, uptr);
3ab08fe20   Davidlohr Bueso   ipc: remove brace...
684

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  		if (err)
  			break;
0d5e75802   Mark Rustad   ipc: resolve shad...
687
688
  		p = compat_alloc_user_space(sizeof(sem64));
  		if (copy_to_user(p, &sem64, sizeof(sem64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
693
694
695
  			err = -EFAULT;
  		else
  			err = sys_shmctl(first, second, p);
  		break;
  
  	case IPC_STAT:
  	case SHM_STAT:
0d5e75802   Mark Rustad   ipc: resolve shad...
696
  		p = compat_alloc_user_space(sizeof(sem64));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
  		err = sys_shmctl(first, second, p);
  		if (err < 0)
  			break;
0d5e75802   Mark Rustad   ipc: resolve shad...
700
  		if (copy_from_user(&sem64, p, sizeof(sem64)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
  			err2 = -EFAULT;
  		else if (version == IPC_64)
0d5e75802   Mark Rustad   ipc: resolve shad...
703
  			err2 = put_compat_shmid64_ds(&sem64, uptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  		else
0d5e75802   Mark Rustad   ipc: resolve shad...
705
  			err2 = put_compat_shmid_ds(&sem64, uptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  		if (err2)
  			err = -EFAULT;
  		break;
  
  	case SHM_INFO:
  		p = compat_alloc_user_space(sizeof(struct shm_info));
  		err = sys_shmctl(first, second, p);
  		if (err < 0)
  			break;
  		err2 = put_compat_shm_info(p, uptr);
  		if (err2)
  			err = -EFAULT;
  		break;
  
  	default:
  		err = -EINVAL;
  		break;
  	}
  	return err;
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
726
727
728
  COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
  		       unsigned, nsops,
  		       const struct compat_timespec __user *, timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  {
81993e81a   H. Peter Anvin   compat: Get rid o...
730
731
732
  	struct timespec __user *ts64;
  	if (compat_convert_timespec(&ts64, timeout))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
  	return sys_semtimedop(semid, tsems, nsops, ts64);
  }