linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / x86_64 / ia32 / sys_ia32.c
index 73514ae..f3d4615 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/highuid.h>
 #include <linux/vmalloc.h>
+#include <linux/fsnotify.h>
 #include <linux/vs_cvirt.h>
 #include <asm/mman.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-#include <asm/ipc.h>
 #include <asm/atomic.h>
 #include <asm/ldt.h>
 
 #include <net/sock.h>
 #include <asm/ia32.h>
 
-#define A(__x)         ((unsigned long)(__x))
 #define AA(__x)                ((unsigned long)(__x))
-#define ROUND_UP(x,a)  ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
 
 int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
 {
@@ -89,7 +86,7 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
                return -EOVERFLOW;
        if (kbuf->size >= 0x7fffffff)
                return -EOVERFLOW;
-       if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
+       if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
            __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
            __put_user (kbuf->ino, &ubuf->st_ino) ||
            __put_user (kbuf->mode, &ubuf->st_mode) ||
@@ -132,7 +129,7 @@ cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
        typeof(ubuf->st_gid) gid = 0;
        SET_UID(uid, stat->uid);
        SET_GID(gid, stat->gid);
-       if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
+       if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
            __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
            __put_user (stat->ino, &ubuf->__st_ino) ||
            __put_user (stat->ino, &ubuf->st_ino) ||
@@ -184,6 +181,28 @@ sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
        return ret;
 }
 
+asmlinkage long
+sys32_fstatat(unsigned int dfd, char __user *filename,
+             struct stat64 __user* statbuf, int flag)
+{
+       struct kstat stat;
+       int error = -EINVAL;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       if (flag & AT_SYMLINK_NOFOLLOW)
+               error = vfs_lstat_fd(dfd, filename, &stat);
+       else
+               error = vfs_stat_fd(dfd, filename, &stat);
+
+       if (!error)
+               error = cp_stat64(statbuf, &stat);
+
+out:
+       return error;
+}
+
 /*
  * Linux/i386 didn't use to be able to handle more than
  * 4 system call parameters, so these system calls used a memory
@@ -213,13 +232,6 @@ sys32_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                return -EINVAL; 
 
-       if (a.flags & MAP_FIXED) {
-               if (a.len > IA32_PAGE_OFFSET)
-                       return -EINVAL;
-               if (a.addr > IA32_PAGE_OFFSET - a.len)
-                       return -ENOMEM;
-       }
-
        if (!(a.flags & MAP_ANONYMOUS)) {
                file = fget(a.fd);
                if (!file)
@@ -237,79 +249,12 @@ sys32_mmap(struct mmap_arg_struct __user *arg)
        return retval;
 }
 
-asmlinkage long
-sys32_munmap(unsigned long start, unsigned long len)
-{
-       if ((start + len) > IA32_PAGE_OFFSET)
-               return -EINVAL;
-       return sys_munmap(start, len);
-}
-
 asmlinkage long 
 sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
-       if ((start + PAGE_ALIGN(len)) >> 32)
-               return -ENOMEM;
        return sys_mprotect(start,len,prot); 
 }
 
-sys32_brk(unsigned long brk)
-{
-       if (brk > IA32_PAGE_OFFSET)
-               return -EINVAL;
-       return sys_brk(brk);
-}
-
-extern unsigned long do_mremap(unsigned long addr,
-   unsigned long old_len, unsigned long new_len,
-   unsigned long flags, unsigned long new_addr);
-
-asmlinkage unsigned long sys32_mremap(unsigned long addr,
-   unsigned long old_len, unsigned long new_len,
-   unsigned long flags, unsigned long new_addr)
-{
-       struct vm_area_struct *vma;
-       unsigned long ret = -EINVAL;
-
-       if (old_len > IA32_PAGE_OFFSET || new_len > IA32_PAGE_OFFSET)
-               goto out;
-       if (addr > IA32_PAGE_OFFSET - old_len)
-               goto out;
-       down_write(&current->mm->mmap_sem);
-       if (flags & MREMAP_FIXED) {
-               if (new_addr > IA32_PAGE_OFFSET - new_len)
-                       goto out_sem;
-       } else if (addr > IA32_PAGE_OFFSET - new_len) {
-               unsigned long map_flags = 0;
-               struct file *file = NULL;
-
-               ret = -ENOMEM;
-               if (!(flags & MREMAP_MAYMOVE))
-                       goto out_sem;
-
-               vma = find_vma(current->mm, addr);
-               if (vma) {
-                       if (vma->vm_flags & VM_SHARED)
-                               map_flags |= MAP_SHARED;
-                       file = vma->vm_file;
-               }
-
-               /* MREMAP_FIXED checked above. */
-               new_addr = get_unmapped_area(file, addr, new_len,
-                       vma ? vma->vm_pgoff : 0, map_flags);
-               ret = new_addr;
-               if (new_addr & ~PAGE_MASK)
-                       goto out_sem;
-               flags |= MREMAP_FIXED;
-       }
-       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-out_sem:
-       up_write(&current->mm->mmap_sem);
-out:
-return ret;
-}
-
-
 asmlinkage long
 sys32_pipe(int __user *fd)
 {
@@ -340,7 +285,7 @@ sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
        if (act) {
                compat_uptr_t handler, restorer;
 
-               if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
                    __get_user(handler, &act->sa_handler) ||
                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
                    __get_user(restorer, &act->sa_restorer)||
@@ -379,9 +324,9 @@ sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
                        set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
                        set32.sig[0] = old_ka.sa.sa_mask.sig[0];
                }
-               if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                   __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
+                   __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
                    __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t)))
                        return -EFAULT;
