[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gentoo-sparc
Subject:    [gentoo-sparc] system lockup bug in >2.6.7-rc1-bk6 tracked down
From:       Jeremy Huddleston <eradicator () gentoo ! org>
Date:       2004-11-27 11:11:47
Message-ID: 1101553907.21614.24.camel () cid ! outersquare ! org
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


A change between 2.6.7-rc1-bk6 and 2.6.7-rc2 can results in a system
lockdown.  One situation in which this can be triggered is when we are a
nfs client, and the nfs server shuts down (or on the server, you simply
issue an 'ifconfig eth1 down').  I have tracked this down to a bug in
dev_ifconf() in fs/compat_ioctl.c

The attached patch will revert this function to it's pre-2.6.7-rc2
state.  This is not meant to be the suggested fix, but it is a
workaround for now for anyone who is in need of it, and hopefully now
that I've narrowed down the problem, someone else might be willing/able
to fix it since it's past 3am here, and I don't have much experience
with the fs/ section of the kernel...

Thanks.

--=20
Jeremy Huddleston <eradicator@gentoo.org>

["dev_ifconf-revert-2.6.7-rc1-bk6.patch" (dev_ifconf-revert-2.6.7-rc1-bk6.patch)]

diff -Naurp linux-2.6.7-rc2/fs/compat_ioctl.c linux-2.6.7-rc2.nfsrevert/fs/compat_ioctl.c
--- linux-2.6.7-rc2/fs/compat_ioctl.c	2004-11-26 19:41:08.000000000 -0800
+++ linux-2.6.7-rc2.nfsrevert/fs/compat_ioctl.c	2004-11-27 02:56:29.180140777 -0800
@@ -490,9 +490,9 @@ static int dev_ifconf(unsigned int fd, u
 {
 	struct ifconf32 ifc32;
 	struct ifconf ifc;
-	struct ifconf __user *uifc;
 	struct ifreq32 __user *ifr32;
 	struct ifreq __user *ifr;
+	mm_segment_t old_fs;
 	unsigned int i, j;
 	int err;
 
@@ -502,59 +502,63 @@ static int dev_ifconf(unsigned int fd, u
 	if (ifc32.ifcbuf == 0) {
 		ifc32.ifc_len = 0;
 		ifc.ifc_len = 0;
-		ifc.ifc_req = NULL;
-		uifc = compat_alloc_user_space(sizeof(struct ifconf));
+		ifc.ifc_buf = NULL;
 	} else {
-		size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
 			sizeof (struct ifreq);
-		uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
-		ifc.ifc_len = len;
-		ifr = ifc.ifc_req = (void __user *)(uifc + 1);
-		ifr32 = compat_ptr(ifc32.ifcbuf);
-		for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
-			if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32)))
-				return -EFAULT;
-			ifr++;
-			ifr32++; 
-		}
+		/* should the size be limited? -arnd */
+		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+		if (!ifc.ifc_buf)
+			return -ENOMEM;
 	}
-	if (copy_to_user(uifc, &ifc, sizeof(struct ifconf)))
-		return -EFAULT;
-
-	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc);	
-	if (err)
-		return err;
-
-	if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 
-		return -EFAULT;
-
 	ifr = ifc.ifc_req;
 	ifr32 = compat_ptr(ifc32.ifcbuf);
-	for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
-	     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
-		if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32)))
+	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+		if (copy_from_user(ifr, ifr32, sizeof (struct ifreq32))) {
+			kfree (ifc.ifc_buf);
 			return -EFAULT;
+		}
 		ifr32++;
 		ifr++;
 	}
-
-	if (ifc32.ifcbuf == 0) {
-		/* Translate from 64-bit structure multiple to
-		 * a 32-bit one.
-		 */
-		i = ifc.ifc_len;
-		i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
-		ifc32.ifc_len = i;
-	} else {
-		if (i <= ifc32.ifc_len)
-			ifc32.ifc_len = i;
-		else
-			ifc32.ifc_len = i - sizeof (struct ifreq32);
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	set_fs (old_fs);
+	if (!err) {
+		ifr = ifc.ifc_req;
+		ifr32 = compat_ptr(ifc32.ifcbuf);
+		for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+		     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+			int k = copy_to_user(ifr32, ifr, sizeof (struct ifreq32));
+			ifr32++;
+			ifr++;
+			if (k) {
+				err = -EFAULT;
+				break;
+			}
+		       
+		}
+		if (!err) {
+			if (ifc32.ifcbuf == 0) {
+				/* Translate from 64-bit structure multiple to
+				 * a 32-bit one.
+				 */
+				i = ifc.ifc_len;
+				i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
+				ifc32.ifc_len = i;
+			} else {
+				if (i <= ifc32.ifc_len)
+					ifc32.ifc_len = i;
+				else
+					ifc32.ifc_len = i - sizeof (struct ifreq32);
+			}
+			if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32)))
+				err = -EFAULT;
+		}
 	}
-	if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32)))
-		return -EFAULT;
-
-	return 0;
+	if(ifc.ifc_buf != NULL)
+		kfree (ifc.ifc_buf);
+	return err;
 }
 
 static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)

["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic