⬢ DragonFlyBSD Kernel Audit
DF-2726 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -1245,6 +1245,7 @@
 {
 	struct vnode *vp;
 	off_t loffset;
+	off_t phys_offset;
 	int maxclen, cursize;
 	int async;
 	cluster_cache_t dummy;
@@ -1258,6 +1259,12 @@
 	loffset = bp->b_loffset;
 	KASSERT(bp->b_loffset != NOOFFSET, 
 		("cluster_write: no buffer offset"));
+	/*
+	 * Snapshot the physical offset: bdwrite()/bawrite() below release
+	 * the buffer, so bp must not be dereferenced afterwards (use
+	 * phys_offset for the post-release v_lasta updates).
+	 */
+	phys_offset = bp->b_bio2.bio_offset;
 
 	cc = cluster_getcache(&dummy, vp, loffset);
 
@@ -1311,6 +1318,7 @@
 							      bp, blksize);
 				endbp = &buflist->bs_children
 					[buflist->bs_nchildren - 1];
+				phys_offset = bp->b_bio2.bio_offset;
 				if (VOP_REALLOCBLKS(vp, buflist)) {
 					/*
 					 * Failed, push the previous cluster
@@ -1342,7 +1350,7 @@
 						bdwrite(*bpp);
 					kfree(buflist, M_SEGMENT);
 					cc->v_lastw = loffset + blksize;
-					cc->v_lasta = bp->b_bio2.bio_offset +
+					cc->v_lasta = phys_offset +
 						      blksize;
 					cluster_putcache(cc);
 					return;
@@ -1360,9 +1368,10 @@
 		    (bp->b_bio2.bio_offset == NOOFFSET) &&
 		    (VOP_BMAP(vp, loffset, &bp->b_bio2.bio_offset, &maxclen, NULL, BUF_CMD_WRITE) ||
 		     bp->b_bio2.bio_offset == NOOFFSET)) {
+			phys_offset = bp->b_bio2.bio_offset;
 			bdwrite(bp);
 			cc->v_clen = 0;
-			cc->v_lasta = bp->b_bio2.bio_offset + blksize;
+			cc->v_lasta = phys_offset + blksize;
 			cc->v_cstart = loffset;
 			cc->v_lastw = loffset + blksize;
 			cluster_putcache(cc);
@@ -1406,7 +1415,7 @@
 		bdwrite(bp);
 	}
 	cc->v_lastw = loffset + blksize;
-	cc->v_lasta = bp->b_bio2.bio_offset + blksize;
+	cc->v_lasta = phys_offset + blksize;
 	cluster_putcache(cc);
 }