Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Jul 2000 20:10:02 -0700 (PDT)
From:      Bruce Evans <bde@zeta.org.au>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/19407: Panic running linux binary on ext2fs
Message-ID:  <200007240310.UAA96945@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/19407; it has been noted by GNATS.

From: Bruce Evans <bde@zeta.org.au>
To: "Mark W. Krentel" <krentel@dreamscape.com>
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: kern/19407: Panic running linux binary on ext2fs
Date: Mon, 24 Jul 2000 13:02:40 +1000 (EST)

 On Thu, 6 Jul 2000, Mark W. Krentel wrote:
 
 >  I've run some more experiments and I've narrowed the problem somewhat.
 >  
 >  Using the Slackware 7 live file system, I tar-copied /cdrom/live/bin
 >  onto ufs and ext2fs partitions.  Then I ran Slackware's ls from ufs,
 >  cdrom and ext2fs and listed directories on ufs, cdrom and ext2fs.
 >  Sometimes it worked ok, sometimes the output of ls was corrupt (too
 >  few files), and the pattern is quite clear.
 >  
 >                          directory listed on 
 >      binary on        ufs       cdrom       ext2fs
 >        ufs            ok       corrupt      corrupt
 >       cdrom           ok       corrupt      corrupt
 >       ext2fs          ok       corrupt      corrupt
 
 I found some of the problems using these hints.  There were 2 serious bugs
 in ext2_readdir(): writing far beyond the end of the cookie buffer, and
 reading a little beyond the end of the directory buffer.
 
 There don't seem to be any problems with the Linuxulator.  It just asks
 ext2_readdir() for cookies.  Then cookie processing is usually fatal.
 Similarly for readdir() on an nfs-mounted ext2fs filesystem.
 
 Overrunning the directory buffer can cause panics and wrong results from
 readdir(3) even for native binaries, but this problem doesn't usually occur
 for native binaries because they use an adequate buffer size (4K).  Linux
 binaries trigger the bug by using a too-small buffer size (512 bytes).
 This size makes Linux's ls (an old (1997) RedHat version) take about 4
 times as much system time as FreeBSD's ls even on ufs filesystems.
 getdirentries(2) claims that the correct size is given by stat(2), but 
 Linux's ls apparently doesn't know this, and in any case the correct
 size is a little larger than the filesystem blocksize for ext2fs, since
 ext2_readdir() expands some directory entries.
 
 Try these fixes:
 
 Index: ext2_lookup.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/gnu/ext2fs/ext2_lookup.c,v
 retrieving revision 1.24
 diff -c -2 -r1.24 ext2_lookup.c
 *** ext2_lookup.c	2000/05/05 09:57:57	1.24
 --- ext2_lookup.c	2000/07/24 02:09:03
 ***************
 *** 153,166 ****
   	struct iovec aiov;
   	caddr_t dirbuf;
   	int readcnt;
 ! 	u_quad_t startoffset = uio->uio_offset;
   
 !         count = uio->uio_resid;		/* legyenek boldogok akik akarnak ... */
 !         uio->uio_resid = count;
 !         uio->uio_iov->iov_len = count;
 ! 
 ! #if 0
 ! printf("ext2_readdir called uio->uio_offset %d uio->uio_resid %d count %d \n", 
 ! 	(int)uio->uio_offset, (int)uio->uio_resid, (int)count);
   #endif
   
 --- 152,175 ----
   	struct iovec aiov;
   	caddr_t dirbuf;
 + 	int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->s_blocksize;
   	int readcnt;
 ! 	off_t startoffset = uio->uio_offset;
   
 ! 	count = uio->uio_resid;
 ! 	/*
 ! 	 * Avoid complications for partial directory entries by adjusting
 ! 	 * the i/o to end at a block boundary.  Don't give up (like ufs
 ! 	 * does) if the initial adjustment gives a negative count, since
 ! 	 * many callers don't supply a large enough buffer.  The correct
 ! 	 * size is a little larger than DIRBLKSIZ to allow for expansion
 ! 	 * of directory entries, but some callers just use 512.
 ! 	 */
 ! 	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
 ! 	if (count <= 0)
 ! 		count += DIRBLKSIZ;
 ! 
 ! #ifdef EXT2FS_DEBUG
 ! 	printf("ext2_readdir: uio_offset = %lld, uio_resid = %d, count = %d\n", 
 ! 	    uio->uio_offset, uio->uio_resid, count);
   #endif
   
 ***************
 *** 168,171 ****
 --- 177,181 ----
   	auio.uio_iov = &aiov;
   	auio.uio_iovcnt = 1;
 + 	auio.uio_resid = count;
   	auio.uio_segflg = UIO_SYSSPACE;
   	aiov.iov_len = count;
 ***************
 *** 226,231 ****
   
   		if (!error && ap->a_ncookies != NULL) {
 ! 			u_long *cookies;
 ! 			u_long *cookiep;
   			off_t off;
   
 --- 236,240 ----
   
   		if (!error && ap->a_ncookies != NULL) {
 ! 			u_long *cookiep, *cookies, *ecookies;
   			off_t off;
   
 ***************
 *** 235,240 ****
   			       M_WAITOK);
   			off = startoffset;
 ! 			for (dp = (struct ext2_dir_entry_2 *)dirbuf, cookiep = cookies;
 ! 			     dp < edp;
   			     dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
   				off += dp->rec_len;
 --- 244,250 ----
   			       M_WAITOK);
   			off = startoffset;
 ! 			for (dp = (struct ext2_dir_entry_2 *)dirbuf,
 ! 			     cookiep = cookies, ecookies = cookies + ncookies;
 ! 			     cookiep < ecookies;
   			     dp = (struct ext2_dir_entry_2 *)((caddr_t) dp + dp->rec_len)) {
   				off += dp->rec_len;
 
 Bruce
 
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200007240310.UAA96945>