DragonFlyBSD Kernel Audit
DF-2876 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_diskiocom.c	2026-09-02 18:33:18.862281095 +0000
+++ b/sys/kern/subr_diskiocom.c	2026-09-02 18:33:36.210063774 +0000
@@ -425,6 +425,8 @@
 		 * the buffer cache buffer for the case where we can just
 		 * use the message's data pointer.
 		 */
+		kdmsg_data_t *adata;
+
 		reterr = 0;
 		if (msg->aux_size >= msg->any.blk_write.bytes)
 			bp = getpbuf(NULL);
@@ -435,14 +437,25 @@
 		bp->b_cmd = BUF_CMD_WRITE;
 		bp->b_bcount = msg->any.blk_write.bytes;
 		bp->b_resid = bp->b_bcount;
+		bio->bio_caller_info2.ptr = NULL;
 		if (msg->aux_size >= msg->any.blk_write.bytes) {
+			/*
+			 * DF-2875: the detached aux buffer must be owned by
+			 * THIS bio, not by the shared single-slot
+			 * iost->data.  Pipelined writes in one transaction
+			 * used to overwrite the slot, freeing the most
+			 * recent buffer while its bio was still in flight
+			 * and leaking all earlier ones.
+			 */
 			bp->b_data = msg->aux_data;
-			kdmsg_detach_aux_data(msg, &iost->data);
+			adata = kmalloc(sizeof(*adata), M_DEVBUF,
+					M_WAITOK | M_ZERO);
+			kdmsg_detach_aux_data(msg, adata);
+			bio->bio_caller_info2.ptr = adata;
 		} else {
 			bcopy(msg->aux_data, bp->b_data, msg->aux_size);
 			bzero(bp->b_data + msg->aux_size,
 			      msg->any.blk_write.bytes - msg->aux_size);
-			bzero(&iost->data, sizeof(iost->data));
 		}
 		bio->bio_offset = msg->any.blk_write.offset;
 		bio->bio_caller_info1.ptr = msg->state;
@@ -595,6 +608,17 @@
 		cmd = DMSG_LNK_ERROR;
 		data = bp->b_data;
 		bytes = bp->b_bcount;
+		/*
+		 * DF-2876: on error or short reads the buffer content is
+		 * stale (whatever a previous pbuf user left behind); do
+		 * not disclose it.  Return only completed bytes.
+		 */
+		if (bp->b_flags & B_ERROR) {
+			data = NULL;
+			bytes = 0;
+		} else if (bp->b_resid) {
+			bytes = bp->b_bcount - bp->b_resid;
+		}
 		/* fall through */
 	case BUF_CMD_WRITE:
 		if (bp->b_flags & B_ERROR) {
@@ -603,7 +627,18 @@
 			error = 0;
 			resid = bp->b_resid;
 		}
-		kdmsg_free_aux_data(&iost->data);
+		/*
+		 * DF-2875: free exactly the aux data owned by THIS bio,
+		 * not the shared iost->data slot.
+		 */
+		{
+			kdmsg_data_t *adata = bio->bio_caller_info2.ptr;
+			if (adata) {
+				kdmsg_free_aux_data(adata);
+				kfree(adata, M_DEVBUF);
+				bio->bio_caller_info2.ptr = NULL;
+			}
+		}
 		break;
 	case BUF_CMD_FLUSH:
 	case BUF_CMD_FREEBLKS: