[PATCH] OPP: Fix cleanup ordering

Gregor Herburger posted 1 patch 1 week, 3 days ago
drivers/opp/core.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
[PATCH] OPP: Fix cleanup ordering
Posted by Gregor Herburger 1 week, 3 days ago
Commit 173e02d67494 ("OPP: Initialize scope-based pointers inline")
added initialization for all pointers. In some cases, the ordering was
changed so that *opp_table was initialized after *opp. This also changes
the order of the registered cleanup functions.

When the cleanup happens, this can cause use-after-free errors when the
last reference is released and the release function _opp_kref_release
tries to access the already freed opp->opp_table.

Initialize *opp_table before *opp again to fix this and ensure the
correct cleanup order.

Fixes: 173e02d67494 ("OPP: Initialize scope-based pointers inline")
Signed-off-by: Gregor Herburger <gregor.herburger@linutronix.de>
---
 drivers/opp/core.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index ab0b0a2f85a17..b6966e509f7dd 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1412,13 +1412,12 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
  */
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 {
+	struct opp_table *opp_table __free(put_opp_table) =
+		_find_opp_table(dev);
 	struct dev_pm_opp *opp __free(put_opp) = NULL;
 	unsigned long freq = 0, temp_freq;
 	bool forced = false;
 
-	struct opp_table *opp_table __free(put_opp_table) =
-		_find_opp_table(dev);
-
 	if (IS_ERR(opp_table)) {
 		dev_err(dev, "%s: device's opp table doesn't exist\n", __func__);
 		return PTR_ERR(opp_table);
@@ -2870,11 +2869,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add_dynamic);
 static int _opp_set_availability(struct device *dev, unsigned long freq,
 				 bool availability_req)
 {
-	struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp;
-
 	/* Find the opp_table */
 	struct opp_table *opp_table __free(put_opp_table) =
 		_find_opp_table(dev);
+	struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp;
 
 	if (IS_ERR(opp_table)) {
 		dev_warn(dev, "%s: Device OPP not found (%ld)\n", __func__,
@@ -2932,12 +2930,11 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
 			      unsigned long u_volt_max)
 
 {
-	struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp;
-	int r;
-
 	/* Find the opp_table */
 	struct opp_table *opp_table __free(put_opp_table) =
 		_find_opp_table(dev);
+	struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp;
+	int r;
 
 	if (IS_ERR(opp_table)) {
 		r = PTR_ERR(opp_table);

---
base-commit: 58717b2a1365d06c8c64b72aa948541b53fe31eb
change-id: 20260715-opp-fix-e49f208be1bf

Best regards,
--  
Gregor Herburger <gregor.herburger@linutronix.de>
Re: [PATCH] OPP: Fix cleanup ordering
Posted by Viresh Kumar 1 week, 3 days ago
On 15-07-26, 09:35, Gregor Herburger wrote:
> Commit 173e02d67494 ("OPP: Initialize scope-based pointers inline")
> added initialization for all pointers. In some cases, the ordering was
> changed so that *opp_table was initialized after *opp. This also changes
> the order of the registered cleanup functions.
> 
> When the cleanup happens, this can cause use-after-free errors when the
> last reference is released and the release function _opp_kref_release
> tries to access the already freed opp->opp_table.
> 
> Initialize *opp_table before *opp again to fix this and ensure the
> correct cleanup order.
> 
> Fixes: 173e02d67494 ("OPP: Initialize scope-based pointers inline")
> Signed-off-by: Gregor Herburger <gregor.herburger@linutronix.de>
> ---
>  drivers/opp/core.c | 13 +++++--------
>  1 file changed, 5 insertions(+), 8 deletions(-)

Applied. Thanks.

-- 
viresh