DragonFlyBSD Kernel Audit
DF-0846 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/ufs/ufs_quota.c b/sys/vfs/ufs/ufs_quota.c
--- a/sys/vfs/ufs/ufs_quota.c
+++ b/sys/vfs/ufs/ufs_quota.c
@@ -434,13 +434,26 @@
 	nlookup_done(&nd);
 
 	vn_unlock(vp);
-	if (*vpp != vp)
+	if (*vpp != vp) {
 		ufs_quotaoff(mp, type);
+	} else {
+		/*
+		 * Same quota vnode re-supplied (e.g. Q_QUOTAON on an
+		 * already-active quota file).  quotaoff() is skipped so the
+		 * extra reference taken by vn_open() above is never released,
+		 * and um_cred[type] still points at the previous credential.
+		 * Drop both to avoid leaking a vnode reference and a struct
+		 * ucred on every re-enable call.  The reference retained by
+		 * um_quotas[type] keeps vp alive across this vn_close().
+		 */
+		vn_close(vp, FREAD|FWRITE, NULL);
+		if (ump->um_cred[type] != NOCRED)
+			crfree(ump->um_cred[type]);
+	}
 	ump->um_qflags[type] |= QTF_OPENING;
 	mp->mnt_flag |= MNT_QUOTA;
 	vsetflags(vp, VSYSTEM);
 	*vpp = vp;
-	/* XXX release duplicate vp if *vpp == vp? */
 	/*
 	 * Save the credential of the process that turned on quotas.
 	 * Set up the time limits for this quota.