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: 29387fd2129a ("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 a587ed5c3b95..c8099a1a3f7b 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -325,7 +325,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) @@ -398,10 +401,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) 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_simple_get(&host_index_ida, 0, 0, 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 4da5b13bdafc..803fd7251346 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -77,7 +77,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; @@ -110,7 +112,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 208a4a3e9bd9..392fff5425c7 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -527,6 +527,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 @@ -698,13 +703,10 @@ struct Scsi_Host { */ struct device *dma_dev; - /* Used for an rcu-synchronizing eh wakeup */ - struct work_struct eh_work; - KABI_USE(1, bool is_builtin) KABI_REPLACE(_KABI_RESERVE(2); _KABI_RESERVE(3), struct list_head eh_abort_list) - KABI_RESERVE(4) + KABI_USE(4, struct scsi_host_eh_work *eh_work) KABI_RESERVE(5) KABI_RESERVE(6) -- 2.52.0