OPP: Fix race between OPP addition and lookup
A race exists between dev_pm_opp_add_dynamic() and
dev_pm_opp_find_freq_exact():
CPU0 (add) CPU1 (lookup)
------------------------------- ------------------------------
_opp_add()
mutex_lock()
list_add(&new_opp->node, head)
mutex_unlock() _opp_table_find_key()
mutex_lock()
dev_pm_opp_get(opp)
kref_get()
mutex_unlock()
kref_init(&new_opp->kref)
dev_pm_opp_put()
kref_put_mutex()
The newly added OPP is inserted into the list before its kref is
initialized. A concurrent lookup can find this OPP and increment its
reference count while it is still uninitialized, leading to refcount
corruption and a potential premature free.
Fix this by initializing ->kref and ->opp_table before making the OPP
visible via list_add(). This ensures any concurrent lookup observes a
fully initialized object.
Fixes: 7034764a1e (PM / OPP: Add 'struct kref' to struct dev_pm_opp)
Co-developed-by: Ling Xu <ling_ling.xu@unisoc.com>
Signed-off-by: Ling Xu <ling_ling.xu@unisoc.com>
Signed-off-by: Di Shen <di.shen@unisoc.com>
[ Viresh: Updated commit log ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
1 parent
254f49634e
commit
f5e1cc9a28
1 file changed
+2
-3
+2
-3
@@ -2088,11 +2088,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
|
||||
return ret;
|
||||
|
||||
list_add(&new_opp->node, head);
|
||||
new_opp->opp_table = opp_table;
|
||||
kref_init(&new_opp->kref);
|
||||
}
|
||||
|
||||
new_opp->opp_table = opp_table;
|
||||
kref_init(&new_opp->kref);
|
||||
|
||||
opp_debug_create_one(new_opp, opp_table);
|
||||
|
||||
if (!_opp_supported_by_regulators(new_opp, opp_table)) {
|
||||
|
||||
Reference in new issue
Block a user