From: Johan Hovold Date: Wed, 25 Mar 2026 14:53:19 +0000 (+0100) Subject: spi: fix use-after-free on managed registration failure X-Git-Tag: ceph-for-7.1-rc1~106^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8d2e0cb3224c89275c5471c92850e7f74df80c20;p=ceph-client.git spi: fix use-after-free on managed registration failure The SPI API is asymmetric and the controller is freed as part of deregistration (unless it has been allocated using devm_spi_alloc_host/target()). A recent change converting the managed registration function to use devm_add_action_or_reset() inadvertently introduced a (mostly theoretical) regression where a non-devres managed controller could be freed as part of failed registration. This in turn would lead to use-after-free in controller driver error paths. Fix this by taking another reference before calling devm_add_action_or_reset() and not releasing it on errors for non-devres allocated controllers. An alternative would be a partial revert of the offending commit, but it is better to handle this explicitly until the API has been fixed (e.g. see 5e844cc37a5c ("spi: Introduce device-managed SPI controller allocation")). Fixes: b6376dbed8e1 ("spi: Simplify devm_spi_*_controller()") Reported-by: Felix Gu Link: https://lore.kernel.org/all/20260324145548.139952-1-ustc.gu@gmail.com/ Cc: Andy Shevchenko Signed-off-by: Johan Hovold Acked-by: Andy Shevchenko Link: https://patch.msgid.link/20260325145319.1132072-1-johan@kernel.org Signed-off-by: Mark Brown --- diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4101c2803eb3..9b1125556d29 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3534,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev, if (ret) return ret; - return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); + /* + * Prevent controller from being freed by spi_unregister_controller() + * if devm_add_action_or_reset() fails for a non-devres allocated + * controller. + */ + spi_controller_get(ctlr); + + ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); + if (ret == 0 || ctlr->devm_allocated) + spi_controller_put(ctlr); + + return ret; } EXPORT_SYMBOL_GPL(devm_spi_register_controller);