[PATCH v2 2/6] scsi: core: release legacy ioctl request before user copyback

From: Yingjie Wang

Date: Mon Oct 26 2026 - 04:40:46 EST


From: Yingjie Wang <x-professor@xxxxxxxxxxx>

SCSI_IOCTL_SEND_COMMAND copies sense or command data to userspace while
the completed request still occupies its queue tag. A fault that needs
the same queue can therefore wait for a resource held by the ioctl.

Save the command status and the compatibility-limited sense data, then
release the request before copying to userspace. The data buffer is a
separate allocation and remains valid until the existing buffer cleanup.
Keep the positive SCSI status and -EFAULT return conventions unchanged.

This complements the SG_IO fix by covering the legacy
SCSI_IOCTL_SEND_COMMAND path.

Fixes: d285203cf647 ("scsi: add support for a blk-mq based I/O path.")
Link: https://lore.kernel.org/r/20261022.scsi-copyback-review.31b8d6a70f4c@xxxxxxxxxxx
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yingjie Wang <x-professor@xxxxxxxxxxx>
---
drivers/scsi/scsi_ioctl.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 68e84705634c9..95e91ae1332c4 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -533,6 +533,8 @@ static int sg_scsi_ioctl(struct request_queue *q, bool open_for_write,
struct scsi_ioctl_command __user *sic)
{
struct request *rq;
+ u8 sense_buffer[16];
+ unsigned int sense_len = 0;
int err;
unsigned int in_len, out_len, bytes, opcode, cmdlen;
struct scsi_cmnd *scmd;
@@ -621,17 +623,21 @@ static int sg_scsi_ioctl(struct request_queue *q, bool open_for_write,
blk_execute_rq(rq, false);

err = scmd->result & 0xff; /* only 8 bit SCSI status */
+ if (err && scmd->sense_len && scmd->sense_buffer) {
+ /* limit sense len for backward compatibility */
+ sense_len = min(scmd->sense_len, sizeof(sense_buffer));
+ memcpy(sense_buffer, scmd->sense_buffer, sense_len);
+ }
+ blk_mq_free_request(rq);
+
if (err) {
- if (scmd->sense_len && scmd->sense_buffer) {
- /* limit sense len for backward compatibility */
- if (copy_to_user(sic->data, scmd->sense_buffer,
- min(scmd->sense_len, 16U)))
- err = -EFAULT;
- }
+ if (sense_len && copy_to_user(sic->data, sense_buffer, sense_len))
+ err = -EFAULT;
} else {
if (copy_to_user(sic->data, buffer, out_len))
err = -EFAULT;
}
+ goto error_free_buffer;

error:
blk_mq_free_request(rq);
--
2.43.0