Skip to content

Commit 3d4df40

Browse files
gcabidduherbertx
authored andcommitted
crypto: qat - flush misc workqueue during device shutdown
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: e5745f3 ("crypto: qat - enable power management for QAT GEN4") Signed-off-by: Giovanni Cabiddu <[email protected]> Cc: [email protected] Reviewed-by: Ahsan Atta <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 3471c89 commit 3d4df40

File tree

3 files changed

+7
-0
lines changed

3 files changed

+7
-0
lines changed

drivers/crypto/intel/qat/qat_common/adf_common_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ void adf_exit_misc_wq(void);
189189
bool adf_misc_wq_queue_work(struct work_struct *work);
190190
bool adf_misc_wq_queue_delayed_work(struct delayed_work *work,
191191
unsigned long delay);
192+
void adf_misc_wq_flush(void);
192193
#if defined(CONFIG_PCI_IOV)
193194
int adf_sriov_configure(struct pci_dev *pdev, int numvfs);
194195
void adf_disable_sriov(struct adf_accel_dev *accel_dev);

drivers/crypto/intel/qat/qat_common/adf_init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
404404
hw_data->exit_admin_comms(accel_dev);
405405

406406
adf_cleanup_etr_data(accel_dev);
407+
adf_misc_wq_flush();
407408
adf_dev_restore(accel_dev);
408409
}
409410

drivers/crypto/intel/qat/qat_common/adf_isr.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,8 @@ bool adf_misc_wq_queue_delayed_work(struct delayed_work *work,
407407
{
408408
return queue_delayed_work(adf_misc_wq, work, delay);
409409
}
410+
411+
void adf_misc_wq_flush(void)
412+
{
413+
flush_workqueue(adf_misc_wq);
414+
}

0 commit comments

Comments
 (0)