Skip to content

Commit 8d2e0cb

Browse files
jhovoldbroonie
authored andcommitted
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 5e844cc ("spi: Introduce device-managed SPI controller allocation")). Fixes: b6376db ("spi: Simplify devm_spi_*_controller()") Reported-by: Felix Gu <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Cc: Andy Shevchenko <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Acked-by: Andy Shevchenko <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent cc34d77 commit 8d2e0cb

1 file changed

Lines changed: 12 additions & 1 deletion

File tree

drivers/spi/spi.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3534,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev,
35343534
if (ret)
35353535
return ret;
35363536

3537-
return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
3537+
/*
3538+
* Prevent controller from being freed by spi_unregister_controller()
3539+
* if devm_add_action_or_reset() fails for a non-devres allocated
3540+
* controller.
3541+
*/
3542+
spi_controller_get(ctlr);
3543+
3544+
ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
35383545

3546+
if (ret == 0 || ctlr->devm_allocated)
3547+
spi_controller_put(ctlr);
3548+
3549+
return ret;
35393550
}
35403551
EXPORT_SYMBOL_GPL(devm_spi_register_controller);
35413552

0 commit comments

Comments
 (0)