[PATCH OLK-6.6 0/2] CVE-2026-68396
CVE-2026-68396 Zhou Minqiang (2): scsi: core: wake eh reliably when using scsi_schedule_eh scsi: core: Fix kabi breakage of struct Scsi_Host drivers/scsi/hosts.c | 13 +++++++++++++ drivers/scsi/scsi_error.c | 24 +++++++++++++++++++++++- drivers/scsi/scsi_priv.h | 1 + include/scsi/scsi_host.h | 7 ++++++- 4 files changed, 43 insertions(+), 2 deletions(-) -- 2.52.0
mainline inclusion from mainline-v7.2-rc4 commit dccf3b1798b70f94e958b3d00b83010399e6fb05 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17046 CVE: CVE-2026-68396 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Drivers which use the scsi_schedule_eh function to run the error handler currently risk the error handler thread never waking once all commands are timed out or inactive. There is no enforced memory order between setting the host into error recovery state and counting busy commands. This can result in a race with scsi_dec_host_busy where neither CPU sees both conditions of all commands inactive and the host error state to request waking the error handler. To fix this, run the scsi_schedule_eh's scsi_eh_wakeup from a new work item which will use rcu to ensure scsi_schedule_eh's call to scsi_host_busy will occur after the error state is globally visible and will be seen by any current scsi_dec_host_busy callers. Fixes: 6eb045e092ef ("scsi: core: avoid host-wide host_busy counter for scsi_mq") Signed-off-by: David Jeffery <djeffery@redhat.com> Link: https://patch.msgid.link/20260615174630.11492-1-djeffery@redhat.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Zhou Minqiang <zhouminqiang2@huawei.com> --- drivers/scsi/hosts.c | 2 ++ drivers/scsi/scsi_error.c | 22 +++++++++++++++++++++- drivers/scsi/scsi_priv.h | 1 + include/scsi/scsi_host.h | 3 +++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index f274812aee1e..03c2cb126988 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -344,6 +344,7 @@ static void scsi_host_dev_release(struct device *dev) /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */ rcu_barrier(); + cancel_work_sync(&shost->eh_work); if (shost->tmf_work_q) destroy_workqueue(shost->tmf_work_q); if (shost->ehandler) @@ -409,6 +410,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv INIT_LIST_HEAD(&shost->starved_list); init_waitqueue_head(&shost->host_wait); mutex_init(&shost->scan_mutex); + INIT_WORK(&shost->eh_work, scsi_rcu_eh_wakeup); index = ida_alloc(&host_index_ida, GFP_KERNEL); if (index < 0) { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 18474e441b87..7fe549f40450 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -73,6 +73,26 @@ void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy) } } +void scsi_rcu_eh_wakeup(struct work_struct *work) +{ + struct Scsi_Host *shost = container_of(work, struct Scsi_Host, eh_work); + unsigned long flags; + unsigned int busy; + + /* + * Ensure any running scsi_dec_host_busy has completed its rcu section + * so changes to host state and host_eh_scheduled are visible to all + * future calls of scsi_dec_host_busy + */ + synchronize_rcu(); + + busy = scsi_host_busy(shost); + + spin_lock_irqsave(shost->host_lock, flags); + scsi_eh_wakeup(shost, busy); + spin_unlock_irqrestore(shost->host_lock, flags); +} + /** * scsi_schedule_eh - schedule EH for SCSI host * @shost: SCSI host to invoke error handling on. @@ -88,7 +108,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost) if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { shost->host_eh_scheduled++; - scsi_eh_wakeup(shost, scsi_host_busy(shost)); + queue_work(shost->tmf_work_q, &shost->eh_work); } spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 1fbfe1b52c9f..c4ffe5f53da3 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -93,6 +93,7 @@ extern enum blk_eh_timer_return scsi_timeout(struct request *req); extern int scsi_error_handler(void *host); extern enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *cmd); extern void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy); +extern void scsi_rcu_eh_wakeup(struct work_struct *work); extern void scsi_eh_scmd_add(struct scsi_cmnd *); void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q, diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 9df750d30328..ea64e7f12a51 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -716,6 +716,9 @@ struct Scsi_Host { */ struct device *dma_dev; + /* Used for an rcu-synchronizing eh wakeup */ + struct work_struct eh_work; + KABI_RESERVE(1) KABI_RESERVE(2) KABI_RESERVE(3) -- 2.52.0
Offering: HULK hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17046 CVE: CVE-2026-68396 -------------------------------- Adding struct work_struct eh_work into struct Scsi_Host changes the structure size and breaks kABI for out-of-tree modules. Use KABI_USE(1, struct scsi_host_eh_work *) instead of embedding work_struct directly. The separately allocated scsi_host_eh_work contains a back-pointer to shost so the callback recovers the host via container_of(work, struct scsi_host_eh_work, work). Fixes: ab94a39e2eaf ("scsi: core: wake eh reliably when using scsi_schedule_eh") Signed-off-by: Zhou Minqiang <zhouminqiang2@huawei.com> --- drivers/scsi/hosts.c | 15 +++++++++++++-- drivers/scsi/scsi_error.c | 6 ++++-- include/scsi/scsi_host.h | 10 ++++++---- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 03c2cb126988..5d1aa5fbcbcd 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -344,7 +344,10 @@ static void scsi_host_dev_release(struct device *dev) /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */ rcu_barrier(); - cancel_work_sync(&shost->eh_work); + if (shost->eh_work) { + cancel_work_sync(&shost->eh_work->work); + kfree(shost->eh_work); + } if (shost->tmf_work_q) destroy_workqueue(shost->tmf_work_q); if (shost->ehandler) @@ -410,10 +413,18 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv INIT_LIST_HEAD(&shost->starved_list); init_waitqueue_head(&shost->host_wait); mutex_init(&shost->scan_mutex); - INIT_WORK(&shost->eh_work, scsi_rcu_eh_wakeup); + + shost->eh_work = kzalloc(sizeof(*shost->eh_work), GFP_KERNEL); + if (!shost->eh_work) { + kfree(shost); + return NULL; + } + shost->eh_work->shost = shost; + INIT_WORK(&shost->eh_work->work, scsi_rcu_eh_wakeup); index = ida_alloc(&host_index_ida, GFP_KERNEL); if (index < 0) { + kfree(shost->eh_work); kfree(shost); return NULL; } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 7fe549f40450..c114cff5cff7 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -75,7 +75,9 @@ void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy) void scsi_rcu_eh_wakeup(struct work_struct *work) { - struct Scsi_Host *shost = container_of(work, struct Scsi_Host, eh_work); + struct scsi_host_eh_work *ehw = + container_of(work, struct scsi_host_eh_work, work); + struct Scsi_Host *shost = ehw->shost; unsigned long flags; unsigned int busy; @@ -108,7 +110,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost) if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { shost->host_eh_scheduled++; - queue_work(shost->tmf_work_q, &shost->eh_work); + queue_work(shost->tmf_work_q, &shost->eh_work->work); } spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index ea64e7f12a51..c6dd14528838 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -538,6 +538,11 @@ enum scsi_host_state { SHOST_DEL_RECOVERY, }; +struct scsi_host_eh_work { + struct Scsi_Host *shost; /* back-pointer for callback */ + struct work_struct work; +}; + struct Scsi_Host { /* * __devices is protected by the host_lock, but you should @@ -716,10 +721,7 @@ struct Scsi_Host { */ struct device *dma_dev; - /* Used for an rcu-synchronizing eh wakeup */ - struct work_struct eh_work; - - KABI_RESERVE(1) + KABI_USE(1, struct scsi_host_eh_work *eh_work) KABI_RESERVE(2) KABI_RESERVE(3) KABI_RESERVE(4) -- 2.52.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/27499 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/XUD... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/27499 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/XUD...
participants (2)
-
patchwork bot -
Zhou Minqiang