Subject: Re: nfs/ubc panic with bad pointers
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: tech-kern
Date: 10/27/2002 17:19:45
In article <1035713161.485419.541.nullmailer@yamt.dyndns.org>,
YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp> wrote:
>-=-=-=-=-=-
>
>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

Isn't a better way to:

	if (uvm_useracc(bad_pointer, bad_size, B_READ) == FALSE)
		return EFAULT;
	
>-=-=-=-=-=-
>
>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;
>
>-=-=-=-=-=-