pse_controller_unregister() frees the PI array, but the PI regulators
are only unregistered after it, by devres. Until then their ops still
run, for example on a read of the regulator's sysfs "state" or when a
consumer enables or disables the PI, and they read the freed array.
Free the PI array from a devm action that is added before the PI
regulators, so devres frees it after them. This also frees it when
registration fails, where it was leaked before.
Triggered in QEMU (arm64, KASAN) with a test-only PSE controller:
reading the PI regulators' sysfs "state" while the controller unbinds
gives
BUG: KASAN: slab-use-after-free in pse_pi_is_enabled+0x294/0x2d4
With this patch it is gone.
Fixes: d83e13761d5b ("net: pse-pd: Use regulator framework within PSE framework")
Signed-off-by: Carlo Szelinsky <redacted>
---
drivers/net/pse-pd/pse_core.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 43f6e304fe5e..eccbdb3acbee 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -147,6 +147,11 @@ static void pse_release_pis(struct pse_controller_dev *pcdev)
kfree(pcdev->pi);
}
+static void devm_pse_release_pis(void *data)
+{
+ pse_release_pis(data);
+}
+
/**
* of_load_pse_pis - load all the PSE PIs
* @pcdev: a pointer to the PSE controller device@@ -1123,6 +1128,13 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
if (ret)
return ret;
+ /* The PI regulator ops use pcdev->pi until devres unregisters the
+ * regulators, so free it from devres too, after them.
+ */
+ ret = devm_add_action_or_reset(pcdev->dev, devm_pse_release_pis, pcdev);
+ if (ret)
+ return ret;
+
if (pcdev->ops->setup_pi_matrix) {
ret = pcdev->ops->setup_pi_matrix(pcdev);
if (ret)@@ -1194,7 +1206,6 @@ void pse_controller_unregister(struct pse_controller_dev *pcdev)
mutex_unlock(&pse_list_mutex);
cancel_work_sync(&pcdev->ntf_work);
pse_flush_pw_ds(pcdev);
- pse_release_pis(pcdev);
kfifo_free(&pcdev->ntf_fifo);
}
EXPORT_SYMBOL_GPL(pse_controller_unregister);
--
2.43.0