⬢ DragonFlyBSD Kernel Audit
DF-3208 / fix.diff
← back to finding ↓ download raw
--- a/isofs/cd9660/cd9660_node.c	2026-09-08 13:09:29.861631092 +0000
+++ b/isofs/cd9660/cd9660_node.c	2026-09-08 13:09:29.853631196 +0000
@@ -126,6 +126,8 @@
 				break;
 		}
 		if (ip == NULL || ITOV(ip) != vp) {
+			/* hash state changed while we were blocked */
+			vput(vp);
 			goto loop;
 		}
 		lwkt_reltoken(&cd9660_ihash_token);
@@ -181,6 +183,32 @@
 }
 
 /*
+ * Discard a freshly allocated iso_node whose vget_internal() setup failed
+ * AFTER the node was published in the ihash (cd9660_ihashins).  The error
+ * paths used to vx_put() the vnode with the node still hashed, handing the
+ * orphaned half-initialized VNON vnode (i_mnt == NULL, i_devvp == NULL)
+ * to any concurrent cd9660_ihashget() blocked in vget() on the same
+ * (dev, ino) -- it would return it as a SUCCESS.
+ *
+ * vp->v_data is cleared first so the later reclaim (refcount -> 0 via
+ * vx_put/vput -> cd9660_inactive/reclaim) skips the normal processing:
+ * the node is already off the hash and freed here.  cd9660_inactive() and
+ * cd9660_reclaim() tolerate a NULL v_data.
+ */
+void
+cd9660_ihashpurge(struct vnode *vp, struct iso_node *ip)
+{
+
+	vp->v_data = NULL;
+	cd9660_ihashrem(ip);
+	if (ip->i_devvp != NULL) {
+		vrele(ip->i_devvp);
+		ip->i_devvp = NULL;
+	}
+	kfree(ip, M_ISOFSNODE);
+}
+
+/*
  * Last reference to an inode, write the inode out and if necessary,
  * truncate and deallocate the file.
  *

--- a/isofs/cd9660/cd9660_node.h	2026-09-08 13:09:29.861631092 +0000
+++ b/isofs/cd9660/cd9660_node.h	2026-09-08 13:09:29.857631143 +0000
@@ -121,6 +121,7 @@
 			struct iso_node *, struct buf *, enum ISO_FTYPE);
 struct vnode *cd9660_ihashget(cdev_t, ino_t);
 int cd9660_ihashins(struct iso_node *);
+void cd9660_ihashpurge(struct vnode *, struct iso_node *);
 int cd9660_tstamp_conv7(u_char *, struct timespec *, enum ISO_FTYPE);
 int cd9660_tstamp_conv17(u_char *, struct timespec *);
 

--- a/isofs/cd9660/cd9660_vfsops.c	2026-09-08 13:09:29.873630936 +0000
+++ b/isofs/cd9660/cd9660_vfsops.c	2026-09-08 13:09:29.857631143 +0000
@@ -773,6 +773,7 @@
 
 		lbn = lblkno(imp, ino);
 		if (lbn >= imp->volume_space_size) {
+			cd9660_ihashpurge(vp, ip);
 			vx_put(vp);
 			kprintf("fhtovp: lbn exceed volume space %d\n", lbn);
 			return (ESTALE);
@@ -780,6 +781,7 @@
 
 		off = blkoff(imp, ino);
 		if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
+			cd9660_ihashpurge(vp, ip);
 			vx_put(vp);
 			kprintf("fhtovp: crosses block boundary %d\n",
 			       off + ISO_DIRECTORY_RECORD_SIZE);
@@ -790,6 +792,7 @@
 			      lblktooff(imp, lbn),
 			      imp->logical_block_size, &bp);
 		if (error) {
+			cd9660_ihashpurge(vp, ip);
 			vx_put(vp);
 			brelse(bp);
 			kprintf("fhtovp: bread error %d\n",error);
@@ -799,6 +802,7 @@
 
 		if (off + isonum_711(isodir->length) >
 		    imp->logical_block_size) {
+			cd9660_ihashpurge(vp, ip);
 			vx_put(vp);
 			if (bp != NULL)
 				brelse(bp);
@@ -835,6 +839,8 @@
 		if (bp != NULL)
 			brelse(bp);
 		if ((error = cd9660_devblkatoff(vp, (off_t)0, NULL, &bp)) != 0) {
+			/* i_devvp was vref'd; ihashpurge vrele()s it */
+			cd9660_ihashpurge(vp, ip);
 			vx_put(vp);
 			return (error);
 		}