Skip to content

Commit d659bc6

Browse files
superna9999vireshk
authored andcommitted
OPP: add index check to assert to avoid buffer overflow in _read_freq()
Pass the freq index to the assert function to make sure we do not read a freq out of the opp->rates[] table when called from the indexed variants: dev_pm_opp_find_freq_exact_indexed() or dev_pm_opp_find_freq_ceil/floor_indexed(). Add a secondary parameter to the assert function, unused for assert_single_clk() then add assert_clk_index() which will check for the clock index when called from the _indexed() find functions. Fixes: 142e17c ("OPP: Introduce dev_pm_opp_find_freq_{ceil/floor}_indexed() APIs") Fixes: a589392 ("OPP: Add dev_pm_opp_find_freq_exact_indexed()") Signed-off-by: Neil Armstrong <[email protected]> Signed-off-by: Viresh Kumar <[email protected]>
1 parent 402074f commit d659bc6

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

drivers/opp/core.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,21 @@ struct opp_table *_find_opp_table(struct device *dev)
101101
* representation in the OPP table and manage the clock configuration themselves
102102
* in an platform specific way.
103103
*/
104-
static bool assert_single_clk(struct opp_table *opp_table)
104+
static bool assert_single_clk(struct opp_table *opp_table,
105+
unsigned int __always_unused index)
105106
{
106107
return !WARN_ON(opp_table->clk_count > 1);
107108
}
108109

110+
/*
111+
* Returns true if clock table is large enough to contain the clock index.
112+
*/
113+
static bool assert_clk_index(struct opp_table *opp_table,
114+
unsigned int index)
115+
{
116+
return opp_table->clk_count > index;
117+
}
118+
109119
/**
110120
* dev_pm_opp_get_bw() - Gets the bandwidth corresponding to an opp
111121
* @opp: opp for which bandwidth has to be returned for
@@ -524,12 +534,12 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
524534
unsigned long (*read)(struct dev_pm_opp *opp, int index),
525535
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
526536
unsigned long opp_key, unsigned long key),
527-
bool (*assert)(struct opp_table *opp_table))
537+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
528538
{
529539
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
530540

531541
/* Assert that the requirement is met */
532-
if (assert && !assert(opp_table))
542+
if (assert && !assert(opp_table, index))
533543
return ERR_PTR(-EINVAL);
534544

535545
mutex_lock(&opp_table->lock);
@@ -557,7 +567,7 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available,
557567
unsigned long (*read)(struct dev_pm_opp *opp, int index),
558568
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
559569
unsigned long opp_key, unsigned long key),
560-
bool (*assert)(struct opp_table *opp_table))
570+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
561571
{
562572
struct opp_table *opp_table;
563573
struct dev_pm_opp *opp;
@@ -580,7 +590,7 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available,
580590
static struct dev_pm_opp *_find_key_exact(struct device *dev,
581591
unsigned long key, int index, bool available,
582592
unsigned long (*read)(struct dev_pm_opp *opp, int index),
583-
bool (*assert)(struct opp_table *opp_table))
593+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
584594
{
585595
/*
586596
* The value of key will be updated here, but will be ignored as the
@@ -593,7 +603,7 @@ static struct dev_pm_opp *_find_key_exact(struct device *dev,
593603
static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
594604
unsigned long *key, int index, bool available,
595605
unsigned long (*read)(struct dev_pm_opp *opp, int index),
596-
bool (*assert)(struct opp_table *opp_table))
606+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
597607
{
598608
return _opp_table_find_key(opp_table, key, index, available, read,
599609
_compare_ceil, assert);
@@ -602,7 +612,7 @@ static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
602612
static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
603613
int index, bool available,
604614
unsigned long (*read)(struct dev_pm_opp *opp, int index),
605-
bool (*assert)(struct opp_table *opp_table))
615+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
606616
{
607617
return _find_key(dev, key, index, available, read, _compare_ceil,
608618
assert);
@@ -611,7 +621,7 @@ static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
611621
static struct dev_pm_opp *_find_key_floor(struct device *dev,
612622
unsigned long *key, int index, bool available,
613623
unsigned long (*read)(struct dev_pm_opp *opp, int index),
614-
bool (*assert)(struct opp_table *opp_table))
624+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
615625
{
616626
return _find_key(dev, key, index, available, read, _compare_floor,
617627
assert);
@@ -672,7 +682,8 @@ struct dev_pm_opp *
672682
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
673683
u32 index, bool available)
674684
{
675-
return _find_key_exact(dev, freq, index, available, _read_freq, NULL);
685+
return _find_key_exact(dev, freq, index, available, _read_freq,
686+
assert_clk_index);
676687
}
677688
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact_indexed);
678689

@@ -732,7 +743,8 @@ struct dev_pm_opp *
732743
dev_pm_opp_find_freq_ceil_indexed(struct device *dev, unsigned long *freq,
733744
u32 index)
734745
{
735-
return _find_key_ceil(dev, freq, index, true, _read_freq, NULL);
746+
return _find_key_ceil(dev, freq, index, true, _read_freq,
747+
assert_clk_index);
736748
}
737749
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
738750

@@ -785,7 +797,7 @@ struct dev_pm_opp *
785797
dev_pm_opp_find_freq_floor_indexed(struct device *dev, unsigned long *freq,
786798
u32 index)
787799
{
788-
return _find_key_floor(dev, freq, index, true, _read_freq, NULL);
800+
return _find_key_floor(dev, freq, index, true, _read_freq, assert_clk_index);
789801
}
790802
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor_indexed);
791803

@@ -1727,7 +1739,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
17271739
if (IS_ERR(opp_table))
17281740
return;
17291741

1730-
if (!assert_single_clk(opp_table))
1742+
if (!assert_single_clk(opp_table, 0))
17311743
goto put_table;
17321744

17331745
mutex_lock(&opp_table->lock);
@@ -2079,7 +2091,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
20792091
unsigned long tol, u_volt = data->u_volt;
20802092
int ret;
20812093

2082-
if (!assert_single_clk(opp_table))
2094+
if (!assert_single_clk(opp_table, 0))
20832095
return -EINVAL;
20842096

20852097
new_opp = _opp_allocate(opp_table);
@@ -2835,7 +2847,7 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
28352847
return r;
28362848
}
28372849

2838-
if (!assert_single_clk(opp_table)) {
2850+
if (!assert_single_clk(opp_table, 0)) {
28392851
r = -EINVAL;
28402852
goto put_table;
28412853
}
@@ -2911,7 +2923,7 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
29112923
return r;
29122924
}
29132925

2914-
if (!assert_single_clk(opp_table)) {
2926+
if (!assert_single_clk(opp_table, 0)) {
29152927
r = -EINVAL;
29162928
goto put_table;
29172929
}

0 commit comments

Comments
 (0)