From a451b6bb922ede877b141beb09c3d2eb3cc9edfe Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Fri, 28 Aug 2026 18:44:39 +0200 Subject: [PATCH] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout pcf85063_clkout_register_clk() registered the OF clock provider with the deprecated of_clk_add_provider() and never removed it, so the provider kept pointing at freed data after unbind, leading to a use-after-free the next time the device-tree clock was resolved. Switch to devm_clk_hw_register() and devm_of_clk_add_hw_provider(): both the clock and its OF provider are managed resources now, and the provider is torn down before the clock on unbind. Register the clock on the parent i2c device instead of the rtc device. devm_of_clk_add_hw_provider() must use the parent, which owns the of_node, and the clkout_hw it points at lives in the driver data allocated on the parent. Tying both to the parent releases them together on unbind, before the driver data is freed, and keeps their teardown ordering guaranteed by a single devres list. Registering the clock on the rtc device instead could defer its unregistration past unbind (e.g. while a /dev/rtcN fd is open), after clkout_hw has already been freed. Signed-off-by: Alexander Sverdlin Link: https://patch.msgid.link/20260828164445.3907839-2-alexander.sverdlin@siemens.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 8cb9ffc73f6d..ac9ab1c376c0 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -495,12 +495,13 @@ static const struct clk_ops pcf85063_clkout_ops = { .set_rate = pcf85063_clkout_set_rate, }; -static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) +static int pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) { - struct clk *clk; + struct device *dev = pcf85063->rtc->dev.parent; struct clk_init_data init = {}; - struct device_node *node = pcf85063->rtc->dev.parent->of_node; + struct device_node *node = dev->of_node; struct device_node *fixed_clock; + int ret; fixed_clock = of_get_child_by_name(node, "clock"); if (fixed_clock) { @@ -510,7 +511,7 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) * registered automatically when being referenced. */ of_node_put(fixed_clock); - return NULL; + return 0; } init.name = "pcf85063-clkout"; @@ -524,12 +525,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) of_property_read_string(node, "clock-output-names", &init.name); /* register the clock */ - clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw); + ret = devm_clk_hw_register(dev, &pcf85063->clkout_hw); + if (ret) + return ret; - if (!IS_ERR(clk)) - of_clk_add_provider(node, of_clk_src_simple_get, clk); - - return clk; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &pcf85063->clkout_hw); } #endif