Skip to content

Commit 979e4c2

Browse files
committed
Merge: CVE-2024-57998 kernel: OPP: add index check to assert to avoid buffer overflow in _read_freq()
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6578 ## Summary of Changes Backport upstream `d659bc68ed48` ("OPP: add index check to assert to avoid buffer overflow in \_read\_freq()") to fix CVE-2024-57998, plus a few other patches that prevent conflicts. Note that `b44b9bc7cab2` ("OPP: fix dev\_pm\_opp\_find\_bw\_\*() when bandwidth table not initialized") fixes CVE-2024-58068 and is also included because it's in the same series as `d659bc68ed48`. ## Approved Development Ticket(s) JIRA: https://issues.redhat.com/browse/RHEL-81432 CVE: CVE-2024-57998 JIRA: https://issues.redhat.com/browse/RHEL-84805 CVE: CVE-2024-58068 Signed-off-by: Jared Kangas <[email protected]> Approved-by: Brian Masney <[email protected]> Approved-by: Radu Rendec <[email protected]> Approved-by: Eric Chanudet <[email protected]> Approved-by: CKI KWF Bot <[email protected]> Merged-by: Augusto Caringi <[email protected]>
2 parents 839e349 + befd813 commit 979e4c2

File tree

2 files changed

+78
-16
lines changed

2 files changed

+78
-16
lines changed

drivers/opp/core.c

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,30 @@ 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+
119+
/*
120+
* Returns true if bandwidth table is large enough to contain the bandwidth index.
121+
*/
122+
static bool assert_bandwidth_index(struct opp_table *opp_table,
123+
unsigned int index)
124+
{
125+
return opp_table->path_count > index;
126+
}
127+
109128
/**
110129
* dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
111130
* @opp: opp for which voltage has to be returned for
@@ -499,12 +518,12 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
499518
unsigned long (*read)(struct dev_pm_opp *opp, int index),
500519
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
501520
unsigned long opp_key, unsigned long key),
502-
bool (*assert)(struct opp_table *opp_table))
521+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
503522
{
504523
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
505524

506525
/* Assert that the requirement is met */
507-
if (assert && !assert(opp_table))
526+
if (assert && !assert(opp_table, index))
508527
return ERR_PTR(-EINVAL);
509528

510529
mutex_lock(&opp_table->lock);
@@ -532,7 +551,7 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available,
532551
unsigned long (*read)(struct dev_pm_opp *opp, int index),
533552
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
534553
unsigned long opp_key, unsigned long key),
535-
bool (*assert)(struct opp_table *opp_table))
554+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
536555
{
537556
struct opp_table *opp_table;
538557
struct dev_pm_opp *opp;
@@ -555,7 +574,7 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available,
555574
static struct dev_pm_opp *_find_key_exact(struct device *dev,
556575
unsigned long key, int index, bool available,
557576
unsigned long (*read)(struct dev_pm_opp *opp, int index),
558-
bool (*assert)(struct opp_table *opp_table))
577+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
559578
{
560579
/*
561580
* The value of key will be updated here, but will be ignored as the
@@ -568,7 +587,7 @@ static struct dev_pm_opp *_find_key_exact(struct device *dev,
568587
static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
569588
unsigned long *key, int index, bool available,
570589
unsigned long (*read)(struct dev_pm_opp *opp, int index),
571-
bool (*assert)(struct opp_table *opp_table))
590+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
572591
{
573592
return _opp_table_find_key(opp_table, key, index, available, read,
574593
_compare_ceil, assert);
@@ -577,7 +596,7 @@ static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
577596
static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
578597
int index, bool available,
579598
unsigned long (*read)(struct dev_pm_opp *opp, int index),
580-
bool (*assert)(struct opp_table *opp_table))
599+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
581600
{
582601
return _find_key(dev, key, index, available, read, _compare_ceil,
583602
assert);
@@ -586,7 +605,7 @@ static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
586605
static struct dev_pm_opp *_find_key_floor(struct device *dev,
587606
unsigned long *key, int index, bool available,
588607
unsigned long (*read)(struct dev_pm_opp *opp, int index),
589-
bool (*assert)(struct opp_table *opp_table))
608+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
590609
{
591610
return _find_key(dev, key, index, available, read, _compare_floor,
592611
assert);
@@ -623,6 +642,35 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
623642
}
624643
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
625644

645+
/**
646+
* dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
647+
* clock corresponding to the index
648+
* @dev: Device for which we do this operation
649+
* @freq: frequency to search for
650+
* @index: Clock index
651+
* @available: true/false - match for available opp
652+
*
653+
* Search for the matching exact OPP for the clock corresponding to the
654+
* specified index from a starting freq for a device.
655+
*
656+
* Return: matching *opp , else returns ERR_PTR in case of error and should be
657+
* handled using IS_ERR. Error return values can be:
658+
* EINVAL: for bad pointer
659+
* ERANGE: no match found for search
660+
* ENODEV: if device not found in list of registered devices
661+
*
662+
* The callers are required to call dev_pm_opp_put() for the returned OPP after
663+
* use.
664+
*/
665+
struct dev_pm_opp *
666+
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
667+
u32 index, bool available)
668+
{
669+
return _find_key_exact(dev, freq, index, available, _read_freq,
670+
assert_clk_index);
671+
}
672+
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact_indexed);
673+
626674
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
627675
unsigned long *freq)
628676
{
@@ -679,7 +727,8 @@ struct dev_pm_opp *
679727
dev_pm_opp_find_freq_ceil_indexed(struct device *dev, unsigned long *freq,
680728
u32 index)
681729
{
682-
return _find_key_ceil(dev, freq, index, true, _read_freq, NULL);
730+
return _find_key_ceil(dev, freq, index, true, _read_freq,
731+
assert_clk_index);
683732
}
684733
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
685734

@@ -732,7 +781,7 @@ struct dev_pm_opp *
732781
dev_pm_opp_find_freq_floor_indexed(struct device *dev, unsigned long *freq,
733782
u32 index)
734783
{
735-
return _find_key_floor(dev, freq, index, true, _read_freq, NULL);
784+
return _find_key_floor(dev, freq, index, true, _read_freq, assert_clk_index);
736785
}
737786
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor_indexed);
738787

