diff mbox series

[1/2] OPP: add index check to assert to avoid buffer overflow in _read_freq()

Message ID 20241128-topic-opp-fix-assert-index-check-v1-1-cb8bd4c0370e@linaro.org
State New
Headers show
Series OPP: fix buffer overflow in indexed freq and bandwidth reads | expand

Commit Message

Neil Armstrong Nov. 28, 2024, 10:07 a.m. UTC
Pass the freq index to the assert function to make sure
we do not read a freq out of the opp->rates[] table.

Without that the index value is never checked when called from
dev_pm_opp_find_freq_exact_indexed() or
dev_pm_opp_find_freq_ceil/floor_indexed().

Add a specialized version of assert_single_clk() to check for
the index to be used with the generic find functions.

Fixes: 142e17c1c2b4 ("OPP: Introduce dev_pm_opp_find_freq_{ceil/floor}_indexed() APIs")
Fixes: a5893928bb17 ("OPP: Add dev_pm_opp_find_freq_exact_indexed()")
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
---
 drivers/opp/core.c | 38 ++++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 14 deletions(-)

Comments

Viresh Kumar Nov. 29, 2024, 8:40 a.m. UTC | #1
On 28-11-24, 11:07, Neil Armstrong wrote:
> Pass the freq index to the assert function to make sure
> we do not read a freq out of the opp->rates[] table.
> 
> Without that the index value is never checked when called from
> dev_pm_opp_find_freq_exact_indexed() or
> dev_pm_opp_find_freq_ceil/floor_indexed().

These APIs aren't supported for cases where we have more than one clks
available and hence assert for single clk.
Neil Armstrong Nov. 29, 2024, 8:53 a.m. UTC | #2
Hi,

On 29/11/2024 09:40, Viresh Kumar wrote:
> On 28-11-24, 11:07, Neil Armstrong wrote:
>> Pass the freq index to the assert function to make sure
>> we do not read a freq out of the opp->rates[] table.
>>
>> Without that the index value is never checked when called from
>> dev_pm_opp_find_freq_exact_indexed() or
>> dev_pm_opp_find_freq_ceil/floor_indexed().
> 
> These APIs aren't supported for cases where we have more than one clks
> available and hence assert for single clk.
> 

I don't understand, the _indexed functions clearly have an index parameter
which is documented as "Clock index"

I agree we could leave the other ones with assert_single_clk, but we would
need to duplicate it to have one with the index parameter, so it felt simpler
to use assert_clk_index everywhere but indeed we do not exclude them for
when there's multiple clock...

Neil
Viresh Kumar Nov. 29, 2024, 9:04 a.m. UTC | #3
On 29-11-24, 09:53, Neil Armstrong wrote:
> Hi,
> 
> On 29/11/2024 09:40, Viresh Kumar wrote:
> > On 28-11-24, 11:07, Neil Armstrong wrote:
> > > Pass the freq index to the assert function to make sure
> > > we do not read a freq out of the opp->rates[] table.
> > > 
> > > Without that the index value is never checked when called from
> > > dev_pm_opp_find_freq_exact_indexed() or
> > > dev_pm_opp_find_freq_ceil/floor_indexed().
> > 
> > These APIs aren't supported for cases where we have more than one clks
> > available and hence assert for single clk.
> > 
> 
> I don't understand, the _indexed functions clearly have an index parameter
> which is documented as "Clock index"

Ahh, I missed that there are few _indexed() helpers as well which you are
correctly modifying.

> I agree we could leave the other ones with assert_single_clk, but we would
> need to duplicate it to have one with the index parameter, so it felt simpler
> to use assert_clk_index everywhere but indeed we do not exclude them for
> when there's multiple clock...

What prevents a user to call dev_pm_opp_find_freq_exact() for a multi-clk setup
after your patch ? As we use Index = 0 here in the code.

That's why I would prefer the earlier assert for all these, except the indexed
ones.
Neil Armstrong Nov. 29, 2024, 9:07 a.m. UTC | #4
On 29/11/2024 10:04, Viresh Kumar wrote:
> On 29-11-24, 09:53, Neil Armstrong wrote:
>> Hi,
>>
>> On 29/11/2024 09:40, Viresh Kumar wrote:
>>> On 28-11-24, 11:07, Neil Armstrong wrote:
>>>> Pass the freq index to the assert function to make sure
>>>> we do not read a freq out of the opp->rates[] table.
>>>>
>>>> Without that the index value is never checked when called from
>>>> dev_pm_opp_find_freq_exact_indexed() or
>>>> dev_pm_opp_find_freq_ceil/floor_indexed().
>>>
>>> These APIs aren't supported for cases where we have more than one clks
>>> available and hence assert for single clk.
>>>
>>
>> I don't understand, the _indexed functions clearly have an index parameter
>> which is documented as "Clock index"
> 
> Ahh, I missed that there are few _indexed() helpers as well which you are
> correctly modifying.
> 
>> I agree we could leave the other ones with assert_single_clk, but we would
>> need to duplicate it to have one with the index parameter, so it felt simpler
>> to use assert_clk_index everywhere but indeed we do not exclude them for
>> when there's multiple clock...
> 
> What prevents a user to call dev_pm_opp_find_freq_exact() for a multi-clk setup
> after your patch ? As we use Index = 0 here in the code.
> 
> That's why I would prefer the earlier assert for all these, except the indexed
> ones.

Yes, let me send a v2 with this addressed

Thanks,
Neil
diff mbox series

Patch

diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index d4a0030a0228d6282d672e3ffe3aeea27e80822a..8692e8ce05b7c31a725ea3a7928f238c7a1d6f51 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -106,6 +106,14 @@  static bool assert_single_clk(struct opp_table *opp_table)
 	return !WARN_ON(opp_table->clk_count > 1);
 }
 
+/*
+ * Returns true if clock table is large enough to contain the clock index.
+ */
+static bool assert_clk_index(struct opp_table *opp_table, int index)
+{
+	return opp_table->clk_count > index;
+}
+
 /**
  * dev_pm_opp_get_bw() - Gets the bandwidth corresponding to an opp
  * @opp:	opp for which bandwidth has to be returned for
@@ -524,12 +532,12 @@  static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
 		unsigned long (*read)(struct dev_pm_opp *opp, int index),
 		bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
 				unsigned long opp_key, unsigned long key),
-		bool (*assert)(struct opp_table *opp_table))
+		bool (*assert)(struct opp_table *opp_table, int index))
 {
 	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
 	/* Assert that the requirement is met */
-	if (assert && !assert(opp_table))
+	if (assert && !assert(opp_table, index))
 		return ERR_PTR(-EINVAL);
 
 	mutex_lock(&opp_table->lock);
@@ -557,7 +565,7 @@  _find_key(struct device *dev, unsigned long *key, int index, bool available,
 	  unsigned long (*read)(struct dev_pm_opp *opp, int index),
 	  bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
 			  unsigned long opp_key, unsigned long key),
-	  bool (*assert)(struct opp_table *opp_table))
+	  bool (*assert)(struct opp_table *opp_table, int index))
 {
 	struct opp_table *opp_table;
 	struct dev_pm_opp *opp;
@@ -580,7 +588,7 @@  _find_key(struct device *dev, unsigned long *key, int index, bool available,
 static struct dev_pm_opp *_find_key_exact(struct device *dev,
 		unsigned long key, int index, bool available,
 		unsigned long (*read)(struct dev_pm_opp *opp, int index),
-		bool (*assert)(struct opp_table *opp_table))
+		bool (*assert)(struct opp_table *opp_table, int index))
 {
 	/*
 	 * The value of key will be updated here, but will be ignored as the
@@ -593,7 +601,7 @@  static struct dev_pm_opp *_find_key_exact(struct device *dev,
 static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
 		unsigned long *key, int index, bool available,
 		unsigned long (*read)(struct dev_pm_opp *opp, int index),
-		bool (*assert)(struct opp_table *opp_table))
+		bool (*assert)(struct opp_table *opp_table, int index))
 {
 	return _opp_table_find_key(opp_table, key, index, available, read,
 				   _compare_ceil, assert);
@@ -602,7 +610,7 @@  static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
 static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
 		int index, bool available,
 		unsigned long (*read)(struct dev_pm_opp *opp, int index),
-		bool (*assert)(struct opp_table *opp_table))
+		bool (*assert)(struct opp_table *opp_table, int index))
 {
 	return _find_key(dev, key, index, available, read, _compare_ceil,
 			 assert);
@@ -611,7 +619,7 @@  static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
 static struct dev_pm_opp *_find_key_floor(struct device *dev,
 		unsigned long *key, int index, bool available,
 		unsigned long (*read)(struct dev_pm_opp *opp, int index),
-		bool (*assert)(struct opp_table *opp_table))
+		bool (*assert)(struct opp_table *opp_table, int index))
 {
 	return _find_key(dev, key, index, available, read, _compare_floor,
 			 assert);
@@ -644,7 +652,7 @@  struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
 		unsigned long freq, bool available)
 {
 	return _find_key_exact(dev, freq, 0, available, _read_freq,
-			       assert_single_clk);
+			       assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
 
@@ -672,7 +680,8 @@  struct dev_pm_opp *
 dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
 				   u32 index, bool available)
 {
-	return _find_key_exact(dev, freq, index, available, _read_freq, NULL);
+	return _find_key_exact(dev, freq, index, available, _read_freq,
+			       assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact_indexed);
 
@@ -680,7 +689,7 @@  static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
 						   unsigned long *freq)
 {
 	return _opp_table_find_key_ceil(opp_table, freq, 0, true, _read_freq,
-					assert_single_clk);
+					assert_clk_index);
 }
 
 /**
@@ -704,7 +713,7 @@  static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
 struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
 					     unsigned long *freq)
 {
-	return _find_key_ceil(dev, freq, 0, true, _read_freq, assert_single_clk);
+	return _find_key_ceil(dev, freq, 0, true, _read_freq, assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 
@@ -732,7 +741,8 @@  struct dev_pm_opp *
 dev_pm_opp_find_freq_ceil_indexed(struct device *dev, unsigned long *freq,
 				  u32 index)
 {
-	return _find_key_ceil(dev, freq, index, true, _read_freq, NULL);
+	return _find_key_ceil(dev, freq, index, true, _read_freq,
+			      assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
 
@@ -757,7 +767,7 @@  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 					      unsigned long *freq)
 {
-	return _find_key_floor(dev, freq, 0, true, _read_freq, assert_single_clk);
+	return _find_key_floor(dev, freq, 0, true, _read_freq, assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
 
@@ -785,7 +795,7 @@  struct dev_pm_opp *
 dev_pm_opp_find_freq_floor_indexed(struct device *dev, unsigned long *freq,
 				   u32 index)
 {
-	return _find_key_floor(dev, freq, index, true, _read_freq, NULL);
+	return _find_key_floor(dev, freq, index, true, _read_freq, assert_clk_index);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor_indexed);