Subject: Re: misc/29696 : NetBSD freezes when accessing smbfs under linux emulation [Patch included]
To: None <misc-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Kailash Sethuraman <hsaliak@kasba.ath.cx>
List: netbsd-bugs
Date: 04/16/2005 15:07:01
The following reply was made to PR misc/29696; it has been noted by GNATS.
From: Kailash Sethuraman <hsaliak@kasba.ath.cx>
To: gnats-bugs@NetBSD.org
Cc: misc-bug-people@NetBSD.org
Subject: Re: misc/29696 : NetBSD freezes when accessing smbfs under linux emulation [Patch included]
Date: Sat, 16 Apr 2005 23:06:45 +0800
Hi,
I encountered the same problem when using opera on the smbfs recently.
The issue lies in
src/sys/compat/linux/common/linux_file64.c
ident linux_file64.c
linux_file64.c:
$NetBSD: linux_file64.c,v 1.22 2003/08/10 20:16:27 jdolecek Exp $
The offending function : linux_sys_getdents64
The crash is caused by a null pointer dereference in line 486.
off = *cookie++;
As indicated by VOP_READDIR's man page it seems that cookie support is optional,
in fact it says its only for NFS. However a quick inspection showed that both
ufs and ext2fs and have support for this. smbfs doesnt, and hence the problem
surfaces as the linux compat code assumes that the cookiebuf returned is
not NULL.
I have included a patch that fixes the code and hence should no longer cause a
crash when this code path is taken on filesystems without this VOP_READDIR
cookie support. I have tested this on NetBSD 2.0 i386.
Unfortunately, I have also noticed that this the getdents* code is similar
across many emulations (such as Sunos) and hence I believe that the other
emulations may
require similar patches. I can send similar patches but I will not be able
to test them, as I only have i386 hardware.
I also hope that this is the desired fix for the problem, rather than say
adding the cookie support to smbfs and other filesystems without it.
PS: Sorry for not providing a patch against the file in -current, as I do not
track it.
Regards,
Kailash
src/sys/compat/linux/common/linux_file64.c
--- linux_file64.c.orig 2005-04-16 21:09:19.000000000 +0800
+++ linux_file64.c 2005-04-16 22:46:12.000000000 +0800
@@ -474,16 +474,20 @@
panic("linux_readdir");
if (bdp->d_fileno == 0) {
inp += reclen; /* it is a hole; squish it out */
- off = *cookie++;
+ if(cookie)
+ off = *cookie++;
+ else
+ off += reclen;
continue;
}
+
linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
if (reclen > len || resid < linux_reclen) {
/* entry too big for buffer, so just stop */
outp++;
break;
}
- off = *cookie++; /* each entry points to next */
+
/*
* Massage in place to make a Linux-shaped dirent (otherwise
* we have to worry about touching user memory outside of
@@ -491,7 +495,9 @@
*/
idb.d_ino = bdp->d_fileno;
idb.d_type = bdp->d_type;
- idb.d_off = off;
+ idb.d_off = (cookie)
+ ? (linux_off_t) *cookie
+ : (linux_off_t)(off + reclen);
idb.d_reclen = (u_short)linux_reclen;
strcpy(idb.d_name, bdp->d_name);
if ((error = copyout((caddr_t)&idb, outp, linux_reclen)))
@@ -501,6 +507,11 @@
/* advance output past Linux-shaped entry */
outp += linux_reclen;
resid -= linux_reclen;
+
+ if(cookie)
+ off = *cookie++;
+ else
+ off += reclen;
}
/* if we squished out the whole block, try again */