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