DragonFlyBSD Kernel Audit
DF-0931 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/ufs/ufs_readwrite.c b/sys/vfs/ufs/ufs_readwrite.c
--- a/sys/vfs/ufs/ufs_readwrite.c
+++ b/sys/vfs/ufs/ufs_readwrite.c
@@ -65,7 +65,7 @@
 	struct buf *bp;
 	off_t bytesinfile;
 	int xfersize, blkoffset;
-	int error, orig_resid;
+	int error; size_t orig_resid;
 	int seqcount;
 	int ioflag;
 
@@ -217,7 +217,7 @@
 	off_t osize;
 	off_t nsize;
 	int seqcount;
-	int blkoffset, error, extended, flags, ioflag, resid, size, xfersize;
+	int blkoffset, error, extended, flags, ioflag, size, xfersize, xferred; size_t resid;
 	struct thread *td;
 
 	extended = 0;
@@ -287,6 +287,7 @@
 	else
 		vclrflags(vp, VLASTWRITETS);
 
+	xferred = 0;
 	for (error = 0; uio->uio_resid > 0;) {
 		lbn = lblkno(fs, uio->uio_offset);
 		blkoffset = blkoff(fs, uio->uio_offset);
@@ -330,6 +331,7 @@
 				   ap->a_cred, flags, &bp);
 		if (error != 0)
 			break;
+		xferred = 1;
 		/*
 		 * If the buffer is not valid and we did not clear garbage
 		 * out above, we have to do so here even though the write
@@ -397,9 +399,9 @@
 	 * we clear the setuid and setgid bits as a precaution against
 	 * tampering.
 	 */
-	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
+	if ((xferred || resid > uio->uio_resid) && ap->a_cred && ap->a_cred->cr_uid != 0)
 		ip->i_mode &= ~(ISUID | ISGID);
-	if (resid > uio->uio_resid)
+	if (xferred || resid > uio->uio_resid)
 		VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
 	if (error) {
 		if (ioflag & IO_UNIT) {
@@ -408,7 +410,7 @@
 			uio->uio_offset -= resid - uio->uio_resid;
 			uio->uio_resid = resid;
 		}
-	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
+	} else if ((xferred || resid > uio->uio_resid) && (ioflag & IO_SYNC)) {
 		error = ffs_update(vp, 1);
 	} else {
 		ufs_itimes(vp);