Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / arch / arm / kernel / sys_oabi-compat.c
index 075a2e0..68112c1 100644 (file)
 #include <linux/socket.h>
 #include <linux/net.h>
 #include <linux/ipc.h>
+#include <linux/ipc_namespace.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 
+#include <asm/syscall.h>
+
 struct oldabi_stat64 {
        unsigned long long st_dev;
        unsigned int    __pad1;
@@ -191,60 +194,87 @@ struct oabi_flock64 {
        pid_t   l_pid;
 } __attribute__ ((packed,aligned(4)));
 
-static long do_locks(unsigned int fd, unsigned int cmd,
-                                unsigned long arg)
+static int get_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg)
 {
-       struct flock64 kernel;
        struct oabi_flock64 user;
-       mm_segment_t fs;
-       long ret;
 
        if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
                           sizeof(user)))
                return -EFAULT;
-       kernel.l_type   = user.l_type;
-       kernel.l_whence = user.l_whence;
-       kernel.l_start  = user.l_start;
-       kernel.l_len    = user.l_len;
-       kernel.l_pid    = user.l_pid;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel);
-       set_fs(fs);
-
-       if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) {
-               user.l_type     = kernel.l_type;
-               user.l_whence   = kernel.l_whence;
-               user.l_start    = kernel.l_start;
-               user.l_len      = kernel.l_len;
-               user.l_pid      = kernel.l_pid;
-               if (copy_to_user((struct oabi_flock64 __user *)arg,
-                                &user, sizeof(user)))
-                       ret = -EFAULT;
-       }
-       return ret;
+
+       kernel->l_type   = user.l_type;
+       kernel->l_whence = user.l_whence;
+       kernel->l_start  = user.l_start;
+       kernel->l_len    = user.l_len;
+       kernel->l_pid    = user.l_pid;
+
+       return 0;
+}
+
+static int put_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg)
+{
+       struct oabi_flock64 user;
+
+       user.l_type     = kernel->l_type;
+       user.l_whence   = kernel->l_whence;
+       user.l_start    = kernel->l_start;
+       user.l_len      = kernel->l_len;
+       user.l_pid      = kernel->l_pid;
+
+       if (copy_to_user((struct oabi_flock64 __user *)arg,
+                        &user, sizeof(user)))
+               return -EFAULT;
+
+       return 0;
 }
 
 asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
                                 unsigned long arg)
 {
+       void __user *argp = (void __user *)arg;
+       struct fd f = fdget_raw(fd);
+       struct flock64 flock;
+       long err = -EBADF;
+
+       if (!f.file)
+               goto out;
+
        switch (cmd) {
-       case F_OFD_GETLK:
-       case F_OFD_SETLK:
-       case F_OFD_SETLKW:
        case F_GETLK64:
+       case F_OFD_GETLK:
+               err = security_file_fcntl(f.file, cmd, arg);
+               if (err)
+                       break;
+               err = get_oabi_flock(&flock, argp);
+               if (err)
+                       break;
+               err = fcntl_getlk64(f.file, cmd, &flock);
+               if (!err)
+                      err = put_oabi_flock(&flock, argp);
+               break;
        case F_SETLK64:
        case F_SETLKW64:
-               return do_locks(fd, cmd, arg);
-
+       case F_OFD_SETLK:
+       case F_OFD_SETLKW:
+               err = security_file_fcntl(f.file, cmd, arg);
+               if (err)
+                       break;
+               err = get_oabi_flock(&flock, argp);
+               if (err)
+                       break;
+               err = fcntl_setlk64(fd, f.file, cmd, &flock);
+               break;
        default:
-               return sys_fcntl64(fd, cmd, arg);
+               err = sys_fcntl64(fd, cmd, arg);
+               break;
        }
+       fdput(f);
+out:
+       return err;
 }
 
 struct oabi_epoll_event {
-       __u32 events;
+       __poll_t events;
        __u64 data;
 } __attribute__ ((packed,aligned(4)));
 
@@ -264,55 +294,34 @@ asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd,
 
        return do_epoll_ctl(epfd, op, fd, &kernel, false);
 }
