| From 3d4df408ba9bad2b205c7fb8afc1836a6a4ca88a Mon Sep 17 00:00:00 2001 |
| From: Giovanni Cabiddu <giovanni.cabiddu@intel.com> |
| Date: Fri, 11 Jul 2025 13:27:43 +0100 |
| Subject: crypto: qat - flush misc workqueue during device shutdown |
| |
| From: Giovanni Cabiddu <giovanni.cabiddu@intel.com> |
| |
| commit 3d4df408ba9bad2b205c7fb8afc1836a6a4ca88a upstream. |
| |
| Repeated loading and unloading of a device specific QAT driver, for |
| example qat_4xxx, in a tight loop can lead to a crash due to a |
| use-after-free scenario. This occurs when a power management (PM) |
| interrupt triggers just before the device-specific driver (e.g., |
| qat_4xxx.ko) is unloaded, while the core driver (intel_qat.ko) remains |
| loaded. |
| |
| Since the driver uses a shared workqueue (`qat_misc_wq`) across all |
| devices and owned by intel_qat.ko, a deferred routine from the |
| device-specific driver may still be pending in the queue. If this |
| routine executes after the driver is unloaded, it can dereference freed |
| memory, resulting in a page fault and kernel crash like the following: |
| |
| BUG: unable to handle page fault for address: ffa000002e50a01c |
| #PF: supervisor read access in kernel mode |
| RIP: 0010:pm_bh_handler+0x1d2/0x250 [intel_qat] |
| Call Trace: |
| pm_bh_handler+0x1d2/0x250 [intel_qat] |
| process_one_work+0x171/0x340 |
| worker_thread+0x277/0x3a0 |
| kthread+0xf0/0x120 |
| ret_from_fork+0x2d/0x50 |
| |
| To prevent this, flush the misc workqueue during device shutdown to |
| ensure that all pending work items are completed before the driver is |
| unloaded. |
| |
| Note: This approach may slightly increase shutdown latency if the |
| workqueue contains jobs from other devices, but it ensures correctness |
| and stability. |
| |
| Fixes: e5745f34113b ("crypto: qat - enable power management for QAT GEN4") |
| Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com> |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Ahsan Atta <ahsan.atta@intel.com> |
| Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/crypto/intel/qat/qat_common/adf_common_drv.h | 1 + |
| drivers/crypto/intel/qat/qat_common/adf_init.c | 1 + |
| drivers/crypto/intel/qat/qat_common/adf_isr.c | 5 +++++ |
| 3 files changed, 7 insertions(+) |
| |
| --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h |
| +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h |
| @@ -193,6 +193,7 @@ void adf_exit_misc_wq(void); |
| bool adf_misc_wq_queue_work(struct work_struct *work); |
| bool adf_misc_wq_queue_delayed_work(struct delayed_work *work, |
| unsigned long delay); |
| +void adf_misc_wq_flush(void); |
| #if defined(CONFIG_PCI_IOV) |
| int adf_sriov_configure(struct pci_dev *pdev, int numvfs); |
| void adf_disable_sriov(struct adf_accel_dev *accel_dev); |
| --- a/drivers/crypto/intel/qat/qat_common/adf_init.c |
| +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c |
| @@ -381,6 +381,7 @@ static void adf_dev_shutdown(struct adf_ |
| hw_data->exit_admin_comms(accel_dev); |
| |
| adf_cleanup_etr_data(accel_dev); |
| + adf_misc_wq_flush(); |
| adf_dev_restore(accel_dev); |
| } |
| |
| --- a/drivers/crypto/intel/qat/qat_common/adf_isr.c |
| +++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c |
| @@ -386,3 +386,8 @@ bool adf_misc_wq_queue_delayed_work(stru |
| { |
| return queue_delayed_work(adf_misc_wq, work, delay); |
| } |
| + |
| +void adf_misc_wq_flush(void) |
| +{ |
| + flush_workqueue(adf_misc_wq); |
| +} |