This reverts commit 23de0fa0d2a05ff71c7bc8df9d12c9f23be83f13. carl9170_register() is invoked asynchronously from the request_firmware_nowait() callback after carl9170_usb_probe() has already returned, and carl9170_usb_disconnect() calls carl9170_unregister() followed immediately by carl9170_free(), which frees struct ar9170 (including struct hwrng ar->rng.rng and ar->rng.name). Registering the hardware random number generator via devm_hwrng_register(&ar->udev->dev, &ar->rng.rng) ties its unregistration to the parent struct usb_device rather than the driver lifecycle. Furthermore, if carl9170_rng_get() fails at the end of carl9170_register_hwrng(), or when the interface is disconnected and carl9170_free() frees struct ar9170 before devres_release_all() runs, the embedded struct hwrng remains registered on the global rng_list in freed memory, causing a use-after-free. Fixes: 23de0fa0d2a0 ("carl9170: devres-ing hwrng_register usage") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Dmitry Torokhov --- drivers/net/wireless/ath/carl9170/carl9170.h | 1 + drivers/net/wireless/ath/carl9170/main.c | 29 +++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index e66e3e2ae952..03a94a5a209b 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -454,6 +454,7 @@ struct ar9170 { # define CARL9170_HWRNG_CACHE_SIZE CARL9170_MAX_CMD_PAYLOAD_LEN struct { struct hwrng rng; + bool initialized; char name[30 + 1]; u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)]; unsigned int cache_idx; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 702b6d113b18..8ca76e9044de 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1545,7 +1545,7 @@ static int carl9170_rng_get(struct ar9170 *ar) BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN); - if (!IS_ACCEPTING_CMD(ar)) + if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized) return -EAGAIN; count = ARRAY_SIZE(ar->rng.cache); @@ -1591,6 +1591,14 @@ static int carl9170_rng_read(struct hwrng *rng, u32 *data) return sizeof(u16); } +static void carl9170_unregister_hwrng(struct ar9170 *ar) +{ + if (ar->rng.initialized) { + hwrng_unregister(&ar->rng.rng); + ar->rng.initialized = false; + } +} + static int carl9170_register_hwrng(struct ar9170 *ar) { int err; @@ -1601,14 +1609,25 @@ static int carl9170_register_hwrng(struct ar9170 *ar) ar->rng.rng.data_read = carl9170_rng_read; ar->rng.rng.priv = (unsigned long)ar; - err = devm_hwrng_register(&ar->udev->dev, &ar->rng.rng); + if (WARN_ON(ar->rng.initialized)) + return -EALREADY; + + err = hwrng_register(&ar->rng.rng); if (err) { dev_err(&ar->udev->dev, "Failed to register the random " "number generator (%d)\n", err); return err; } - return carl9170_rng_get(ar); + ar->rng.initialized = true; + + err = carl9170_rng_get(ar); + if (err) { + carl9170_unregister_hwrng(ar); + return err; + } + + return 0; } #endif /* CONFIG_CARL9170_HWRNG */ @@ -2053,6 +2072,10 @@ void carl9170_unregister(struct ar9170 *ar) } #endif /* CONFIG_CARL9170_WPC */ +#ifdef CONFIG_CARL9170_HWRNG + carl9170_unregister_hwrng(ar); +#endif /* CONFIG_CARL9170_HWRNG */ + carl9170_cancel_worker(ar); cancel_work_sync(&ar->restart_work); -- 2.56.0.rc1.315.gc6ed9934b7-goog