blob: 666bb6daa148e649d3156aea4b88c65e7c553b3e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/s390x/kernel/linux32.c
3 *
4 * S390 version
5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Gerhard Tonn (ton@de.ibm.com)
8 * Thomas Spatzier (tspat@de.ibm.com)
9 *
10 * Conversion between 31bit and 64bit native syscalls.
11 *
12 * Heavily inspired by the 32-bit Sparc compat code which is
13 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
14 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
15 *
16 */
17
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/kernel.h>
20#include <linux/sched.h>
21#include <linux/fs.h>
22#include <linux/mm.h>
23#include <linux/file.h>
24#include <linux/signal.h>
25#include <linux/resource.h>
26#include <linux/times.h>
27#include <linux/utsname.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/smp.h>
29#include <linux/smp_lock.h>
30#include <linux/sem.h>
31#include <linux/msg.h>
32#include <linux/shm.h>
33#include <linux/slab.h>
34#include <linux/uio.h>
35#include <linux/nfs_fs.h>
36#include <linux/quota.h>
37#include <linux/module.h>
38#include <linux/sunrpc/svc.h>
39#include <linux/nfsd/nfsd.h>
40#include <linux/nfsd/cache.h>
41#include <linux/nfsd/xdr.h>
42#include <linux/nfsd/syscall.h>
43#include <linux/poll.h>
44#include <linux/personality.h>
45#include <linux/stat.h>
46#include <linux/filter.h>
47#include <linux/highmem.h>
48#include <linux/highuid.h>
49#include <linux/mman.h>
50#include <linux/ipv6.h>
51#include <linux/in.h>
52#include <linux/icmpv6.h>
53#include <linux/syscalls.h>
54#include <linux/sysctl.h>
55#include <linux/binfmts.h>
Randy Dunlapa9415642006-01-11 12:17:48 -080056#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/compat.h>
58#include <linux/vfs.h>
59#include <linux/ptrace.h>
Martin Schwidefsky068e1b92005-07-13 01:10:46 -070060#include <linux/fadvise.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#include <asm/types.h>
63#include <asm/ipc.h>
64#include <asm/uaccess.h>
65#include <asm/semaphore.h>
66
67#include <net/scm.h>
68#include <net/sock.h>
69
70#include "compat_linux.h"
71
Gerald Schaeferc1821c22007-02-05 21:18:17 +010072long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
73 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
74 PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
75long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
76 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
77 PSW32_MASK_PSTATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* For this source file, we want overflow handling. */
80
81#undef high2lowuid
82#undef high2lowgid
83#undef low2highuid
84#undef low2highgid
85#undef SET_UID16
86#undef SET_GID16
87#undef NEW_TO_OLD_UID
88#undef NEW_TO_OLD_GID
89#undef SET_OLDSTAT_UID
90#undef SET_OLDSTAT_GID
91#undef SET_STAT_UID
92#undef SET_STAT_GID
93
94#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
95#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
96#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
97#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
98#define SET_UID16(var, uid) var = high2lowuid(uid)
99#define SET_GID16(var, gid) var = high2lowgid(gid)
100#define NEW_TO_OLD_UID(uid) high2lowuid(uid)
101#define NEW_TO_OLD_GID(gid) high2lowgid(gid)
102#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
103#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
104#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
105#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
106
Al Viro24954a12006-02-01 05:16:15 -0500107asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 return sys_chown(filename, low2highuid(user), low2highgid(group));
110}
111
Al Viro24954a12006-02-01 05:16:15 -0500112asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 return sys_lchown(filename, low2highuid(user), low2highgid(group));
115}
116
117asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
118{
119 return sys_fchown(fd, low2highuid(user), low2highgid(group));
120}
121
122asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
123{
124 return sys_setregid(low2highgid(rgid), low2highgid(egid));
125}
126
127asmlinkage long sys32_setgid16(u16 gid)
128{
129 return sys_setgid((gid_t)gid);
130}
131
132asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
133{
134 return sys_setreuid(low2highuid(ruid), low2highuid(euid));
135}
136
137asmlinkage long sys32_setuid16(u16 uid)
138{
139 return sys_setuid((uid_t)uid);
140}
141
142asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
143{
144 return sys_setresuid(low2highuid(ruid), low2highuid(euid),
145 low2highuid(suid));
146}
147
Al Viro24954a12006-02-01 05:16:15 -0500148asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
150 int retval;
151
152 if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
153 !(retval = put_user(high2lowuid(current->euid), euid)))
154 retval = put_user(high2lowuid(current->suid), suid);
155
156 return retval;
157}
158
159asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
160{
161 return sys_setresgid(low2highgid(rgid), low2highgid(egid),
162 low2highgid(sgid));
163}
164
Al Viro24954a12006-02-01 05:16:15 -0500165asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166{
167 int retval;
168
169 if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
170 !(retval = put_user(high2lowgid(current->egid), egid)))
171 retval = put_user(high2lowgid(current->sgid), sgid);
172
173 return retval;
174}
175
176asmlinkage long sys32_setfsuid16(u16 uid)
177{
178 return sys_setfsuid((uid_t)uid);
179}
180
181asmlinkage long sys32_setfsgid16(u16 gid)
182{
183 return sys_setfsgid((gid_t)gid);
184}
185
Al Viro24954a12006-02-01 05:16:15 -0500186static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 int i;
189 u16 group;
190
191 for (i = 0; i < group_info->ngroups; i++) {
192 group = (u16)GROUP_AT(group_info, i);
193 if (put_user(group, grouplist+i))
194 return -EFAULT;
195 }
196
197 return 0;
198}
199
Al Viro24954a12006-02-01 05:16:15 -0500200static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 int i;
203 u16 group;
204
205 for (i = 0; i < group_info->ngroups; i++) {
206 if (get_user(group, grouplist+i))
207 return -EFAULT;
208 GROUP_AT(group_info, i) = (gid_t)group;
209 }
210
211 return 0;
212}
213
Al Viro24954a12006-02-01 05:16:15 -0500214asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 int i;
217
218 if (gidsetsize < 0)
219 return -EINVAL;
220
221 get_group_info(current->group_info);
222 i = current->group_info->ngroups;
223 if (gidsetsize) {
224 if (i > gidsetsize) {
225 i = -EINVAL;
226 goto out;
227 }
228 if (groups16_to_user(grouplist, current->group_info)) {
229 i = -EFAULT;
230 goto out;
231 }
232 }
233out:
234 put_group_info(current->group_info);
235 return i;
236}
237
Al Viro24954a12006-02-01 05:16:15 -0500238asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 struct group_info *group_info;
241 int retval;
242
243 if (!capable(CAP_SETGID))
244 return -EPERM;
245 if ((unsigned)gidsetsize > NGROUPS_MAX)
246 return -EINVAL;
247
248 group_info = groups_alloc(gidsetsize);
249 if (!group_info)
250 return -ENOMEM;
251 retval = groups16_from_user(group_info, grouplist);
252 if (retval) {
253 put_group_info(group_info);
254 return retval;
255 }
256
257 retval = set_current_groups(group_info);
258 put_group_info(group_info);
259
260 return retval;
261}
262
263asmlinkage long sys32_getuid16(void)
264{
265 return high2lowuid(current->uid);
266}
267
268asmlinkage long sys32_geteuid16(void)
269{
270 return high2lowuid(current->euid);
271}
272
273asmlinkage long sys32_getgid16(void)
274{
275 return high2lowgid(current->gid);
276}
277
278asmlinkage long sys32_getegid16(void)
279{
280 return high2lowgid(current->egid);
281}
282
283/* 32-bit timeval and related flotsam. */
284
Al Viro24954a12006-02-01 05:16:15 -0500285static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Martin Schwidefskya63a4932006-01-06 00:19:09 -0800287 return (!access_ok(VERIFY_READ, o, sizeof(*o)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 (__get_user(o->tv_sec, &i->tv_sec) ||
289 __get_user(o->tv_usec, &i->tv_usec)));
290}
291
Al Viro24954a12006-02-01 05:16:15 -0500292static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
295 (__put_user(i->tv_sec, &o->tv_sec) ||
296 __put_user(i->tv_usec, &o->tv_usec)));
297}
298
299/*
300 * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
301 *
302 * This is really horribly ugly.
303 */
Cedric Le Goater1df23952006-10-18 18:30:41 +0200304#ifdef CONFIG_SYSVIPC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
306{
307 if (call >> 16) /* hack for backward compatibility */
308 return -EINVAL;
309
310 call &= 0xffff;
311
312 switch (call) {
313 case SEMTIMEDOP:
314 return compat_sys_semtimedop(first, compat_ptr(ptr),
315 second, compat_ptr(third));
316 case SEMOP:
317 /* struct sembuf is the same on 32 and 64bit :)) */
318 return sys_semtimedop(first, compat_ptr(ptr),
319 second, NULL);
320 case SEMGET:
321 return sys_semget(first, second, third);
322 case SEMCTL:
323 return compat_sys_semctl(first, second, third,
324 compat_ptr(ptr));
325 case MSGSND:
326 return compat_sys_msgsnd(first, second, third,
327 compat_ptr(ptr));
328 case MSGRCV:
329 return compat_sys_msgrcv(first, second, 0, third,
330 0, compat_ptr(ptr));
331 case MSGGET:
332 return sys_msgget((key_t) first, second);
333 case MSGCTL:
334 return compat_sys_msgctl(first, second, compat_ptr(ptr));
335 case SHMAT:
336 return compat_sys_shmat(first, second, third,
337 0, compat_ptr(ptr));
338 case SHMDT:
339 return sys_shmdt(compat_ptr(ptr));
340 case SHMGET:
341 return sys_shmget(first, (unsigned)second, third);
342 case SHMCTL:
343 return compat_sys_shmctl(first, second, compat_ptr(ptr));
344 }
345
346 return -ENOSYS;
347}
Cedric Le Goater1df23952006-10-18 18:30:41 +0200348#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Al Viro24954a12006-02-01 05:16:15 -0500350asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
352 if ((int)high < 0)
353 return -EINVAL;
354 else
355 return sys_truncate(path, (high << 32) | low);
356}
357
358asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
359{
360 if ((int)high < 0)
361 return -EINVAL;
362 else
363 return sys_ftruncate(fd, (high << 32) | low);
364}
365
Al Viro24954a12006-02-01 05:16:15 -0500366int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
David Howellsafefdbb2006-10-03 01:13:46 -0700368 compat_ino_t ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 int err;
370
371 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
372 return -EOVERFLOW;
373
David Howellsafefdbb2006-10-03 01:13:46 -0700374 ino = stat->ino;
375 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
376 return -EOVERFLOW;
377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
379 err |= put_user(stat->ino, &statbuf->st_ino);
380 err |= put_user(stat->mode, &statbuf->st_mode);
381 err |= put_user(stat->nlink, &statbuf->st_nlink);
382 err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
383 err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
384 err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
385 err |= put_user(stat->size, &statbuf->st_size);
386 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
387 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
388 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
389 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
390 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
391 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
392 err |= put_user(stat->blksize, &statbuf->st_blksize);
393 err |= put_user(stat->blocks, &statbuf->st_blocks);
394/* fixme
395 err |= put_user(0, &statbuf->__unused4[0]);
396 err |= put_user(0, &statbuf->__unused4[1]);
397*/
398 return err;
399}
400
401struct sysinfo32 {
402 s32 uptime;
403 u32 loads[3];
404 u32 totalram;
405 u32 freeram;
406 u32 sharedram;
407 u32 bufferram;
408 u32 totalswap;
409 u32 freeswap;
410 unsigned short procs;
411 unsigned short pads;
412 u32 totalhigh;
413 u32 freehigh;
414 unsigned int mem_unit;
415 char _f[8];
416};
417
418asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
419{
420 struct sysinfo s;
421 int ret, err;
422 mm_segment_t old_fs = get_fs ();
423
424 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100425 ret = sys_sysinfo((struct sysinfo __force __user *) &s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 set_fs (old_fs);
427 err = put_user (s.uptime, &info->uptime);
428 err |= __put_user (s.loads[0], &info->loads[0]);
429 err |= __put_user (s.loads[1], &info->loads[1]);
430 err |= __put_user (s.loads[2], &info->loads[2]);
431 err |= __put_user (s.totalram, &info->totalram);
432 err |= __put_user (s.freeram, &info->freeram);
433 err |= __put_user (s.sharedram, &info->sharedram);
434 err |= __put_user (s.bufferram, &info->bufferram);
435 err |= __put_user (s.totalswap, &info->totalswap);
436 err |= __put_user (s.freeswap, &info->freeswap);
437 err |= __put_user (s.procs, &info->procs);
438 err |= __put_user (s.totalhigh, &info->totalhigh);
439 err |= __put_user (s.freehigh, &info->freehigh);
440 err |= __put_user (s.mem_unit, &info->mem_unit);
441 if (err)
442 return -EFAULT;
443 return ret;
444}
445
446asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
447 struct compat_timespec __user *interval)
448{
449 struct timespec t;
450 int ret;
451 mm_segment_t old_fs = get_fs ();
452
453 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100454 ret = sys_sched_rr_get_interval(pid,
455 (struct timespec __force __user *) &t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 set_fs (old_fs);
457 if (put_compat_timespec(&t, interval))
458 return -EFAULT;
459 return ret;
460}
461
462asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
463 compat_sigset_t __user *oset, size_t sigsetsize)
464{
465 sigset_t s;
466 compat_sigset_t s32;
467 int ret;
468 mm_segment_t old_fs = get_fs();
469
470 if (set) {
471 if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
472 return -EFAULT;
473 switch (_NSIG_WORDS) {
474 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
475 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
476 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
477 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
478 }
479 }
480 set_fs (KERNEL_DS);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200481 ret = sys_rt_sigprocmask(how,
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100482 set ? (sigset_t __force __user *) &s : NULL,
483 oset ? (sigset_t __force __user *) &s : NULL,
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200484 sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 set_fs (old_fs);
486 if (ret) return ret;
487 if (oset) {
488 switch (_NSIG_WORDS) {
489 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
490 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
491 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
492 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
493 }
494 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
495 return -EFAULT;
496 }
497 return 0;
498}
499
500asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
501 size_t sigsetsize)
502{
503 sigset_t s;
504 compat_sigset_t s32;
505 int ret;
506 mm_segment_t old_fs = get_fs();
507
508 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100509 ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 set_fs (old_fs);
511 if (!ret) {
512 switch (_NSIG_WORDS) {
513 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
514 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
515 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
516 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
517 }
518 if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
519 return -EFAULT;
520 }
521 return ret;
522}
523
524asmlinkage long
525sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
526{
527 siginfo_t info;
528 int ret;
529 mm_segment_t old_fs = get_fs();
530
531 if (copy_siginfo_from_user32(&info, uinfo))
532 return -EFAULT;
533 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100534 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 set_fs (old_fs);
536 return ret;
537}
538
539/*
540 * sys32_execve() executes a new program after the asm stub has set
541 * things up for us. This should basically do what I want it to.
542 */
543asmlinkage long
544sys32_execve(struct pt_regs regs)
545{
546 int error;
547 char * filename;
548
549 filename = getname(compat_ptr(regs.orig_gpr2));
550 error = PTR_ERR(filename);
551 if (IS_ERR(filename))
552 goto out;
553 error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
554 compat_ptr(regs.gprs[4]), &regs);
555 if (error == 0)
556 {
557 task_lock(current);
558 current->ptrace &= ~PT_DTRACE;
559 task_unlock(current);
560 current->thread.fp_regs.fpc=0;
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200561 asm volatile("sfpc %0,0" : : "d" (0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
563 putname(filename);
564out:
565 return error;
566}
567
568
569#ifdef CONFIG_MODULES
570
571asmlinkage long
572sys32_init_module(void __user *umod, unsigned long len,
573 const char __user *uargs)
574{
575 return sys_init_module(umod, len, uargs);
576}
577
578asmlinkage long
579sys32_delete_module(const char __user *name_user, unsigned int flags)
580{
581 return sys_delete_module(name_user, flags);
582}
583
584#else /* CONFIG_MODULES */
585
586asmlinkage long
587sys32_init_module(void __user *umod, unsigned long len,
588 const char __user *uargs)
589{
590 return -ENOSYS;
591}
592
593asmlinkage long
594sys32_delete_module(const char __user *name_user, unsigned int flags)
595{
596 return -ENOSYS;
597}
598
599#endif /* CONFIG_MODULES */
600
601/* Translations due to time_t size differences. Which affects all
602 sorts of things, like timeval and itimerval. */
603
604extern struct timezone sys_tz;
605
Al Viro24954a12006-02-01 05:16:15 -0500606asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 if (tv) {
609 struct timeval ktv;
610 do_gettimeofday(&ktv);
611 if (put_tv32(tv, &ktv))
612 return -EFAULT;
613 }
614 if (tz) {
615 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
616 return -EFAULT;
617 }
618 return 0;
619}
620
Al Viro24954a12006-02-01 05:16:15 -0500621static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 long usec;
624
625 if (!access_ok(VERIFY_READ, i, sizeof(*i)))
626 return -EFAULT;
627 if (__get_user(o->tv_sec, &i->tv_sec))
628 return -EFAULT;
629 if (__get_user(usec, &i->tv_usec))
630 return -EFAULT;
631 o->tv_nsec = usec * 1000;
632 return 0;
633}
634
Al Viro24954a12006-02-01 05:16:15 -0500635asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
637 struct timespec kts;
638 struct timezone ktz;
639
640 if (tv) {
641 if (get_ts32(&kts, tv))
642 return -EFAULT;
643 }
644 if (tz) {
645 if (copy_from_user(&ktz, tz, sizeof(ktz)))
646 return -EFAULT;
647 }
648
649 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
650}
651
652/* These are here just in case some old sparc32 binary calls it. */
653asmlinkage long sys32_pause(void)
654{
655 current->state = TASK_INTERRUPTIBLE;
656 schedule();
657 return -ERESTARTNOHAND;
658}
659
Al Viro24954a12006-02-01 05:16:15 -0500660asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 size_t count, u32 poshi, u32 poslo)
662{
663 if ((compat_ssize_t) count < 0)
664 return -EINVAL;
665 return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
666}
667
Al Viro24954a12006-02-01 05:16:15 -0500668asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 size_t count, u32 poshi, u32 poslo)
670{
671 if ((compat_ssize_t) count < 0)
672 return -EINVAL;
673 return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
674}
675
676asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
677{
678 return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
679}
680
Al Viro24954a12006-02-01 05:16:15 -0500681asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 mm_segment_t old_fs = get_fs();
684 int ret;
685 off_t of;
686
687 if (offset && get_user(of, offset))
688 return -EFAULT;
689
690 set_fs(KERNEL_DS);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200691 ret = sys_sendfile(out_fd, in_fd,
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100692 offset ? (off_t __force __user *) &of : NULL, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 set_fs(old_fs);
694
Tsuneo.Yoshioka@f-secure.com83b942b2005-09-12 18:49:24 +0200695 if (offset && put_user(of, offset))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return -EFAULT;
697
698 return ret;
699}
700
701asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
Al Viro24954a12006-02-01 05:16:15 -0500702 compat_loff_t __user *offset, s32 count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 mm_segment_t old_fs = get_fs();
705 int ret;
706 loff_t lof;
707
708 if (offset && get_user(lof, offset))
709 return -EFAULT;
710
711 set_fs(KERNEL_DS);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200712 ret = sys_sendfile64(out_fd, in_fd,
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100713 offset ? (loff_t __force __user *) &lof : NULL,
714 count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 set_fs(old_fs);
716
717 if (offset && put_user(lof, offset))
718 return -EFAULT;
719
720 return ret;
721}
722
Eric W. Biedermanb89a8172006-09-27 01:51:04 -0700723#ifdef CONFIG_SYSCTL_SYSCALL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724struct __sysctl_args32 {
725 u32 name;
726 int nlen;
727 u32 oldval;
728 u32 oldlenp;
729 u32 newval;
730 u32 newlen;
731 u32 __unused[4];
732};
733
Al Viro24954a12006-02-01 05:16:15 -0500734asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
736 struct __sysctl_args32 tmp;
737 int error;
Al Viro24954a12006-02-01 05:16:15 -0500738 size_t oldlen;
739 size_t __user *oldlenp = NULL;
740 unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 if (copy_from_user(&tmp, args, sizeof(tmp)))
743 return -EFAULT;
744
745 if (tmp.oldval && tmp.oldlenp) {
746 /* Duh, this is ugly and might not work if sysctl_args
747 is in read-only memory, but do_sysctl does indirectly
748 a lot of uaccess in both directions and we'd have to
749 basically copy the whole sysctl.c here, and
750 glibc's __sysctl uses rw memory for the structure
751 anyway. */
Al Viro24954a12006-02-01 05:16:15 -0500752 if (get_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)) ||
753 put_user(oldlen, (size_t __user *)addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 return -EFAULT;
Al Viro24954a12006-02-01 05:16:15 -0500755 oldlenp = (size_t __user *)addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
757
758 lock_kernel();
Al Viro24954a12006-02-01 05:16:15 -0500759 error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, compat_ptr(tmp.oldval),
760 oldlenp, compat_ptr(tmp.newval), tmp.newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 unlock_kernel();
762 if (oldlenp) {
763 if (!error) {
Al Viro24954a12006-02-01 05:16:15 -0500764 if (get_user(oldlen, (size_t __user *)addr) ||
765 put_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 error = -EFAULT;
767 }
Heiko Carstens12bae232006-10-27 12:39:22 +0200768 if (copy_to_user(args->__unused, tmp.__unused,
769 sizeof(tmp.__unused)))
770 error = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 return error;
773}
774#endif
775
776struct stat64_emu31 {
777 unsigned long long st_dev;
778 unsigned int __pad1;
779#define STAT64_HAS_BROKEN_ST_INO 1
780 u32 __st_ino;
781 unsigned int st_mode;
782 unsigned int st_nlink;
783 u32 st_uid;
784 u32 st_gid;
785 unsigned long long st_rdev;
786 unsigned int __pad3;
787 long st_size;
788 u32 st_blksize;
789 unsigned char __pad4[4];
790 u32 __pad5; /* future possible st_blocks high bits */
791 u32 st_blocks; /* Number 512-byte blocks allocated. */
792 u32 st_atime;
793 u32 __pad6;
794 u32 st_mtime;
795 u32 __pad7;
796 u32 st_ctime;
797 u32 __pad8; /* will be high 32 bits of ctime someday */
798 unsigned long st_ino;
799};
800
Al Viro24954a12006-02-01 05:16:15 -0500801static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct stat64_emu31 tmp;
804
805 memset(&tmp, 0, sizeof(tmp));
806
807 tmp.st_dev = huge_encode_dev(stat->dev);
808 tmp.st_ino = stat->ino;
809 tmp.__st_ino = (u32)stat->ino;
810 tmp.st_mode = stat->mode;
811 tmp.st_nlink = (unsigned int)stat->nlink;
812 tmp.st_uid = stat->uid;
813 tmp.st_gid = stat->gid;
814 tmp.st_rdev = huge_encode_dev(stat->rdev);
815 tmp.st_size = stat->size;
816 tmp.st_blksize = (u32)stat->blksize;
817 tmp.st_blocks = (u32)stat->blocks;
818 tmp.st_atime = (u32)stat->atime.tv_sec;
819 tmp.st_mtime = (u32)stat->mtime.tv_sec;
820 tmp.st_ctime = (u32)stat->ctime.tv_sec;
821
822 return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
823}
824
Al Viro24954a12006-02-01 05:16:15 -0500825asmlinkage long sys32_stat64(char __user * filename, struct stat64_emu31 __user * statbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
827 struct kstat stat;
828 int ret = vfs_stat(filename, &stat);
829 if (!ret)
830 ret = cp_stat64(statbuf, &stat);
831 return ret;
832}
833
Al Viro24954a12006-02-01 05:16:15 -0500834asmlinkage long sys32_lstat64(char __user * filename, struct stat64_emu31 __user * statbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835{
836 struct kstat stat;
837 int ret = vfs_lstat(filename, &stat);
838 if (!ret)
839 ret = cp_stat64(statbuf, &stat);
840 return ret;
841}
842
Al Viro24954a12006-02-01 05:16:15 -0500843asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
845 struct kstat stat;
846 int ret = vfs_fstat(fd, &stat);
847 if (!ret)
848 ret = cp_stat64(statbuf, &stat);
849 return ret;
850}
851
Heiko Carstensed3d0212006-02-17 13:52:50 -0800852asmlinkage long sys32_fstatat64(unsigned int dfd, char __user *filename,
853 struct stat64_emu31 __user* statbuf, int flag)
Heiko Carstens19bf9cb2006-02-12 12:35:03 +0100854{
855 struct kstat stat;
856 int error = -EINVAL;
857
858 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
859 goto out;
860
861 if (flag & AT_SYMLINK_NOFOLLOW)
862 error = vfs_lstat_fd(dfd, filename, &stat);
863 else
864 error = vfs_stat_fd(dfd, filename, &stat);
865
866 if (!error)
867 error = cp_stat64(statbuf, &stat);
868out:
869 return error;
870}
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872/*
873 * Linux/i386 didn't use to be able to handle more than
874 * 4 system call parameters, so these system calls used a memory
875 * block for parameter passing..
876 */
877
878struct mmap_arg_struct_emu31 {
879 u32 addr;
880 u32 len;
881 u32 prot;
882 u32 flags;
883 u32 fd;
884 u32 offset;
885};
886
887/* common code for old and new mmaps */
888static inline long do_mmap2(
889 unsigned long addr, unsigned long len,
890 unsigned long prot, unsigned long flags,
891 unsigned long fd, unsigned long pgoff)
892{
893 struct file * file = NULL;
894 unsigned long error = -EBADF;
895
896 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
897 if (!(flags & MAP_ANONYMOUS)) {
898 file = fget(fd);
899 if (!file)
900 goto out;
901 }
902
903 down_write(&current->mm->mmap_sem);
904 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
905 if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
906 /* Result is out of bounds. */
907 do_munmap(current->mm, addr, len);
908 error = -ENOMEM;
909 }
910 up_write(&current->mm->mmap_sem);
911
912 if (file)
913 fput(file);
914out:
915 return error;
916}
917
918
919asmlinkage unsigned long
Al Viro24954a12006-02-01 05:16:15 -0500920old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
922 struct mmap_arg_struct_emu31 a;
923 int error = -EFAULT;
924
925 if (copy_from_user(&a, arg, sizeof(a)))
926 goto out;
927
928 error = -EINVAL;
929 if (a.offset & ~PAGE_MASK)
930 goto out;
931
932 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
933out:
934 return error;
935}
936
937asmlinkage long
Al Viro24954a12006-02-01 05:16:15 -0500938sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939{
940 struct mmap_arg_struct_emu31 a;
941 int error = -EFAULT;
942
943 if (copy_from_user(&a, arg, sizeof(a)))
944 goto out;
945 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
946out:
947 return error;
948}
949
Al Viro24954a12006-02-01 05:16:15 -0500950asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951{
952 if ((compat_ssize_t) count < 0)
953 return -EINVAL;
954
955 return sys_read(fd, buf, count);
956}
957
Al Viro24954a12006-02-01 05:16:15 -0500958asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 if ((compat_ssize_t) count < 0)
961 return -EINVAL;
962
963 return sys_write(fd, buf, count);
964}
965
966asmlinkage long sys32_clone(struct pt_regs regs)
967{
968 unsigned long clone_flags;
969 unsigned long newsp;
Al Viro24954a12006-02-01 05:16:15 -0500970 int __user *parent_tidptr, *child_tidptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 clone_flags = regs.gprs[3] & 0xffffffffUL;
973 newsp = regs.orig_gpr2 & 0x7fffffffUL;
Al Viro24954a12006-02-01 05:16:15 -0500974 parent_tidptr = compat_ptr(regs.gprs[4]);
975 child_tidptr = compat_ptr(regs.gprs[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (!newsp)
977 newsp = regs.gprs[15];
978 return do_fork(clone_flags, newsp, &regs, 0,
979 parent_tidptr, child_tidptr);
980}
981
982/*
Martin Schwidefsky068e1b92005-07-13 01:10:46 -0700983 * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64.
984 * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE}
985 * because the 31 bit values differ from the 64 bit values.
986 */
987
988asmlinkage long
989sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
990{
991 if (advise == 4)
992 advise = POSIX_FADV_DONTNEED;
993 else if (advise == 5)
994 advise = POSIX_FADV_NOREUSE;
995 return sys_fadvise64(fd, offset, len, advise);
996}
997
998struct fadvise64_64_args {
999 int fd;
1000 long long offset;
1001 long long len;
1002 int advice;
1003};
1004
1005asmlinkage long
1006sys32_fadvise64_64(struct fadvise64_64_args __user *args)
1007{
1008 struct fadvise64_64_args a;
1009
1010 if ( copy_from_user(&a, args, sizeof(a)) )
1011 return -EFAULT;
1012 if (a.advice == 4)
1013 a.advice = POSIX_FADV_DONTNEED;
1014 else if (a.advice == 5)
1015 a.advice = POSIX_FADV_NOREUSE;
1016 return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
1017}