@@ -400,7 +345,7 @@ sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigacti
                compat_old_sigset_t mask;
                compat_uptr_t handler, restorer;
 
-               if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
                    __get_user(handler, &act->sa_handler) ||
                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
                    __get_user(restorer, &act->sa_restorer) ||
@@ -416,9 +361,9 @@ sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigacti
         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
        if (!ret && oact) {
-               if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                   __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
+                   __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
                    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
                        return -EFAULT;
@@ -567,26 +512,6 @@ sys32_old_select(struct sel_arg_struct __user *arg)
                                 compat_ptr(a.exp), compat_ptr(a.tvp));
 }
 
-/*
- * sys_time() can be implemented in user-level using
- * sys_gettimeofday().  x86-64 did this but i386 Linux did not
- * so we have to implement this system call here.
- */
-asmlinkage long sys32_time(int __user * tloc)
-{
-       int i;
-       struct timeval tv;
-
-       do_gettimeofday(&tv);
-       i = tv.tv_sec;
-
-       if (tloc) {
-               if (put_user(i,tloc))
-                       i = -EFAULT;
-       }
-       return i;
-}
-
 extern asmlinkage long
 compat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,
                 struct compat_rusage *ru);
@@ -665,7 +590,7 @@ sys32_sysinfo(struct sysinfo32 __user *info)
                s.freehigh >>= bitcount;
        }
 
-       if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
+       if (!access_ok(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
            __put_user (s.uptime, &info->uptime) ||
            __put_user (s.loads[0], &info->loads[0]) ||
            __put_user (s.loads[1], &info->loads[1]) ||
@@ -723,53 +648,14 @@ sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
        return ret;
 }
 
-
 asmlinkage long
-sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo,
-                     struct compat_timespec __user *uts, compat_size_t sigsetsize)
-{
-       sigset_t s;
-       compat_sigset_t s32;
-       struct timespec t;
-       int ret;
-       mm_segment_t old_fs = get_fs();
-       siginfo_t info;
-               
-       if (copy_from_user (&s32, uthese, sizeof(compat_sigset_t)))
-               return -EFAULT;
-       switch (_NSIG_WORDS) {
-       case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
-       case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
-       case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
-       case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
-       }
-       if (uts && get_compat_timespec(&t, uts))
-               return -EFAULT;
-       if (uinfo) {
-               /* stop data leak to user space in case of structure fill mismatch
-                * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user.
-                */
-               memset(&info, 0, sizeof(info));
-       }
-       set_fs (KERNEL_DS);
-       ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL,
-                       sigsetsize);
-       set_fs (old_fs);
-       if (ret >= 0 && uinfo) {
-               if (ia32_copy_siginfo_to_user(uinfo, &info))
-                       return -EFAULT;
-       }
-       return ret;
-}
-
-asmlinkage long
-sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo)
+sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
 {
        siginfo_t info;
        int ret;
        mm_segment_t old_fs = get_fs();
        
-       if (ia32_copy_siginfo_from_user(&info, uinfo))
+       if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
        set_fs (KERNEL_DS);
        ret = sys_rt_sigqueueinfo(pid, sig, &info);
@@ -787,6 +673,7 @@ sys32_pause(void)
 }
 
 
