Subject: nfs/ubc panic with bad pointers
To: None <tech-kern@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 10/27/2002 19:06:01
--NextPart-20021027190112-0031901
Content-Type: Text/Plain; charset=us-ascii

hi.

for nfs,
following may cause assertion failure (bytes != 0) in genfs_gop_write.
(originally reported by kay on a japanese mailing list)

fd = open(.., O_RDWR|O_TRUNC);
write(fd, bad_pointer, 1);
close(fd);

the problem is that it'll assign pages to vnode without bumping v_size.
panic can be avoided with attached patch, i think.
i'm not sure how to do for NMODIFIED, though.

YAMAMOTO Takashi

--NextPart-20021027190112-0031901
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="nfs_bio.c.diff"

Index: nfs_bio.c
===================================================================
RCS file: /cvs/NetBSD/syssrc/sys/nfs/nfs_bio.c,v
retrieving revision 1.84
diff -u -p -r1.84 nfs_bio.c
--- nfs_bio.c	2002/10/23 09:14:48	1.84
+++ nfs_bio.c	2002/10/27 09:38:20
@@ -591,6 +591,8 @@ nfs_write(v)
 
 	origoff = uio->uio_offset;
 	do {
+		boolean_t extending; /* if we are extending whole pages */
+		u_quad_t oldsize;
 		oldoff = uio->uio_offset;
 		bytelen = uio->uio_resid;
 
@@ -616,13 +618,15 @@ nfs_write(v)
 #endif
 		nfsstats.biocache_writes++;
 
+		oldsize = np->n_size;
 		np->n_flag |= NMODIFIED;
 		if (np->n_size < uio->uio_offset + bytelen) {
 			np->n_size = uio->uio_offset + bytelen;
 		}
-		if ((uio->uio_offset & PAGE_MASK) == 0 &&
+		extending = ((uio->uio_offset & PAGE_MASK) == 0 &&
 		    (bytelen & PAGE_MASK) == 0 &&
-		    uio->uio_offset >= vp->v_size) {
+		    uio->uio_offset >= vp->v_size);
+		if (extending) {
 			win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen,
 			    UBC_WRITE | UBC_FAULTBUSY);
 		} else {
@@ -632,6 +636,14 @@ nfs_write(v)
 		error = uiomove(win, bytelen, uio);
 		ubc_release(win, 0);
 		if (error) {
+			if (extending) {
+				/*
+				 * backout size and free pages past eof.
+				 */
+				np->n_size = oldsize;
+				(void)VOP_PUTPAGES(vp, round_page(vp->v_size),
+				    0, PGO_SYNCIO | PGO_FREE);
+			}
 			break;
 		}
 		wrotedta = 1;

--NextPart-20021027190112-0031901--