@@ -850,7 +899,8 @@ struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct device *dev, unsigned int *bw,
850899
unsigned long temp = *bw;
851900
struct dev_pm_opp *opp;
852901

853-
opp = _find_key_ceil(dev, &temp, index, true, _read_bw, NULL);
902+
opp = _find_key_ceil(dev, &temp, index, true, _read_bw,
903+
assert_bandwidth_index);
854904
*bw = temp;
855905
return opp;
856906
}
@@ -881,7 +931,8 @@ struct dev_pm_opp *dev_pm_opp_find_bw_floor(struct device *dev,
881931
unsigned long temp = *bw;
882932
struct dev_pm_opp *opp;
883933

884-
opp = _find_key_floor(dev, &temp, index, true, _read_bw, NULL);
934+
opp = _find_key_floor(dev, &temp, index, true, _read_bw,
935+
assert_bandwidth_index);
885936
*bw = temp;
886937
return opp;
887938
}
@@ -1675,7 +1726,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
16751726
if (IS_ERR(opp_table))
16761727
return;
16771728

1678-
if (!assert_single_clk(opp_table))
1729+
if (!assert_single_clk(opp_table, 0))
16791730
goto put_table;
16801731

16811732
mutex_lock(&opp_table->lock);
@@ -2027,7 +2078,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
20272078
unsigned long tol, u_volt = data->u_volt;
20282079
int ret;
20292080

2030-
if (!assert_single_clk(opp_table))
2081+
if (!assert_single_clk(opp_table, 0))
20312082
return -EINVAL;
20322083

20332084
new_opp = _opp_allocate(opp_table);
@@ -2894,7 +2945,7 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
28942945
return r;
28952946
}
28962947

2897-
if (!assert_single_clk(opp_table)) {
2948+
if (!assert_single_clk(opp_table, 0)) {
28982949
r = -EINVAL;
28992950
goto put_table;
29002951
}
@@ -2970,7 +3021,7 @@ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
29703021
return r;
29713022
}
29723023

2973-
if (!assert_single_clk(opp_table)) {
3024+
if (!assert_single_clk(opp_table, 0)) {
29743025
r = -EINVAL;
29753026
goto put_table;
29763027
}

include/linux/pm_opp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
142142
unsigned long freq,
143143
bool available);
144144

145+
struct dev_pm_opp *
146+
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
147+
u32 index, bool available);
148+
145149
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
146150
unsigned long *freq);
147151

@@ -284,6 +288,13 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
284288
return ERR_PTR(-EOPNOTSUPP);
285289
}
286290

291+
static inline struct dev_pm_opp *
292+
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
293+
u32 index, bool available)
294+
{
295+
return ERR_PTR(-EOPNOTSUPP);
296+
}
297+
287298
static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
288299
unsigned long *freq)
289300
{

0 commit comments

Comments
 (0)