[PATCH] PCI: switchtec: Fix use-after-free in mrpc_timeout_work

Pei Xiao <[email protected]>
Newsgroups org.kernel.vger.stable,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <e640c79072065c1a347ed25f7ce0fe1ba565f4fe.1786017236.git.xiaopei01@kylinos.cn>
stdev_kill() cancels the works before clearing stdev->alive under
mrpc_mutex. Every path that arms mrpc_timeout holds that mutex, so a
write that already passed the alive check can still schedule
mrpc_timeout after cancel_delayed_work_sync() returns:

CPU0                                      CPU1

                                          | switchtec_dev_write()
                                          | lock_mutex_and_test_alive()
cancel_delayed_work_sync(mrpc_timeout)    |
                                          | mrpc_cmd_submit()
                                          | schedule_delayed_work(mrpc_timeout)
                                          | mutex_unlock(&stdev->mrpc_mutex)
scoped_guard(mutex) { alive = false }     |
put_device() -> kfree(stdev)              |
                                          | mrpc_timeout_work

Fix it by clearing alive under mrpc_mutex before canceling the works, so no
new mrpc_timeout can be armed once alive is cleared.

Fixes: 080b47def5e5 ("MicroSemi Switchtec management interface driver")
Cc: [email protected]
Assisted-by: Codex:deepseek-v4-flash
Signed-off-by: Pei Xiao <[email protected]>
---
 drivers/pci/switch/switchtec.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 235ca1877b6c..9127841b2bf8 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -1323,10 +1323,6 @@ static void stdev_kill(struct switchtec_dev *stdev)
 	if (stdev->dma_mrpc_irq >= 0)
 		devm_free_irq(&stdev->pdev->dev, stdev->dma_mrpc_irq, stdev);
 
-	cancel_work_sync(&stdev->mrpc_work);
-	cancel_work_sync(&stdev->link_event_work);
-	cancel_delayed_work_sync(&stdev->mrpc_timeout);
-
 	/* Mark the hardware as unavailable and complete all completions */
 	scoped_guard (mutex, &stdev->mrpc_mutex) {
 		stdev->alive = false;
@@ -1341,6 +1337,10 @@ static void stdev_kill(struct switchtec_dev *stdev)
 
 	}
 
+	cancel_work_sync(&stdev->mrpc_work);
+	cancel_work_sync(&stdev->link_event_work);
+	cancel_delayed_work_sync(&stdev->mrpc_timeout);
+
 	/* Wake up any users waiting on event_wq */
 	wake_up_interruptible(&stdev->event_wq);
 }
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.