From: Lukasz Bartosik <l...@semihalf.com>

[ Upstream commit 8d3c0c01cb2e36b2bf3c06a82b18b228d0c8f5d0 ]

Fix invalid usage of a list_for_each_entry cursor in
clk_notifier_register(). When list is empty or if the list
is completely traversed (without breaking from the loop on one
of the entries) then the list cursor does not point to a valid
entry and therefore should not be used.

The issue was dicovered when running 5.12-rc1 kernel on x86_64
with KASAN enabled:
BUG: KASAN: global-out-of-bounds in clk_notifier_register+0xab/0x230
Read of size 8 at addr ffffffffa0d10588 by task swapper/0/1

CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1 #1
Hardware name: Google Caroline/Caroline,
BIOS Google_Caroline.7820.430.0 07/20/2018
Call Trace:
 dump_stack+0xee/0x15c
 print_address_description+0x1e/0x2dc
 kasan_report+0x188/0x1ce
 ? clk_notifier_register+0xab/0x230
 ? clk_prepare_lock+0x15/0x7b
 ? clk_notifier_register+0xab/0x230
 clk_notifier_register+0xab/0x230
 dw8250_probe+0xc01/0x10d4
...
Memory state around the buggy address:
 ffffffffa0d10480: 00 00 00 00 00 03 f9 f9 f9 f9 f9 f9 00 00 00 00
 ffffffffa0d10500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9
>ffffffffa0d10580: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
                      ^
 ffffffffa0d10600: 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 00 00 00 00
 ffffffffa0d10680: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 00 00 00 00
 ==================================================================

Fixes: b2476490ef11 ("clk: introduce the common clock framework")
Reported-by: Lukasz Majczak <l...@semihalf.com>
Signed-off-by: Lukasz Bartosik <l...@semihalf.com>
Link: https://lore.kernel.org/r/20210401225149.18826-1...@semihalf.com
Signed-off-by: Stephen Boyd <sb...@kernel.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/clk/clk.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 36e9f38a3882..5db91903d02b 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -4151,20 +4151,19 @@ int clk_notifier_register(struct clk *clk, struct 
notifier_block *nb)
        /* search the list of notifiers for this clk */
        list_for_each_entry(cn, &clk_notifier_list, node)
                if (cn->clk == clk)
-                       break;
+                       goto found;
 
        /* if clk wasn't in the notifier list, allocate new clk_notifier */
-       if (cn->clk != clk) {
-               cn = kzalloc(sizeof(*cn), GFP_KERNEL);
-               if (!cn)
-                       goto out;
+       cn = kzalloc(sizeof(*cn), GFP_KERNEL);
+       if (!cn)
+               goto out;
 
-               cn->clk = clk;
-               srcu_init_notifier_head(&cn->notifier_head);
+       cn->clk = clk;
+       srcu_init_notifier_head(&cn->notifier_head);
 
-               list_add(&cn->node, &clk_notifier_list);
-       }
+       list_add(&cn->node, &clk_notifier_list);
 
+found:
        ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
 
        clk->core->notifier_count++;
-- 
2.30.2



Reply via email to