diff --git a/sys/kern/subr_diskiocom.c b/sys/kern/subr_diskiocom.c --- a/sys/kern/subr_diskiocom.c +++ b/sys/kern/subr_diskiocom.c @@ -383,11 +383,25 @@ done: if (reterr) { if (msg->any.head.cmd & DMSGF_DELETE) { - if (iost && iost->count == 0) { - kfree(iost, M_DEVBUF); - msg->state->any.any = NULL; + if (iost && iost->count > 0) { + /* + * I/O still in flight: defer the DELETE reply to + * diskiodone. Replying now would let cleanuptx + * tear down the state (parent=NULL, removed from + * rbtree) while async disk I/O still holds a raw + * pointer to it in bio_caller_info1.ptr -- UAF in + * diskiodone (DF-0117). Setting eof=1 makes the + * last diskiodone send the DELETE reply itself, + * after all derefs are done. + */ + iost->eof = 1; + } else { + if (iost) { + kfree(iost, M_DEVBUF); + msg->state->any.any = NULL; + } + kdmsg_msg_reply(msg, error); } - kdmsg_msg_reply(msg, error); } else { kdmsg_msg_result(msg, error); } @@ -459,11 +473,25 @@ done: if (reterr) { if (msg->any.head.cmd & DMSGF_DELETE) { - if (iost && iost->count == 0) { - kfree(iost, M_DEVBUF); - msg->state->any.any = NULL; + if (iost && iost->count > 0) { + /* + * I/O still in flight: defer the DELETE reply to + * diskiodone. Replying now would let cleanuptx + * tear down the state (parent=NULL, removed from + * rbtree) while async disk I/O still holds a raw + * pointer to it in bio_caller_info1.ptr -- UAF in + * diskiodone (DF-0117). Setting eof=1 makes the + * last diskiodone send the DELETE reply itself, + * after all derefs are done. + */ + iost->eof = 1; + } else { + if (iost) { + kfree(iost, M_DEVBUF); + msg->state->any.any = NULL; + } + kdmsg_msg_reply(msg, error); } - kdmsg_msg_reply(msg, error); } else { kdmsg_msg_result(msg, error); } @@ -510,11 +538,25 @@ } if (reterr) { if (msg->any.head.cmd & DMSGF_DELETE) { - if (iost && iost->count == 0) { - kfree(iost, M_DEVBUF); - msg->state->any.any = NULL; + if (iost && iost->count > 0) { + /* + * I/O still in flight: defer the DELETE reply to + * diskiodone. Replying now would let cleanuptx + * tear down the state (parent=NULL, removed from + * rbtree) while async disk I/O still holds a raw + * pointer to it in bio_caller_info1.ptr -- UAF in + * diskiodone (DF-0117). Setting eof=1 makes the + * last diskiodone send the DELETE reply itself, + * after all derefs are done. + */ + iost->eof = 1; + } else { + if (iost) { + kfree(iost, M_DEVBUF); + msg->state->any.any = NULL; + } + kdmsg_msg_reply(msg, error); } - kdmsg_msg_reply(msg, error); } else { kdmsg_msg_result(msg, error); } @@ -561,11 +603,25 @@ } if (reterr) { if (msg->any.head.cmd & DMSGF_DELETE) { - if (iost && iost->count == 0) { - kfree(iost, M_DEVBUF); - msg->state->any.any = NULL; + if (iost && iost->count > 0) { + /* + * I/O still in flight: defer the DELETE reply to + * diskiodone. Replying now would let cleanuptx + * tear down the state (parent=NULL, removed from + * rbtree) while async disk I/O still holds a raw + * pointer to it in bio_caller_info1.ptr -- UAF in + * diskiodone (DF-0117). Setting eof=1 makes the + * last diskiodone send the DELETE reply itself, + * after all derefs are done. + */ + iost->eof = 1; + } else { + if (iost) { + kfree(iost, M_DEVBUF); + msg->state->any.any = NULL; + } + kdmsg_msg_reply(msg, error); } - kdmsg_msg_reply(msg, error); } else { kdmsg_msg_result(msg, error); }