-
-asmlinkage long sys_oabi_epoll_wait(int epfd,
-                                   struct oabi_epoll_event __user *events,
-                                   int maxevents, int timeout)
-{
-       struct epoll_event *kbuf;
-       struct oabi_epoll_event e;
-       mm_segment_t fs;
-       long ret, err, i;
-
-       if (maxevents <= 0 ||
-                       maxevents > (INT_MAX/sizeof(*kbuf)) ||
-                       maxevents > (INT_MAX/sizeof(*events)))
-               return -EINVAL;
-       if (!access_ok(events, sizeof(*events) * maxevents))
-               return -EFAULT;
-       kbuf = kmalloc_array(maxevents, sizeof(*kbuf), GFP_KERNEL);
-       if (!kbuf)
-               return -ENOMEM;
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
-       set_fs(fs);
-       err = 0;
-       for (i = 0; i < ret; i++) {
-               e.events = kbuf[i].events;
-               e.data = kbuf[i].data;
-               err = __copy_to_user(events, &e, sizeof(e));
-               if (err)
-                       break;
-               events++;
-       }
-       kfree(kbuf);
-       return err ? -EFAULT : ret;
-}
 #else
 asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd,
                                   struct oabi_epoll_event __user *event)
 {
        return -EINVAL;
 }
+#endif
 
-asmlinkage long sys_oabi_epoll_wait(int epfd,
-                                   struct oabi_epoll_event __user *events,
-                                   int maxevents, int timeout)
+struct epoll_event __user *
+epoll_put_uevent(__poll_t revents, __u64 data,
+                struct epoll_event __user *uevent)
 {
-       return -EINVAL;
+       if (in_oabi_syscall()) {
+               struct oabi_epoll_event __user *oevent = (void __user *)uevent;
+
+               if (__put_user(revents, &oevent->events) ||
+                   __put_user(data, &oevent->data))
+                       return NULL;
+
+               return (void __user *)(oevent+1);
+       }
+
+       if (__put_user(revents, &uevent->events) ||
+           __put_user(data, &uevent->data))
+               return NULL;
+
+       return uevent+1;
 }
-#endif
 
 struct oabi_sembuf {
        unsigned short  sem_num;
@@ -321,46 +330,52 @@ struct oabi_sembuf {
        unsigned short  __pad;
 };
 
+#define sc_semopm     sem_ctls[2]
+
+#ifdef CONFIG_SYSVIPC
 asmlinkage long sys_oabi_semtimedop(int semid,
                                    struct oabi_sembuf __user *tsops,
                                    unsigned nsops,
                                    const struct old_timespec32 __user *timeout)
 {
+       struct ipc_namespace *ns;
        struct sembuf *sops;
-       struct old_timespec32 local_timeout;
        long err;
        int i;
 
+       ns = current->nsproxy->ipc_ns;
+       if (nsops > ns->sc_semopm)
+               return -E2BIG;
        if (nsops < 1 || nsops > SEMOPM)
                return -EINVAL;
-       if (!access_ok(tsops, sizeof(*tsops) * nsops))
-               return -EFAULT;
-       sops = kmalloc_array(nsops, sizeof(*sops), GFP_KERNEL);
+       sops = kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL);
        if (!sops)
                return -ENOMEM;
        err = 0;
        for (i = 0; i < nsops; i++) {
                struct oabi_sembuf osb;
-               err |= __copy_from_user(&osb, tsops, sizeof(osb));
+               err |= copy_from_user(&osb, tsops, sizeof(osb));
                sops[i].sem_num = osb.sem_num;
                sops[i].sem_op = osb.sem_op;
                sops[i].sem_flg = osb.sem_flg;
                tsops++;
        }
-       if (timeout) {
-               /* copy this as well before changing domain protection */
-               err |= copy_from_user(&local_timeout, timeout, sizeof(*timeout));
-               timeout = &local_timeout;
-       }
        if (err) {
                err = -EFAULT;
-       } else {
-               mm_segment_t fs = get_fs();
-               set_fs(KERNEL_DS);
-               err = sys_semtimedop_time32(semid, sops, nsops, timeout);
-               set_fs(fs);
+               goto out;
        }
-       kfree(sops);
+
+       if (timeout) {
+               struct timespec64 ts;
+               err = get_old_timespec32(&ts, timeout);
+               if (err)
+                       goto out;
+               err = __do_semtimedop(semid, sops, nsops, &ts, ns);
+               goto out;
+       }
+       err = __do_semtimedop(semid, sops, nsops, NULL, ns);
+out:
+       kvfree(sops);
        return err;
 }
 
@@ -387,6 +402,27 @@ asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
                return sys_ipc(call, first, second, third, ptr, fifth);
        }
 }
+#else
+asmlinkage long sys_oabi_semtimedop(int semid,
+                                   struct oabi_sembuf __user *tsops,
+                                   unsigned nsops,
+                                   const struct old_timespec32 __user *timeout)
+{
+       return -ENOSYS;
+}
+
+asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops,
+                              unsigned nsops)
+{
+       return -ENOSYS;
+}
+
+asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
+                           void __user *ptr, long fifth)
+{
+       return -ENOSYS;
+}
+#endif
 
 asmlinkage long sys_oabi_bind(int fd, struct sockaddr __user *addr, int addrlen)
 {