⬢ DragonFlyBSD Kernel Audit
DF-2527 / fix.diff
← back to finding ↓ download raw
--- /home/maxx/dfbsd/dfbsd/sys/dev/disk/vn/vn.c	2026-07-22 23:04:24.321615409 +0000
+++ sys/dev/disk/vn/vn.c	2026-10-24 09:12:56.265938105 +0000
@@ -123,6 +123,7 @@
 	int		sc_flags;	/* flags 			*/
 	u_int64_t	sc_size;	/* size of vn, sc_secsize scale	*/
 	int		sc_secsize;	/* sector size			*/
+	struct lwkt_token sc_iotok;	/* serialize I/O vs vnclear	*/
 	struct disk	sc_disk;
 	struct vnode	*sc_vp;		/* vnode if not NULL		*/
 	vm_object_t	sc_object;	/* backing object if not NULL	*/
@@ -301,7 +302,21 @@
 	/*
 	 * Use the translated nbio from this point on
 	 */
-	if (vn->sc_vp && bp->b_cmd == BUF_CMD_FREEBLKS) {
+	struct vnode *vp_snap;
+	int inited_snap;
+
+	/*
+	 * Snapshot the backing-store state under the token so a
+	 * concurrent vnclear (detach) cannot free sc_vp between the
+	 * test and the use.  (Full lifetime safety additionally needs
+	 * a held vnode reference across the I/O.)
+	 */
+	lwkt_gettoken(&vn->sc_iotok);
+	vp_snap = vn->sc_vp;
+	inited_snap = (vn->sc_flags & VNF_INITED) != 0;
+	lwkt_reltoken(&vn->sc_iotok);
+
+	if (vp_snap && bp->b_cmd == BUF_CMD_FREEBLKS) {
 		/*
 		 * Freeblks is not handled for vnode-backed elements yet.
 		 */
@@ -556,6 +571,10 @@
 	 * If the size is specified, override the file attributes.  Note that
 	 * the vn_size argument is in PAGE_SIZE sized blocks.
 	 */
+	if (vio->vn_size < 0 || vio->vn_size > INT64_MAX / PAGE_SIZE) {
+		error = EDOM;	/* same range guard the swap path applies */
+		goto done;
+	}
 	if (vio->vn_size)
 		vn->sc_size = vio->vn_size * PAGE_SIZE / vn->sc_secsize;
 	else
@@ -857,6 +876,7 @@
 		ret_dev = dev = disk_create(unit, &vn->sc_disk, &vn_ops);
 	}
 	vninitvn(vn, dev);
+	lwkt_token_init(&vn->sc_iotok, "vniotok");
 
 	bzero(&info, sizeof(struct disk_info));
 	info.d_media_blksize = 512;