scsi_bsg_uring_task_cb() copies the sense data to the submitter's
response_addr with copy_to_user(). It runs as io_uring task work, but
io_uring may also run it with tw.cancel set from other contexts when the
submitting task can't run it: from a kworker when the submitting task
has exited (io_tctx_fallback_work()), or from io_cancel_local_task_work()
when a DEFER_TASKRUN ring is torn down.
In a kworker, current->mm is NULL, and the copy does not reliably fail:
the user half of the address space belongs to whatever mm happens to be
lazily loaded, if any, so up to max_response_len bytes of sense data may
be written into an unrelated process.
Don't copy the sense data when the task work is canceled, and complete
the command with -ECANCELED.
Fixes: 7b6d3255e7f8 ("scsi: bsg: add io_uring passthrough handler")
Signed-off-by: James Houghton <[email protected]>
---
drivers/scsi/scsi_bsg.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c
index 5eec248a77a6..3755e33fcdd2 100644
--- a/drivers/scsi/scsi_bsg.c
+++ b/drivers/scsi/scsi_bsg.c
@@ -43,9 +43,17 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req,
io_tw_token_t tw)
if (pdu->bio)
blk_rq_unmap_user(pdu->bio);
+ /*
+ * If the request is being canceled, e.g. because the submitting task
+ * has exited, this may run from a kworker or in a different task, so
+ * don't copy the sense data to the submitter's address.
+ */
+ if (unlikely(tw.cancel))
+ ret = -ECANCELED;
+
if (scsi_status_is_check_condition(scmd->result)) {
driver_status = DRIVER_SENSE;
- if (pdu->response_addr)
+ if (pdu->response_addr && !tw.cancel)
sense_len_wr = min_t(unsigned int,
pdu->max_response_len,
scmd->sense_len);
}
--
2.56.0.307.g5fe7bd680c-goog