64 bit syscall wrapper.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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)

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux