From e11811a552252740bd396ec38378e9570ee16578 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 26 Aug 2026 14:19:57 +0100 Subject: [PATCH 1/3] OPP: of: Fix potential multiplication overflow when calculating freq The multiplication be32_to_cpup(val++) * 1000 is performed using 32 bit unsigned integers and hence uses a 32 bit multiplication; this will overflow if be32_to_cpup(val++) is greater than 4294967 (which is very unlikely at present). The result is assigned to an unsigned long (which is a 64 bit value on 64 bit systems), so fix this potential overflow by casting the first operand of the multiplication to an unsigned int. Fixes: b496dfbc94ab ("PM / OPP: Initialize OPP table from device tree") Signed-off-by: Colin Ian King Signed-off-by: Viresh Kumar --- drivers/opp/of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/opp/of.c b/drivers/opp/of.c index c02e20632fa6..9c4fd1f0e944 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1039,7 +1039,7 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table) val = prop->value; while (nr) { - unsigned long freq = be32_to_cpup(val++) * 1000; + unsigned long freq = (unsigned long)be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); struct dev_pm_opp_data data = { .freq = freq, From a5096d4927d1eb607d51a7342a7e7591a3838c19 Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Sat, 29 Aug 2026 19:19:24 +0530 Subject: [PATCH 2/3] opp: Use %pe to print symbolic error name Replace PTR_ERR() and %ld with %pe and pass the original pointer directly to dev_dbg(), dev_warn(), dev_err() or pr_err(). The %pe format specifier prints a symbolic error name (e.g. -ENOMEM) when CONFIG_SYMBOLIC_ERRNAME is enabled, otherwise it falls back gracefully and prints the raw integer value. This makes error messages more readable without any functional change. Signed-off-by: Sumeet Pawnikar Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 24 ++++++++++++------------ drivers/opp/of.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index cd0e82dae776..1e3b80a1f88e 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -453,8 +453,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_dbg(dev, "%s: OPP table not found (%ld)\n", - __func__, PTR_ERR(opp_table)); + dev_dbg(dev, "%s: OPP table not found (%pe)\n", + __func__, opp_table); return PTR_ERR(opp_table); } @@ -611,8 +611,8 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available, _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, - PTR_ERR(opp_table)); + dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, + opp_table); return ERR_CAST(opp_table); } @@ -722,8 +722,8 @@ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, - PTR_ERR(opp_table)); + dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, + opp_table); return ERR_CAST(opp_table); } @@ -1036,8 +1036,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, /* Regulator not available for device */ if (IS_ERR(reg)) { - dev_dbg(dev, "%s: regulator not available: %ld\n", __func__, - PTR_ERR(reg)); + dev_dbg(dev, "%s: regulator not available: %pe\n", __func__, + reg); return 0; } @@ -1448,8 +1448,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) temp_freq = freq; opp = _find_freq_ceil(opp_table, &temp_freq); if (IS_ERR(opp)) { - dev_err(dev, "%s: failed to find OPP for freq %lu (%ld)\n", - __func__, freq, PTR_ERR(opp)); + dev_err(dev, "%s: failed to find OPP for freq %lu (%pe)\n", + __func__, freq, opp); return PTR_ERR(opp); } @@ -2869,8 +2869,8 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, 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__, - PTR_ERR(opp_table)); + dev_warn(dev, "%s: Device OPP not found (%pe)\n", __func__, + opp_table); return PTR_ERR(opp_table); } diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 9c4fd1f0e944..2f3bbde9a9e1 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1345,8 +1345,8 @@ int of_get_required_opp_performance_state(struct device_node *np, int index) _find_table_of_opp_np(required_np); if (IS_ERR(opp_table)) { - pr_err("%s: Failed to find required OPP table %pOF: %ld\n", - __func__, np, PTR_ERR(opp_table)); + pr_err("%s: Failed to find required OPP table %pOF: %pe\n", + __func__, np, opp_table); return PTR_ERR(opp_table); } From 1f6de65e3314519ce462bfd3a1d29e918f97e4e5 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 8 Sep 2026 12:37:27 +0000 Subject: [PATCH 3/3] opp: fix use after free in _update_opp_table_clk() dev_pm_opp_put_opp_table() frees the opp_table which is subsquently used by dev_err_probe(). This causes an Oops during boot on gs101-oriole. cpu cpu0: error 000000006b6b6b6b: Couldn't find clock Unable to handle kernel paging request at virtual address 006b6b6b6b6b6cd3 ... Hardware name: Oriole (DT) pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : _of_add_table_indexed+0x80/0xbb0 lr : _of_add_table_indexed+0x6c/0xbb0 ... Call trace: _of_add_table_indexed+0x80/0xbb0 (P) dev_pm_opp_of_cpumask_add_table+0x70/0x120 dt_cpufreq_probe+0x23c/0x480 platform_probe+0x64/0xb8 Fixes: 84f05af0975c9 ("opp: Use clk_get_optional() to avoid leaving opp_table->clk as an error pointer") Signed-off-by: Peter Griffin Reviewed-by: Tudor Ambarus [ Viresh: use return value of dev_err_probe() ] Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 1e3b80a1f88e..1da7d86241ae 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1581,6 +1581,8 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, struct opp_table *opp_table, bool getclk) { + int ret; + /* * Return early if we don't need to get clk or we have already done it * earlier. @@ -1607,9 +1609,9 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, opp_table->clk = clk_get_optional(dev, NULL); if (IS_ERR(opp_table->clk)) { + ret = dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); dev_pm_opp_put_opp_table(opp_table); - dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); - return ERR_CAST(opp_table->clk); + return ERR_PTR(ret); } if (opp_table->clk)