DragonFlyBSD Kernel Audit
DF-2499 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/nata/atapi-cam.c b/sys/dev/disk/nata/atapi-cam.c
--- a/sys/dev/disk/nata/atapi-cam.c
+++ b/sys/dev/disk/nata/atapi-cam.c
@@ -881,8 +881,14 @@
     struct atapi_hcb *hcb;
 
     if (scp != NULL) {
+	struct atapi_hcb *hcb_tmp;
+
 	lockmgr(&scp->state_lock, LK_EXCLUSIVE);
-	TAILQ_FOREACH(hcb, &scp->pending_hcbs, chain) {
+	/* free_hcb() kfree()s each hcb inside the loop body; the plain
+	 * TAILQ_FOREACH macro would then dereference the freed element's
+	 * tqe_next pointer (UAF read).  Use the _MUTABLE variant which caches
+	 * the next pointer before the body runs.  See DF-2499. */
+	TAILQ_FOREACH_MUTABLE(hcb, &scp->pending_hcbs, chain, hcb_tmp) {
 	    free_hcb_and_ccb_done(hcb, CAM_UNREC_HBA_ERROR);
 	}
 	lockmgr(&scp->state_lock, LK_RELEASE);