* [GIT PULL] SCSI fixes for 7.3-rc7+
@ 2026-10-18 14:38 James Bottomley
2026-10-18 15:01 ` sashiko-bot
2026-10-18 19:22 ` pr-tracker-bot
0 siblings, 2 replies; 3+ messages in thread
From: James Bottomley @ 2026-10-18 14:38 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds; +Cc: linux-scsi, linux-kernel
The following changes since commit 469fa055664bfd8717b087a80d59c03055789c17:
scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ (2026-10-05 22:05:13 -0400)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git/ tags/scsi-fixes
for you to fetch changes up to ec6b083915e8146e147314a5f4f1285d07b57bfc:
scsi: bsg: Pass reply_len to bsg_setup_queue() to fit UFS ARPMB replies (2026-10-14 22:14:52 -0400)
----------------------------------------------------------------
All fixes in drivers (or the tape ULD) and one core fix to bsg (the
block ioctl equivalent of sg_io). The biggest is the race in auth
updates fix in iscsi configfs, but the next biggest one is in bsg but
the generic pieces of that are mostly threading reply_len.
----------------------------------------------------------------
Laurence Oberman (2):
scsi: st: Save the visited block for the partition the drive is in
scsi: st: Fix use-after-free race between st_remove() and st_open()
Linfeng Sun (1):
scsi: target: iscsi: Fix race in discovery auth updates
Stanley Jhu (1):
scsi: bsg: Pass reply_len to bsg_setup_queue() to fit UFS ARPMB replies
Xingui Yang (1):
scsi: libsas: Fix SMP IO deadlock during HA resume
Yehyeong Lee (4):
scsi: xen/scsifront: Check for a NULL shadow entry on a backend response
scsi: libiscsi: Reject a negative task index from parse_pdu_itt
scsi: libiscsi: Validate the ITT reflected in a Reject PDU
scsi: libiscsi: Validate the task named by a management response
Yu Zhang (1):
scsi: target: Disable interrupts while holding delayed_cmd_lock
block/bsg-lib.c | 13 ++++++++++---
drivers/scsi/libiscsi.c | 14 ++++++++------
drivers/scsi/libsas/sas_expander.c | 14 ++++++++++++--
drivers/scsi/mpi3mr/mpi3mr_app.c | 2 +-
drivers/scsi/scsi_transport_fc.c | 6 ++++--
drivers/scsi/scsi_transport_iscsi.c | 2 +-
drivers/scsi/scsi_transport_sas.c | 6 ++++--
drivers/scsi/st.c | 18 ++++++++++++------
drivers/scsi/xen-scsifront.c | 1 +
drivers/target/iscsi/iscsi_target_configfs.c | 26 +++++++++++++++++++-------
drivers/target/target_core_transport.c | 8 ++++----
drivers/ufs/core/ufs_bsg.c | 2 +-
include/linux/bsg-lib.h | 3 ++-
13 files changed, 79 insertions(+), 36 deletions(-)
---
diff --git a/block/bsg-lib.c b/block/bsg-lib.c
index 895db30a7033..536cee4430a7 100644
--- a/block/bsg-lib.c
+++ b/block/bsg-lib.c
@@ -23,11 +23,14 @@ struct bsg_set {
struct bsg_device *bd;
bsg_job_fn *job_fn;
bsg_timeout_fn *timeout_fn;
+ unsigned int reply_len;
};
static int bsg_transport_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
bool open_for_write, unsigned int timeout)
{
+ struct bsg_set *bset =
+ container_of(q->tag_set, struct bsg_set, tag_set);
struct bsg_job *job;
struct request *rq;
struct bio *bio;
@@ -50,7 +53,7 @@ static int bsg_transport_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
reply = job->reply;
memset(job, 0, sizeof(*job));
job->reply = reply;
- job->reply_len = SCSI_SENSE_BUFFERSIZE;
+ job->reply_len = bset->reply_len;
job->dd_data = job + 1;
job->request_len = hdr->request_len;
@@ -301,9 +304,10 @@ static blk_status_t bsg_queue_rq(struct blk_mq_hw_ctx *hctx,
static int bsg_init_rq(struct blk_mq_tag_set *set, struct request *req,
unsigned int hctx_idx, int numa_node)
{
+ struct bsg_set *bset = container_of(set, struct bsg_set, tag_set);
struct bsg_job *job = blk_mq_rq_to_pdu(req);
- job->reply = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+ job->reply = kzalloc(bset->reply_len, GFP_KERNEL);
if (!job->reply)
return -ENOMEM;
return 0;
@@ -358,10 +362,12 @@ static const struct blk_mq_ops bsg_mq_ops = {
* @job_fn: bsg job handler
* @timeout: timeout handler function pointer
* @dd_job_size: size of LLD data needed for each job
+ * @reply_len: size of the reply buffer needed for each job
*/
struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
struct queue_limits *lim, bsg_job_fn *job_fn,
- bsg_timeout_fn *timeout, int dd_job_size)
+ bsg_timeout_fn *timeout, int dd_job_size,
+ unsigned int reply_len)
{
struct bsg_set *bset;
struct blk_mq_tag_set *set;
@@ -374,6 +380,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
bset->job_fn = job_fn;
bset->timeout_fn = timeout;
+ bset->reply_len = reply_len;
set = &bset->tag_set;
set->ops = &bsg_mq_ops;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 5cbc51899de0..5bfdb30b9088 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1142,13 +1142,15 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
spin_unlock(&conn->session->frwd_lock);
spin_lock(&conn->session->back_lock);
} else {
- struct iscsi_task *task;
+ struct iscsi_task *task = NULL;
/*
* Our nop as ping got dropped. We know the target
* and transport are ok so just clean up
*/
- task = iscsi_itt_to_task(conn, rejected_pdu.itt);
- if (!task) {
+ if (!iscsi_verify_itt(conn, rejected_pdu.itt))
+ task = iscsi_itt_to_task(conn, rejected_pdu.itt);
+ if (!task || task->state == ISCSI_TASK_FREE ||
+ task->sc) {
iscsi_conn_printk(KERN_ERR, conn,
"Invalid pdu reject. Could "
"not lookup rejected task.\n");
@@ -1191,7 +1193,7 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
session->tt->parse_pdu_itt(conn, itt, &i, NULL);
else
i = get_itt(itt);
- if (i >= session->cmds_max)
+ if (i < 0 || i >= session->cmds_max)
return NULL;
return session->cmds[i];
@@ -1284,7 +1286,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
case ISCSI_OP_SCSI_TMFUNC_RSP:
case ISCSI_OP_NOOP_IN:
task = iscsi_itt_to_task(conn, hdr->itt);
- if (!task)
+ if (!task || task->state == ISCSI_TASK_FREE || task->sc)
return ISCSI_ERR_BAD_ITT;
break;
default:
@@ -1384,7 +1386,7 @@ int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
return ISCSI_ERR_BAD_ITT;
}
- if (i >= session->cmds_max) {
+ if (i < 0 || i >= session->cmds_max) {
iscsi_conn_printk(KERN_ERR, conn,
"received invalid itt index %u (max cmds "
"%u.\n", i, session->cmds_max);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 811c9eb4fef1..26c2099c28b9 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -62,7 +62,11 @@ static int smp_execute_task_sg(struct domain_device *dev,
to_sas_internal(dev->port->ha->shost->transportt);
struct sas_ha_struct *ha = dev->port->ha;
- pm_runtime_get_sync(ha->dev);
+ /*
+ * Non-blocking: a sync resume here would deadlock against
+ * sas_drain_work() during HA resume.
+ */
+ pm_runtime_get_noresume(ha->dev);
mutex_lock(&dev->ex_dev.cmd_mutex);
for (retry = 0; retry < 3; retry++) {
if (test_bit(SAS_DEV_GONE, &dev->state)) {
@@ -135,7 +139,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
}
}
mutex_unlock(&dev->ex_dev.cmd_mutex);
- pm_runtime_put_sync(ha->dev);
+ pm_runtime_put(ha->dev);
BUG_ON(retry == 3 && task != NULL);
sas_free_task(task);
@@ -2222,6 +2226,11 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
goto out;
}
+ /* The host may have autosuspended, resume it here. */
+ ret = pm_runtime_resume_and_get(dev->port->ha->dev);
+ if (ret)
+ goto out;
+
ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
job->reply_payload.sg_list);
if (ret >= 0) {
@@ -2229,6 +2238,7 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
rcvlen = job->reply_payload.payload_len - ret;
ret = 0;
}
+ pm_runtime_put(dev->port->ha->dev);
out:
bsg_job_done(job, ret, rcvlen);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
index 1353a8ff9c85..094490713d69 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -3053,7 +3053,7 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
}
q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), &lim,
- mpi3mr_bsg_request, NULL, 0);
+ mpi3mr_bsg_request, NULL, 0, SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
ioc_err(mrioc, "%s: bsg registration failed\n",
dev_name(bsg_dev));
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 173ed6373f04..b66365a382c7 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -4345,7 +4345,8 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
scsi_init_limits(shost, &lim);
lim.max_segments = min_not_zero(lim.max_segments, i->f->max_bsg_segments);
q = bsg_setup_queue(dev, bsg_name, &lim, fc_bsg_dispatch,
- fc_bsg_job_timeout, i->f->dd_bsg_size);
+ fc_bsg_job_timeout, i->f->dd_bsg_size,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
dev_err(dev,
"fc_host%d: bsg interface failed to initialize - setup queue\n",
@@ -4378,7 +4379,8 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
scsi_init_limits(shost, &lim);
lim.max_segments = min_not_zero(lim.max_segments, i->f->max_bsg_segments);
q = bsg_setup_queue(dev, dev_name(dev), &lim, fc_bsg_dispatch_prep,
- fc_bsg_job_timeout, i->f->dd_bsg_size);
+ fc_bsg_job_timeout, i->f->dd_bsg_size,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
dev_err(dev, "failed to setup bsg queue\n");
return PTR_ERR(q);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 8aa76f813bcd..b50ff8a1d0a9 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1545,7 +1545,7 @@ iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);
scsi_init_limits(shost, &lim);
q = bsg_setup_queue(dev, bsg_name, &lim, iscsi_bsg_host_dispatch, NULL,
- 0);
+ 0, SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
shost_printk(KERN_ERR, shost, "bsg interface failed to "
"initialize - no request queue\n");
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index d689b9ed08a6..a825966f60e5 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -199,7 +199,8 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
if (rphy) {
q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), NULL,
- sas_smp_dispatch, NULL, 0);
+ sas_smp_dispatch, NULL, 0,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q))
return PTR_ERR(q);
rphy->q = q;
@@ -208,7 +209,8 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
q = bsg_setup_queue(&shost->shost_gendev, name, NULL,
- sas_smp_dispatch, NULL, 0);
+ sas_smp_dispatch, NULL, 0,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q))
return PTR_ERR(q);
to_sas_host_attrs(shost)->q = q;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f1c3c4946637..a757646c8dc6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3217,14 +3217,20 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
partition >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (partition != STp->partition) {
- if (get_location(STp, &blk, &p, 1))
+ /*
+ * Save the location for the partition the drive reports,
+ * not for STp->partition: after a reset STp->partition may
+ * not match the partition the drive is in.
+ */
+ if (get_location(STp, &blk, &p, 1) ||
+ p < 0 || p >= ST_NBR_PARTITIONS)
STps->last_block_valid = 0;
else {
- STps->last_block_valid = 1;
- STps->last_block_visited = blk;
+ STp->ps[p].last_block_valid = 1;
+ STp->ps[p].last_block_visited = blk;
DEBC_printk(STp, "Visited block %d for "
"partition %d saved.\n",
- blk, STp->partition);
+ blk, p);
}
}
@@ -4509,11 +4515,11 @@ static void st_remove(struct scsi_device *SDp)
remove_cdevs(tpnt);
mutex_lock(&st_ref_mutex);
- kref_put(&tpnt->kref, scsi_tape_release);
- mutex_unlock(&st_ref_mutex);
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, index);
spin_unlock(&st_index_lock);
+ kref_put(&tpnt->kref, scsi_tape_release);
+ mutex_unlock(&st_ref_mutex);
}
/**
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 989bcaee42ca..aa44a233eac8 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -367,6 +367,7 @@ static void scsifront_do_response(struct vscsifrnt_info *info,
struct vscsifrnt_shadow *shadow;
if (ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
+ !info->shadow[ring_rsp->rqid] ||
!info->shadow[ring_rsp->rqid]->inflight) {
scsifront_set_error(info, "illegal rqid returned by backend!");
return;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 704ec94383c3..e1aa0af52c65 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -1306,17 +1306,24 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,
return -EINVAL;
}
+ if (iscsit_get_tpg(discovery_tpg) < 0)
+ return -EINVAL;
+
param = iscsi_find_param_from_key(AUTHMETHOD,
discovery_tpg->param_list);
- if (!param)
- return -EINVAL;
+ if (!param) {
+ err = -EINVAL;
+ goto out;
+ }
if (op) {
/*
* Reset the AuthMethod key to CHAP.
*/
- if (iscsi_update_param_value(param, CHAP) < 0)
- return -EINVAL;
+ if (iscsi_update_param_value(param, CHAP) < 0) {
+ err = -EINVAL;
+ goto out;
+ }
discovery_tpg->tpg_attrib.authentication = 1;
iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 1;
@@ -1327,8 +1334,10 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,
/*
* Reset the AuthMethod key to CHAP,None
*/
- if (iscsi_update_param_value(param, "CHAP,None") < 0)
- return -EINVAL;
+ if (iscsi_update_param_value(param, "CHAP,None") < 0) {
+ err = -EINVAL;
+ goto out;
+ }
discovery_tpg->tpg_attrib.authentication = 0;
iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 0;
@@ -1337,7 +1346,10 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,
" Discovery TPG\n");
}
- return count;
+ err = count;
+out:
+ iscsit_put_tpg(discovery_tpg);
+ return err;
}
CONFIGFS_ATTR(iscsi_disc_, enforce_discovery_auth);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index dcfe94594916..67c046549192 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2359,7 +2359,7 @@ void target_do_delayed_work(struct work_struct *work)
struct se_device *dev = container_of(work, struct se_device,
delayed_cmd_work);
- spin_lock(&dev->delayed_cmd_lock);
+ spin_lock_irq(&dev->delayed_cmd_lock);
while (!dev->ordered_sync_in_progress) {
struct se_cmd *cmd;
@@ -2380,12 +2380,12 @@ void target_do_delayed_work(struct work_struct *work)
dev->ordered_sync_in_progress = true;
list_del(&cmd->se_delayed_node);
- spin_unlock(&dev->delayed_cmd_lock);
+ spin_unlock_irq(&dev->delayed_cmd_lock);
__target_execute_cmd(cmd, true);
- spin_lock(&dev->delayed_cmd_lock);
+ spin_lock_irq(&dev->delayed_cmd_lock);
}
- spin_unlock(&dev->delayed_cmd_lock);
+ spin_unlock_irq(&dev->delayed_cmd_lock);
}
static void transport_complete_ordered_sync(struct se_cmd *cmd)
diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c
index 7a66917b3fc0..156637dd76c8 100644
--- a/drivers/ufs/core/ufs_bsg.c
+++ b/drivers/ufs/core/ufs_bsg.c
@@ -258,7 +258,7 @@ int ufs_bsg_probe(struct ufs_hba *hba)
goto out;
q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), NULL, ufs_bsg_request,
- NULL, 0);
+ NULL, 0, sizeof(struct ufs_rpmb_reply));
if (IS_ERR(q)) {
ret = PTR_ERR(q);
device_del(bsg_dev);
diff --git a/include/linux/bsg-lib.h b/include/linux/bsg-lib.h
index 14fa93268630..a697246feeac 100644
--- a/include/linux/bsg-lib.h
+++ b/include/linux/bsg-lib.h
@@ -66,7 +66,8 @@ void bsg_job_done(struct bsg_job *job, int result,
unsigned int reply_payload_rcv_len);
struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
struct queue_limits *lim, bsg_job_fn *job_fn,
- bsg_timeout_fn *timeout, int dd_job_size);
+ bsg_timeout_fn *timeout, int dd_job_size,
+ unsigned int reply_len);
void bsg_remove_queue(struct request_queue *q);
void bsg_job_put(struct bsg_job *job);
int __must_check bsg_job_get(struct bsg_job *job);
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [GIT PULL] SCSI fixes for 7.3-rc7+
2026-10-18 14:38 [GIT PULL] SCSI fixes for 7.3-rc7+ James Bottomley
@ 2026-10-18 15:01 ` sashiko-bot
2026-10-18 19:22 ` pr-tracker-bot
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-10-18 15:01 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] scsi: libiscsi: premature mgmt response frees pending task on conn->mgmtqueue
- [High] scsi: libsas: smp_execute_task_sg() skips runtime resume for sysfs callers
- [High] scsi: libsas: sas_smp_handler() fails with -EACCES when runtime PM is disabled
- [High] scsi: target: iscsi: UAF race on discovery_tpg param_list during login
--
commit f682ddc340c78ec7c00ca8f8ce335b1612f00410
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
SCSI fixes for 7.3-rc7+
This pull request contains SCSI fixes for libiscsi, libsas, st, xen-scsifront,
target, and bsg.
> diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
> index 5cbc51899de00..5bfdb30b9088d 100644
> --- a/drivers/scsi/libiscsi.c
> +++ b/drivers/scsi/libiscsi.c
> @@ -1142,13 +1142,15 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
> spin_unlock(&conn->session->frwd_lock);
> spin_lock(&conn->session->back_lock);
> } else {
> - struct iscsi_task *task;
> + struct iscsi_task *task = NULL;
> /*
> * Our nop as ping got dropped. We know the target
> * and transport are ok so just clean up
> */
> - task = iscsi_itt_to_task(conn, rejected_pdu.itt);
> - if (!task) {
> + if (!iscsi_verify_itt(conn, rejected_pdu.itt))
> + task = iscsi_itt_to_task(conn, rejected_pdu.itt);
> + if (!task || task->state == ISCSI_TASK_FREE ||
> + task->sc) {
> iscsi_conn_printk(KERN_ERR, conn,
> "Invalid pdu reject. Could "
> "not lookup rejected task.\n");
[ ... ]
> @@ -1284,7 +1286,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
> case ISCSI_OP_SCSI_TMFUNC_RSP:
> case ISCSI_OP_NOOP_IN:
> task = iscsi_itt_to_task(conn, hdr->itt);
> - if (!task)
> + if (!task || task->state == ISCSI_TASK_FREE || task->sc)
> return ISCSI_ERR_BAD_ITT;
> break;
> default:
[Severity: Critical]
Can an unsolicited or premature management response PDU or Reject PDU free a
task while it is still queued on conn->mgmtqueue in ISCSI_TASK_PENDING state?
In drivers/scsi/libiscsi.c, iscsi_alloc_mgmt_task() initializes a management
task under session->frwd_lock with refcount = 1, task->sc = NULL, and
task->state = ISCSI_TASK_PENDING:
drivers/scsi/libiscsi.c:iscsi_alloc_mgmt_task() {
...
refcount_set(&task->refcount, 1);
task->conn = conn;
task->sc = NULL;
INIT_LIST_HEAD(&task->running);
task->state = ISCSI_TASK_PENDING;
}
When ihost->workq is used, iscsi_send_mgmt_task() adds task->running to
conn->mgmtqueue while task->state is still ISCSI_TASK_PENDING and refcount is
still 1:
drivers/scsi/libiscsi.c:iscsi_send_mgmt_task() {
...
} else {
list_add_tail(&task->running, &conn->mgmtqueue);
iscsi_conn_queue_xmit(conn);
}
}
The task only transitions to ISCSI_TASK_RUNNING later when iscsi_data_xmit()
dequeues task->running from conn->mgmtqueue and calls iscsi_prep_mgmt_task().
In addition, iscsi_alloc_task() for SCSI commands runs under
session->frwd_lock (not session->back_lock) and sets task->state =
ISCSI_TASK_PENDING before assigning task->sc = sc.
Because both iscsi_handle_reject() and __iscsi_complete_pdu() only check for
task->state == ISCSI_TASK_FREE || task->sc under session->back_lock, a target
response (ISCSI_OP_NOOP_IN, ISCSI_OP_LOGOUT_RSP, ISCSI_OP_LOGIN_RSP,
ISCSI_OP_TEXT_RSP, ISCSI_OP_SCSI_TMFUNC_RSP, or ISCSI_OP_REJECT with
ISCSI_REASON_IMM_CMD_REJECT for ISCSI_OP_NOOP_OUT) naming the ITT of a task in
ISCSI_TASK_PENDING passes this check.
That calls iscsi_complete_task() -> __iscsi_put_task() -> iscsi_free_task(),
which drops task->refcount from 1 to 0 and returns the task to
session->cmdpool.queue via kfifo_in() without unlinking task->running from
conn->mgmtqueue:
drivers/scsi/libiscsi.c:iscsi_free_task() {
...
session->tt->cleanup_task(task);
task->state = ISCSI_TASK_FREE;
task->sc = NULL;
if (conn->login_task == task)
return;
kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
}
When iscsi_data_xmit() subsequently processes conn->mgmtqueue or the task is
reallocated from cmdpool.queue, wouldn't this cause a use-after-free and
conn->mgmtqueue list corruption? Should both checks require task->state !=
ISCSI_TASK_RUNNING instead of task->state == ISCSI_TASK_FREE?
> diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
> index 811c9eb4fef11..26c2099c28b97 100644
> --- a/drivers/scsi/libsas/sas_expander.c
> +++ b/drivers/scsi/libsas/sas_expander.c
> @@ -62,7 +62,11 @@ static int smp_execute_task_sg(struct domain_device *dev,
> to_sas_internal(dev->port->ha->shost->transportt);
> struct sas_ha_struct *ha = dev->port->ha;
>
> - pm_runtime_get_sync(ha->dev);
> + /*
> + * Non-blocking: a sync resume here would deadlock against
> + * sas_drain_work() during HA resume.
> + */
> + pm_runtime_get_noresume(ha->dev);
> mutex_lock(&dev->ex_dev.cmd_mutex);
> for (retry = 0; retry < 3; retry++) {
> if (test_bit(SAS_DEV_GONE, &dev->state)) {
> @@ -135,7 +139,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
> }
> }
> mutex_unlock(&dev->ex_dev.cmd_mutex);
> - pm_runtime_put_sync(ha->dev);
> + pm_runtime_put(ha->dev);
>
> BUG_ON(retry == 3 && task != NULL);
> sas_free_task(task);
[Severity: High]
Does replacing pm_runtime_get_sync(ha->dev) with
pm_runtime_get_noresume(ha->dev) in smp_execute_task_sg() leave sysfs and
exported PHY management callers executing SMP tasks while the SAS host is
runtime-suspended?
Only sas_smp_handler() was updated to resume ha->dev before calling
smp_execute_task_sg(), but three other non-discovery paths invoke
smp_execute_task() -> smp_execute_task_sg() on expander PHYs
(!scsi_is_sas_phy_local(phy)) without waking ha->dev:
1. Reading expander PHY link error sysfs attributes
(show_sas_phy_invalid_dword_count,
show_sas_phy_running_disparity_error_count,
show_sas_phy_loss_of_dword_sync_count, and
show_sas_phy_phy_reset_problem_count in drivers/scsi/scsi_transport_sas.c)
calls sas_get_linkerrors() -> sas_smp_get_phy_events() ->
smp_execute_task() -> smp_execute_task_sg():
drivers/scsi/libsas/sas_init.c:sas_get_linkerrors() {
if (scsi_is_sas_phy_local(phy)) {
...
}
return sas_smp_get_phy_events(phy);
}
2. Writing expander PHY linkrate sysfs attributes
(store_sas_phy_minimum_linkrate and store_sas_phy_maximum_linkrate in
drivers/scsi/scsi_transport_sas.c) calls sas_set_phy_speed() ->
sas_smp_phy_control() -> smp_execute_task() -> smp_execute_task_sg():
drivers/scsi/libsas/sas_init.c:sas_set_phy_speed() {
...
} else {
struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
ret = sas_smp_phy_control(ddev, phy->number,
PHY_FUNC_LINK_RESET, rates);
}
}
3. Calling the exported sas_phy_reset() on an expander PHY calls
sas_smp_phy_control() -> smp_execute_task() -> smp_execute_task_sg()
without resuming ha->dev (unlike the sysfs workqueue wrappers
queue_phy_reset() and queue_phy_enable() in drivers/scsi/libsas/sas_init.c,
which call pm_runtime_get_sync(ha->dev)).
When the controller is runtime-suspended (for example on hisi_sas_v3_hw where
sas_suspend_devices() clears dev->lldd_dev and powers down the hardware),
won't these expander PHY operations fail with -ECOMM or access a suspended
HBA?
> @@ -2222,6 +2226,11 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
> goto out;
> }
>
> + /* The host may have autosuspended, resume it here. */
> + ret = pm_runtime_resume_and_get(dev->port->ha->dev);
> + if (ret)
> + goto out;
> +
> ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
> job->reply_payload.sg_list);
> if (ret >= 0) {
[Severity: High]
Won't pm_runtime_resume_and_get(dev->port->ha->dev) fail with -EACCES on
platform-bus libsas controllers that do not enable runtime PM, such as
hisi_sas_v1_hw and hisi_sas_v2_hw?
Previously, smp_execute_task_sg() called pm_runtime_get_sync(ha->dev) and did
not check its return value. In drivers/base/power/runtime.c:rpm_resume(), when
dev->power.disable_depth > 0 and !(rpmflags & RPM_TRANSPARENT), it returns 1
only if runtime_status and last_status are both RPM_ACTIVE, and returns
-EACCES otherwise:
drivers/base/power/runtime.c:rpm_resume() {
if (dev->power.runtime_error) {
retval = -EINVAL;
} else if (dev->power.disable_depth > 0) {
if (dev->power.runtime_status == RPM_ACTIVE &&
dev->power.last_status == RPM_ACTIVE)
retval = 1;
else if (rpmflags & RPM_TRANSPARENT)
goto out;
else
retval = -EACCES;
}
}
Unlike PCI devices (where pci_pm_init() calls pm_runtime_set_active()),
platform devices are initialized by pm_runtime_init() with disable_depth = 1,
runtime_status = RPM_SUSPENDED, and last_status = RPM_INVALID. In
drivers/scsi/hisi_sas/hisi_sas_main.c:hisi_sas_probe(), platform controllers
set sha->dev = hisi_hba->dev (&pdev->dev) without calling
pm_runtime_set_active() or pm_runtime_enable(), so every expander BSG request
in sas_smp_handler() will abort at if (ret) goto out with -EACCES when
CONFIG_PM=y.
> diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
> index 704ec94383c3c..e1aa0af52c658 100644
> --- a/drivers/target/iscsi/iscsi_target_configfs.c
> +++ b/drivers/target/iscsi/iscsi_target_configfs.c
> @@ -1306,17 +1306,24 @@ static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,
> return -EINVAL;
> }
>
> + if (iscsit_get_tpg(discovery_tpg) < 0)
> + return -EINVAL;
> +
> param = iscsi_find_param_from_key(AUTHMETHOD,
> discovery_tpg->param_list);
> - if (!param)
> - return -EINVAL;
> + if (!param) {
> + err = -EINVAL;
> + goto out;
> + }
>
> if (op) {
> /*
> * Reset the AuthMethod key to CHAP.
> */
> - if (iscsi_update_param_value(param, CHAP) < 0)
> - return -EINVAL;
> + if (iscsi_update_param_value(param, CHAP) < 0) {
> + err = -EINVAL;
> + goto out;
> + }
>
> discovery_tpg->tpg_attrib.authentication = 1;
> iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 1;
[Severity: High]
Does acquiring discovery_tpg->tpg_access_lock via iscsit_get_tpg() prevent the
use-after-free race against concurrent discovery logins?
In drivers/target/iscsi/iscsi_target_parameters.c, iscsi_update_param_value()
frees param->value and reallocates it in place:
drivers/target/iscsi/iscsi_target_parameters.c:iscsi_update_param_value() {
kfree(param->value);
param->value = kstrdup(value, GFP_KERNEL);
...
}
However, the discovery login path does not acquire
discovery_tpg->tpg_access_lock. When an initiator logs into a discovery
session, iscsi_target_locate_portal() in
drivers/target/iscsi/iscsi_target_nego.c sets conn->tpg =
iscsit_global->discovery_tpg and calls iscsit_access_np(np, conn->tpg), which
only takes discovery_tpg->np_login_sem:
drivers/target/iscsi/iscsi_target_nego.c:iscsi_target_locate_portal() {
...
conn->tpg = iscsit_global->discovery_tpg;
if (iscsit_access_np(np, conn->tpg) < 0) {
...
}
Then iscsi_login_zero_tsih_s2() in drivers/target/iscsi/iscsi_target_login.c
calls iscsi_copy_param_list(), which reads param->value while holding only
discovery_tpg->np_login_sem:
drivers/target/iscsi/iscsi_target_login.c:iscsi_login_zero_tsih_s2() {
...
if (iscsi_copy_param_list(&conn->param_list,
conn->tpg->param_list, 1) < 0) {
...
}
drivers/target/iscsi/iscsi_target_parameters.c:iscsi_copy_param_list() {
...
new_param->name = kstrdup(param->name, GFP_KERNEL);
new_param->value = kstrdup(param->value, GFP_KERNEL);
...
}
Since iscsi_disc_enforce_discovery_auth_store() holds only tpg_access_lock and
discovery login holds only np_login_sem, can kfree(param->value) in
iscsi_update_param_value() still race with kstrdup(param->value, GFP_KERNEL)
in iscsi_copy_param_list()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/6a4bfcdc8e60669d95abb70bdaa07b87154c9a95.camel@HansenPartnership.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [GIT PULL] SCSI fixes for 7.3-rc7+
2026-10-18 14:38 [GIT PULL] SCSI fixes for 7.3-rc7+ James Bottomley
2026-10-18 15:01 ` sashiko-bot
@ 2026-10-18 19:22 ` pr-tracker-bot
1 sibling, 0 replies; 3+ messages in thread
From: pr-tracker-bot @ 2026-10-18 19:22 UTC (permalink / raw)
To: James Bottomley; +Cc: Andrew Morton, Linus Torvalds, linux-scsi, linux-kernel
The pull request you sent on Sun, 18 Oct 2026 10:38:55 -0400:
> https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git/ tags/scsi-fixes
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/f909e534f5e34feb2ea2701d54df63e21aa506fc
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-18 19:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-18 14:38 [GIT PULL] SCSI fixes for 7.3-rc7+ James Bottomley
2026-10-18 15:01 ` sashiko-bot
2026-10-18 19:22 ` pr-tracker-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox