pse_controller_unregister() frees the PI array with pse_release_pis() while the controller is still linked on pse_controller_list, and only removes it from the list afterwards. A concurrent consumer probe running of_pse_control_get() walks that list under pse_list_mutex and calls of_pse_match_pi(), which dereferences pcdev->pi[i].np. If the walk lands on a controller that is being torn down, it reads the freed (with the previous patch, NULLed) PI array. Move the list_del() ahead of pse_release_pis(). Both the lookup and the removal serialise on pse_list_mutex, so once the controller is unlinked no new lookup can reach it, and any lookup already in progress holds the mutex and has matched against a live pi before the free can run. No NULL checks are needed on the lookup path. Fixes: 9be9567a7c59 ("net: pse-pd: Add support for PSE PIs") Signed-off-by: Carlo Szelinsky --- drivers/net/pse-pd/pse_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c index 21ccb5146616..2a9a07dc8c48 100644 --- a/drivers/net/pse-pd/pse_core.c +++ b/drivers/net/pse-pd/pse_core.c @@ -1143,11 +1143,15 @@ void pse_controller_unregister(struct pse_controller_dev *pcdev) disable_irq(pcdev->irq); cancel_work_sync(&pcdev->ntf_work); pse_flush_pw_ds(pcdev); - pse_release_pis(pcdev); - kfifo_free(&pcdev->ntf_fifo); + /* Unlink before freeing pcdev->pi: of_pse_control_get() walks the + * list under pse_list_mutex and dereferences pcdev->pi[] via + * of_pse_match_pi(), so a lookup must never reach a freed array. + */ mutex_lock(&pse_list_mutex); list_del(&pcdev->list); mutex_unlock(&pse_list_mutex); + pse_release_pis(pcdev); + kfifo_free(&pcdev->ntf_fifo); } EXPORT_SYMBOL_GPL(pse_controller_unregister); -- 2.43.0