+#ifdef CONFIG_SYSCTL
 struct sysctl_ia32 {
        unsigned int    name;
        int             nlen;
@@ -801,14 +688,11 @@ struct sysctl_ia32 {
 asmlinkage long
 sys32_sysctl(struct sysctl_ia32 __user *args32)
 {
-#ifndef CONFIG_SYSCTL
-       return -ENOSYS; 
-#else
        struct sysctl_ia32 a32;
        mm_segment_t old_fs = get_fs ();
-       void *oldvalp, *newvalp;
+       void __user *oldvalp, *newvalp;
        size_t oldlen;
-       int *namep;
+       int __user *namep;
        long ret;
        extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
                     void *newval, size_t newlen);
@@ -824,9 +708,9 @@ sys32_sysctl(struct sysctl_ia32 __user *args32)
         * addresses, we KNOW that access_ok() will always succeed, so this is an
         * expensive NOP, but so what...
         */
-       namep = (int *) A(a32.name);
-       oldvalp = (void *) A(a32.oldval);
-       newvalp = (void *) A(a32.newval);
+       namep = compat_ptr(a32.name);
+       oldvalp = compat_ptr(a32.oldval);
+       newvalp =  compat_ptr(a32.newval);
 
        if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
            || !access_ok(VERIFY_WRITE, namep, 0)
@@ -844,8 +728,8 @@ sys32_sysctl(struct sysctl_ia32 __user *args32)
                return -EFAULT;
 
        return ret;
-#endif
 }
+#endif
 
 /* warning: next two assume little endian */ 
 asmlinkage long
@@ -890,7 +774,7 @@ sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
        set_fs(old_fs);
        
-       if (!ret && offset && put_user(of, offset))
+       if (offset && put_user(of, offset))
                return -EFAULT;
                
        return ret;
@@ -921,7 +805,7 @@ sys32_adjtimex(struct timex32 __user *utp)
 
        memset(&txc, 0, sizeof(struct timex));
 
-       if(verify_area(VERIFY_READ, utp, sizeof(struct timex32)) ||
+       if (!access_ok(VERIFY_READ, utp, sizeof(struct timex32)) ||
           __get_user(txc.modes, &utp->modes) ||
           __get_user(txc.offset, &utp->offset) ||
           __get_user(txc.freq, &utp->freq) ||
@@ -946,7 +830,7 @@ sys32_adjtimex(struct timex32 __user *utp)
 
        ret = do_adjtimex(&txc);
 
-       if(verify_area(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
+       if (!access_ok(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
           __put_user(txc.modes, &utp->modes) ||
           __put_user(txc.offset, &utp->offset) ||
           __put_user(txc.freq, &utp->freq) ||
@@ -981,14 +865,6 @@ asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
        struct file * file = NULL;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       if (flags & MAP_FIXED) {
-               if (len > IA32_PAGE_OFFSET)
-                       return -EINVAL;
-               if (addr > IA32_PAGE_OFFSET - len)
-                       return -ENOMEM;
-       }
-
        if (!(flags & MAP_ANONYMOUS)) {
                file = fget(fd);
                if (!file)
@@ -1104,32 +980,6 @@ asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
         return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 }
 
-asmlinkage long sys32_waitid(int which, compat_pid_t pid,
-                            siginfo_t32 __user *uinfo, int options,
-                            struct compat_rusage __user *uru)
-{
-       siginfo_t info;
-       struct rusage ru;
-       long ret;
-       mm_segment_t old_fs = get_fs();
-
-       info.si_signo = 0;
-       set_fs (KERNEL_DS);
-       ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
-                        uru ? &ru : NULL);
-       set_fs (old_fs);
-
-       if (ret < 0 || info.si_signo == 0)
-               return ret;
-
-       if (uru && (ret = put_compat_rusage(&ru, uru)))
-               return ret;
-
-       BUG_ON(info.si_code & __SI_MASK);
-       info.si_code |= __SI_CHLD;
-       return ia32_copy_siginfo_to_user(uinfo, &info);
-}
-
 /*
  * Some system calls that need sign extended arguments. This could be done by a generic wrapper.
  */ 
@@ -1144,61 +994,6 @@ long sys32_kill(int pid, int sig)
        return sys_kill(pid, sig);
 }
  
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
-       char * tmp;
-       int fd, error;
-
-       /* don't force O_LARGEFILE */
-       tmp = getname(filename);
-       fd = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd();
-               if (fd >= 0) {
-                       struct file *f = filp_open(tmp, flags, mode);
-                       error = PTR_ERR(f);
-                       if (IS_ERR(f)) {
-                               put_unused_fd(fd); 
-                               fd = error;
-                       } else
-                               fd_install(fd, f);
-               }
-               putname(tmp);
-       }
-       return fd;
-}
-
-struct sigevent32 { 
-       u32 sigev_value;
-       u32 sigev_signo; 
-       u32 sigev_notify; 
-       u32 payload[(64 / 4) - 3]; 
-}; 
-
-extern asmlinkage long
-sys_timer_create(clockid_t which_clock,
-                struct sigevent __user *timer_event_spec,
-                timer_t __user * created_timer_id);
-
-long
-sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id)
-{
-       struct sigevent __user *p = NULL;
-       if (se32) { 
-               struct sigevent se;
-               p = compat_alloc_user_space(sizeof(struct sigevent));
-               memset(&se, 0, sizeof(struct sigevent)); 
-               if (get_user(se.sigev_value.sival_int,  &se32->sigev_value) ||
-                   __get_user(se.sigev_signo, &se32->sigev_signo) ||
-                   __get_user(se.sigev_notify, &se32->sigev_notify) ||
-                   __copy_from_user(&se._sigev_un._pad, &se32->payload, 
-                                    sizeof(se32->payload)) ||
-                   copy_to_user(p, &se, sizeof(se)))
-                       return -EFAULT;
-       } 
-       return sys_timer_create(clock, p, timer_id);
-} 
-
 long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, 
                        __u32 len_low, __u32 len_high, int advice)
 { 
@@ -1226,8 +1021,6 @@ long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
        return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
 }
 
-cond_syscall(sys32_ipc)
-
 static int __init ia32_init (void)
 {
        printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n");  
@@ -1237,3 +1030,4 @@ static int __init ia32_init (void)
 __initcall(ia32_init);
 
 extern unsigned long ia32_sys_call_table[];
+EXPORT_SYMBOL(ia32_sys_call_table);