--- 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: