[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