linux-mips
[Top] [All Lists]

64 bit syscall wrapper.

To: Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org
Subject: 64 bit syscall wrapper.
From: Carsten Langgaard <carstenl@mips.com>
Date: Mon, 21 Oct 2002 09:34:25 +0200
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
Here's yet another patch for the 64 bit syscall wrapper.

/Carsten


--
_    _ ____  ___   Carsten Langgaard   Mailto:carstenl@mips.com
|\  /|||___)(___   MIPS Denmark        Direct: +45 4486 5527
| \/ |||    ____)  Lautrupvang 4B      Switch: +45 4486 5555
  TECHNOLOGIES     2750 Ballerup       Fax...: +45 4486 5556
                   Denmark             http://www.mips.com


Index: arch/mips64/kernel/linux32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/linux32.c,v
retrieving revision 1.42.2.17
diff -u -r1.42.2.17 linux32.c
--- arch/mips64/kernel/linux32.c        10 Oct 2002 11:38:43 -0000      
1.42.2.17
+++ arch/mips64/kernel/linux32.c        21 Oct 2002 07:30:54 -0000
@@ -2147,81 +2147,42 @@
        unsigned int __unused[4];
 };
 
-asmlinkage long sys32_sysctl(struct sysctl_args32 *uargs32)
+asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
 {
-       struct __sysctl_args kargs;
-       struct sysctl_args32 kargs32;
-       mm_segment_t old_fs;
-       int name[CTL_MAXNAME];
-       size_t oldlen[1];
-       int err, ret;
-
-       ret = -EFAULT;
-
-       memset(&kargs, 0, sizeof (kargs));
-
-       err = get_user(kargs32.name, &uargs32->name);
-       err |= __get_user(kargs32.nlen, &uargs32->nlen);
-       err |= __get_user(kargs32.oldval, &uargs32->oldval);
-       err |= __get_user(kargs32.oldlenp, &uargs32->oldlenp);
-       err |= __get_user(kargs32.newval, &uargs32->newval);
-       err |= __get_user(kargs32.newlen, &uargs32->newlen);
-       if (err)
-               goto out;
-
-       if (kargs32.nlen == 0 || kargs32.nlen >= CTL_MAXNAME) {
-               ret = -ENOTDIR;
-               goto out;
-       }
-
-       kargs.name = name;
-       kargs.nlen = kargs32.nlen;
-       if (copy_from_user(kargs.name, (int *)A(kargs32.name),
-                          kargs32.nlen * sizeof(name) / sizeof(name[0])))
-               goto out;
-
-       if (kargs32.oldval) {
-               if (!kargs32.oldlenp || get_user(oldlen[0],
-                                                (int *)A(kargs32.oldlenp)))
+       struct sysctl_args32 tmp;
+       int error;
+       size_t oldlen, *oldlenp = NULL;
+       unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+
+       if (copy_from_user(&tmp, args, sizeof(tmp)))
+               return -EFAULT;
+
+       if (tmp.oldval && tmp.oldlenp) {
+               /* Duh, this is ugly and might not work if sysctl_args
+                  is in read-only memory, but do_sysctl does indirectly
+                  a lot of uaccess in both directions and we'd have to
+                  basically copy the whole sysctl.c here, and
+                  glibc's __sysctl uses rw memory for the structure
+                  anyway.  */
+               if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
+                   put_user(oldlen, (size_t *)addr))
                        return -EFAULT;
-               kargs.oldlenp = oldlen;
-               kargs.oldval = kmalloc(oldlen[0], GFP_KERNEL);
-               if (!kargs.oldval) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               oldlenp = (size_t *)addr;
        }
 
-       if (kargs32.newval && kargs32.newlen) {
-               kargs.newval = kmalloc(kargs32.newlen, GFP_KERNEL);
-               if (!kargs.newval) {
-                       ret = -ENOMEM;
-                       goto out;
+       lock_kernel();
+       error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
+                         oldlenp, (void *)A(tmp.newval), tmp.newlen);
+       unlock_kernel();
+       if (oldlenp) {
+               if (!error) {
+                       if (get_user(oldlen, (size_t *)addr) ||
+                           put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+                               error = -EFAULT;
                }
-               if (copy_from_user(kargs.newval, (int *)A(kargs32.newval),
-                                  kargs32.newlen))
-                       goto out;
-       }
-
-       old_fs = get_fs(); set_fs (KERNEL_DS);
-       ret = sys_sysctl(&kargs);
-       set_fs (old_fs);
-
-       if (ret)
-               goto out;
-
-       if (kargs.oldval) {
-               if (put_user(oldlen[0], (int *)A(kargs32.oldlenp)) ||
-                   copy_to_user((int *)A(kargs32.oldval), kargs.oldval,
-                                oldlen[0]))
-                       ret = -EFAULT;
+               copy_to_user(args->__unused, tmp.__unused, 
sizeof(tmp.__unused));
        }
-out:
-       if (kargs.oldval)
-               kfree(kargs.oldval);
-       if (kargs.newval)
-               kfree(kargs.newval);
-       return ret;
+       return error;
 }
 
 asmlinkage long sys32_newuname(struct new_utsname * name)
<Prev in Thread] Current Thread [Next in Thread>
  • 64 bit syscall wrapper., Carsten Langgaard <=