Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sys_ia32.c
Go to the documentation of this file.
1 /*
2  * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
3  * sys_sparc32
4  *
5  * Copyright (C) 2000 VA Linux Co
6  * Copyright (C) 2000 Don Dugger <[email protected]>
7  * Copyright (C) 1999 Arun Sharma <[email protected]>
8  * Copyright (C) 1997,1998 Jakub Jelinek ([email protected])
9  * Copyright (C) 1997 David S. Miller ([email protected])
10  * Copyright (C) 2000 Hewlett-Packard Co.
11  * Copyright (C) 2000 David Mosberger-Tang <[email protected]>
12  * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
13  *
14  * These routines maintain argument size conversion between 32bit and 64bit
15  * environment. In 2.5 most of this should be moved to a generic directory.
16  *
17  * This file assumes that there is a hole at the end of user address space.
18  *
19  * Some of the functions are LE specific currently. These are
20  * hopefully all marked. This should be fixed.
21  */
22 
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/fs.h>
26 #include <linux/file.h>
27 #include <linux/signal.h>
28 #include <linux/syscalls.h>
29 #include <linux/times.h>
30 #include <linux/utsname.h>
31 #include <linux/mm.h>
32 #include <linux/uio.h>
33 #include <linux/poll.h>
34 #include <linux/personality.h>
35 #include <linux/stat.h>
36 #include <linux/rwsem.h>
37 #include <linux/compat.h>
38 #include <linux/vfs.h>
39 #include <linux/ptrace.h>
40 #include <linux/highuid.h>
41 #include <linux/sysctl.h>
42 #include <linux/slab.h>
43 #include <asm/mman.h>
44 #include <asm/types.h>
45 #include <asm/uaccess.h>
46 #include <linux/atomic.h>
47 #include <asm/vgtod.h>
48 #include <asm/sys_ia32.h>
49 
50 #define AA(__x) ((unsigned long)(__x))
51 
52 
53 asmlinkage long sys32_truncate64(const char __user *filename,
54  unsigned long offset_low,
55  unsigned long offset_high)
56 {
57  return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
58 }
59 
60 asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low,
61  unsigned long offset_high)
62 {
63  return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
64 }
65 
66 /*
67  * Another set for IA32/LFS -- x86_64 struct stat is different due to
68  * support for 64bit inode numbers.
69  */
70 static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
71 {
72  typeof(ubuf->st_uid) uid = 0;
73  typeof(ubuf->st_gid) gid = 0;
75  SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid));
77  __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
78  __put_user(stat->ino, &ubuf->__st_ino) ||
79  __put_user(stat->ino, &ubuf->st_ino) ||
80  __put_user(stat->mode, &ubuf->st_mode) ||
81  __put_user(stat->nlink, &ubuf->st_nlink) ||
82  __put_user(uid, &ubuf->st_uid) ||
83  __put_user(gid, &ubuf->st_gid) ||
84  __put_user(huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
85  __put_user(stat->size, &ubuf->st_size) ||
86  __put_user(stat->atime.tv_sec, &ubuf->st_atime) ||
87  __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
88  __put_user(stat->mtime.tv_sec, &ubuf->st_mtime) ||
89  __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
90  __put_user(stat->ctime.tv_sec, &ubuf->st_ctime) ||
91  __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
92  __put_user(stat->blksize, &ubuf->st_blksize) ||
93  __put_user(stat->blocks, &ubuf->st_blocks))
94  return -EFAULT;
95  return 0;
96 }
97 
99  struct stat64 __user *statbuf)
100 {
101  struct kstat stat;
102  int ret = vfs_stat(filename, &stat);
103 
104  if (!ret)
105  ret = cp_stat64(statbuf, &stat);
106  return ret;
107 }
108 
109 asmlinkage long sys32_lstat64(const char __user *filename,
110  struct stat64 __user *statbuf)
111 {
112  struct kstat stat;
113  int ret = vfs_lstat(filename, &stat);
114  if (!ret)
115  ret = cp_stat64(statbuf, &stat);
116  return ret;
117 }
118 
119 asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
120 {
121  struct kstat stat;
122  int ret = vfs_fstat(fd, &stat);
123  if (!ret)
124  ret = cp_stat64(statbuf, &stat);
125  return ret;
126 }
127 
128 asmlinkage long sys32_fstatat(unsigned int dfd, const char __user *filename,
129  struct stat64 __user *statbuf, int flag)
130 {
131  struct kstat stat;
132  int error;
133 
134  error = vfs_fstatat(dfd, filename, &stat, flag);
135  if (error)
136  return error;
137  return cp_stat64(statbuf, &stat);
138 }
139 
140 /*
141  * Linux/i386 didn't use to be able to handle more than
142  * 4 system call parameters, so these system calls used a memory
143  * block for parameter passing..
144  */
145 
147  unsigned int addr;
148  unsigned int len;
149  unsigned int prot;
150  unsigned int flags;
151  unsigned int fd;
152  unsigned int offset;
153 };
154 
156 {
157  struct mmap_arg_struct32 a;
158 
159  if (copy_from_user(&a, arg, sizeof(a)))
160  return -EFAULT;
161 
162  if (a.offset & ~PAGE_MASK)
163  return -EINVAL;
164 
165  return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
166  a.offset>>PAGE_SHIFT);
167 }
168 
169 asmlinkage long sys32_mprotect(unsigned long start, size_t len,
170  unsigned long prot)
171 {
172  return sys_mprotect(start, len, prot);
173 }
174 
175 asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
176  struct sigaction32 __user *oact,
177  unsigned int sigsetsize)
178 {
179  struct k_sigaction new_ka, old_ka;
180  int ret;
181  compat_sigset_t set32;
182 
183  /* XXX: Don't preclude handling different sized sigset_t's. */
184  if (sigsetsize != sizeof(compat_sigset_t))
185  return -EINVAL;
186 
187  if (act) {
188  compat_uptr_t handler, restorer;
189 
190  if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
191  __get_user(handler, &act->sa_handler) ||
192  __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
193  __get_user(restorer, &act->sa_restorer) ||
194  __copy_from_user(&set32, &act->sa_mask,
195  sizeof(compat_sigset_t)))
196  return -EFAULT;
197  new_ka.sa.sa_handler = compat_ptr(handler);
198  new_ka.sa.sa_restorer = compat_ptr(restorer);
199 
200  /*
201  * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
202  * than _NSIG_WORDS << 1
203  */
204  switch (_NSIG_WORDS) {
205  case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
206  | (((long)set32.sig[7]) << 32);
207  case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
208  | (((long)set32.sig[5]) << 32);
209  case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
210  | (((long)set32.sig[3]) << 32);
211  case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
212  | (((long)set32.sig[1]) << 32);
213  }
214  }
215 
216  ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
217 
218  if (!ret && oact) {
219  /*
220  * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
221  * than _NSIG_WORDS << 1
222  */
223  switch (_NSIG_WORDS) {
224  case 4:
225  set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
226  set32.sig[6] = old_ka.sa.sa_mask.sig[3];
227  case 3:
228  set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
229  set32.sig[4] = old_ka.sa.sa_mask.sig[2];
230  case 2:
231  set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
232  set32.sig[2] = old_ka.sa.sa_mask.sig[1];
233  case 1:
234  set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
235  set32.sig[0] = old_ka.sa.sa_mask.sig[0];
236  }
237  if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
238  __put_user(ptr_to_compat(old_ka.sa.sa_handler),
239  &oact->sa_handler) ||
240  __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
241  &oact->sa_restorer) ||
242  __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
243  __copy_to_user(&oact->sa_mask, &set32,
244  sizeof(compat_sigset_t)))
245  return -EFAULT;
246  }
247 
248  return ret;
249 }
250 
251 asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
252  struct old_sigaction32 __user *oact)
253 {
254  struct k_sigaction new_ka, old_ka;
255  int ret;
256 
257  if (act) {
259  compat_uptr_t handler, restorer;
260 
261  if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
262  __get_user(handler, &act->sa_handler) ||
263  __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
264  __get_user(restorer, &act->sa_restorer) ||
265  __get_user(mask, &act->sa_mask))
266  return -EFAULT;
267 
268  new_ka.sa.sa_handler = compat_ptr(handler);
269  new_ka.sa.sa_restorer = compat_ptr(restorer);
270 
271  siginitset(&new_ka.sa.sa_mask, mask);
272  }
273 
274  ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
275 
276  if (!ret && oact) {
277  if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
278  __put_user(ptr_to_compat(old_ka.sa.sa_handler),
279  &oact->sa_handler) ||
280  __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
281  &oact->sa_restorer) ||
282  __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
283  __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
284  return -EFAULT;
285  }
286 
287  return ret;
288 }
289 
290 asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
291  int options)
292 {
293  return compat_sys_wait4(pid, stat_addr, options, NULL);
294 }
295 
296 /* 32-bit timeval and related flotsam. */
297 
299  struct compat_timespec __user *interval)
300 {
301  struct timespec t;
302  int ret;
303  mm_segment_t old_fs = get_fs();
304 
305  set_fs(KERNEL_DS);
306  ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
307  set_fs(old_fs);
308  if (put_compat_timespec(&t, interval))
309  return -EFAULT;
310  return ret;
311 }
312 
313 asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
314  compat_size_t sigsetsize)
315 {
316  sigset_t s;
317  compat_sigset_t s32;
318  int ret;
319  mm_segment_t old_fs = get_fs();
320 
321  set_fs(KERNEL_DS);
322  ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
323  set_fs(old_fs);
324  if (!ret) {
325  switch (_NSIG_WORDS) {
326  case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
327  case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
328  case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
329  case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
330  }
331  if (copy_to_user(set, &s32, sizeof(compat_sigset_t)))
332  return -EFAULT;
333  }
334  return ret;
335 }
336 
338  compat_siginfo_t __user *uinfo)
339 {
340  siginfo_t info;
341  int ret;
342  mm_segment_t old_fs = get_fs();
343 
344  if (copy_siginfo_from_user32(&info, uinfo))
345  return -EFAULT;
346  set_fs(KERNEL_DS);
347  ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
348  set_fs(old_fs);
349  return ret;
350 }
351 
352 /* warning: next two assume little endian */
353 asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
354  u32 poslo, u32 poshi)
355 {
356  return sys_pread64(fd, ubuf, count,
357  ((loff_t)AA(poshi) << 32) | AA(poslo));
358 }
359 
360 asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
361  u32 count, u32 poslo, u32 poshi)
362 {
363  return sys_pwrite64(fd, ubuf, count,
364  ((loff_t)AA(poshi) << 32) | AA(poslo));
365 }
366 
367 
368 asmlinkage long sys32_sendfile(int out_fd, int in_fd,
369  compat_off_t __user *offset, s32 count)
370 {
371  mm_segment_t old_fs = get_fs();
372  int ret;
373  off_t of;
374 
375  if (offset && get_user(of, offset))
376  return -EFAULT;
377 
378  set_fs(KERNEL_DS);
379  ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
380  count);
381  set_fs(old_fs);
382 
383  if (offset && put_user(of, offset))
384  return -EFAULT;
385  return ret;
386 }
387 
388 asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
389  struct pt_regs *regs)
390 {
391  void __user *parent_tid = (void __user *)regs->dx;
392  void __user *child_tid = (void __user *)regs->di;
393 
394  if (!newsp)
395  newsp = regs->sp;
396  return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
397 }
398 
399 /*
400  * Some system calls that need sign extended arguments. This could be
401  * done by a generic wrapper.
402  */
403 long sys32_lseek(unsigned int fd, int offset, unsigned int whence)
404 {
405  return sys_lseek(fd, offset, whence);
406 }
407 
408 long sys32_kill(int pid, int sig)
409 {
410  return sys_kill(pid, sig);
411 }
412 
414  __u32 len_low, __u32 len_high, int advice)
415 {
416  return sys_fadvise64_64(fd,
417  (((u64)offset_high)<<32) | offset_low,
418  (((u64)len_high)<<32) | len_low,
419  advice);
420 }
421 
423 {
424  struct task_struct *me = current;
425  static char lastcomm[sizeof(me->comm)];
426 
427  if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
429  "%s: vm86 mode not supported on 64 bit kernel\n",
430  me->comm);
431  strncpy(lastcomm, me->comm, sizeof(lastcomm));
432  }
433  return -ENOSYS;
434 }
435 
437  char __user *buf, size_t len)
438 {
439  return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
440 }
441 
442 asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
443  size_t count)
444 {
445  return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
446 }
447 
448 asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
449  unsigned n_low, unsigned n_hi, int flags)
450 {
451  return sys_sync_file_range(fd,
452  ((u64)off_hi << 32) | off_low,
453  ((u64)n_hi << 32) | n_low, flags);
454 }
455 
456 asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
457  size_t len, int advice)
458 {
459  return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
460  len, advice);
461 }
462 
463 asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
464  unsigned offset_hi, unsigned len_lo,
465  unsigned len_hi)
466 {
467  return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
468  ((u64)len_hi << 32) | len_lo);
469 }
470 
471 asmlinkage long sys32_fanotify_mark(int fanotify_fd, unsigned int flags,
472  u32 mask_lo, u32 mask_hi,
473  int fd, const char __user *pathname)
474 {
475  return sys_fanotify_mark(fanotify_fd, flags,
476  ((u64)mask_hi << 32) | mask_lo,
477  fd, pathname);
478 }