Takashi Iwai a1094b
From 7045465500e465b09f09d6e5bdc260a9f1aab97b Mon Sep 17 00:00:00 2001
Takashi Iwai a1094b
From: Lukasz Bartosik <lb@semihalf.com>
Takashi Iwai a1094b
Date: Fri, 2 Apr 2021 00:51:49 +0200
Takashi Iwai a1094b
Subject: [PATCH] clk: fix invalid usage of list cursor in unregister
Takashi Iwai a1094b
Git-commit: 7045465500e465b09f09d6e5bdc260a9f1aab97b
Takashi Iwai a1094b
Patch-mainline: v5.12-rc7
Takashi Iwai a1094b
References: git-fixes
Takashi Iwai a1094b
Takashi Iwai a1094b
Fix invalid usage of a list_for_each_entry cursor in
Takashi Iwai a1094b
clk_notifier_unregister(). When list is empty or if the list
Takashi Iwai a1094b
is completely traversed (without breaking from the loop on one
Takashi Iwai a1094b
of the entries) then the list cursor does not point to a valid
Takashi Iwai a1094b
entry and therefore should not be used. The patch fixes a logical
Takashi Iwai a1094b
bug that hasn't been seen in pratice however it is analogus
Takashi Iwai a1094b
to the bug fixed in clk_notifier_register().
Takashi Iwai a1094b
Takashi Iwai a1094b
The issue was dicovered when running 5.12-rc1 kernel on x86_64
Takashi Iwai a1094b
with KASAN enabled:
Takashi Iwai a1094b
Bug: KASAN: global-out-of-bounds in clk_notifier_register+0xab/0x230
Takashi Iwai a1094b
Read of size 8 at addr ffffffffa0d10588 by task swapper/0/1
Takashi Iwai a1094b
Takashi Iwai a1094b
Cpu: 1 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1 #1
Takashi Iwai a1094b
Hardware name: Google Caroline/Caroline,
Takashi Iwai a1094b
BIOS Google_Caroline.7820.430.0 07/20/2018
Takashi Iwai a1094b
Call Trace:
Takashi Iwai a1094b
 dump_stack+0xee/0x15c
Takashi Iwai a1094b
 print_address_description+0x1e/0x2dc
Takashi Iwai a1094b
 kasan_report+0x188/0x1ce
Takashi Iwai a1094b
 ? clk_notifier_register+0xab/0x230
Takashi Iwai a1094b
 ? clk_prepare_lock+0x15/0x7b
Takashi Iwai a1094b
 ? clk_notifier_register+0xab/0x230
Takashi Iwai a1094b
 clk_notifier_register+0xab/0x230
Takashi Iwai a1094b
 dw8250_probe+0xc01/0x10d4
Takashi Iwai a1094b
 ...
Takashi Iwai a1094b
 Memory state around the buggy address:
Takashi Iwai a1094b
  ffffffffa0d10480: 00 00 00 00 00 03 f9 f9 f9 f9 f9 f9 00 00 00 00
Takashi Iwai a1094b
  ffffffffa0d10500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9
Takashi Iwai a1094b
 >ffffffffa0d10580: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
Takashi Iwai a1094b
                          ^
Takashi Iwai a1094b
  ffffffffa0d10600: 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 00 00 00 00
Takashi Iwai a1094b
  ffffffffa0d10680: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 00 00 00 00
Takashi Iwai a1094b
  ==================================================================
Takashi Iwai a1094b
Takashi Iwai a1094b
Fixes: b2476490ef11 ("clk: introduce the common clock framework")
Takashi Iwai a1094b
Reported-by: Lukasz Majczak <lma@semihalf.com>
Takashi Iwai a1094b
Signed-off-by: Lukasz Bartosik <lb@semihalf.com>
Takashi Iwai a1094b
Link: https://lore.kernel.org/r/20210401225149.18826-2-lb@semihalf.com
Takashi Iwai a1094b
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Takashi Iwai a1094b
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai a1094b
Takashi Iwai a1094b
---
Takashi Iwai a1094b
 drivers/clk/clk.c | 30 +++++++++++++-----------------
Takashi Iwai a1094b
 1 file changed, 13 insertions(+), 17 deletions(-)
Takashi Iwai a1094b
Takashi Iwai a1094b
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
Takashi Iwai a1094b
index 16634d5912be..39cfc6c6a8d2 100644
Takashi Iwai a1094b
--- a/drivers/clk/clk.c
Takashi Iwai a1094b
+++ b/drivers/clk/clk.c
Takashi Iwai a1094b
@@ -4394,32 +4394,28 @@ EXPORT_SYMBOL_GPL(clk_notifier_register);
Takashi Iwai a1094b
  */
Takashi Iwai a1094b
 int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
Takashi Iwai a1094b
 {
Takashi Iwai a1094b
-	struct clk_notifier *cn = NULL;
Takashi Iwai a1094b
-	int ret = -EINVAL;
Takashi Iwai a1094b
+	struct clk_notifier *cn;
Takashi Iwai a1094b
+	int ret = -ENOENT;
Takashi Iwai a1094b
 
Takashi Iwai a1094b
 	if (!clk || !nb)
Takashi Iwai a1094b
 		return -EINVAL;
Takashi Iwai a1094b
 
Takashi Iwai a1094b
 	clk_prepare_lock();
Takashi Iwai a1094b
 
Takashi Iwai a1094b
-	list_for_each_entry(cn, &clk_notifier_list, node)
Takashi Iwai a1094b
-		if (cn->clk == clk)
Takashi Iwai a1094b
-			break;
Takashi Iwai a1094b
-
Takashi Iwai a1094b
-	if (cn->clk == clk) {
Takashi Iwai a1094b
-		ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
Takashi Iwai a1094b
+	list_for_each_entry(cn, &clk_notifier_list, node) {
Takashi Iwai a1094b
+		if (cn->clk == clk) {
Takashi Iwai a1094b
+			ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
Takashi Iwai a1094b
 
Takashi Iwai a1094b
-		clk->core->notifier_count--;
Takashi Iwai a1094b
+			clk->core->notifier_count--;
Takashi Iwai a1094b
 
Takashi Iwai a1094b
-		/* XXX the notifier code should handle this better */
Takashi Iwai a1094b
-		if (!cn->notifier_head.head) {
Takashi Iwai a1094b
-			srcu_cleanup_notifier_head(&cn->notifier_head);
Takashi Iwai a1094b
-			list_del(&cn->node);
Takashi Iwai a1094b
-			kfree(cn);
Takashi Iwai a1094b
+			/* XXX the notifier code should handle this better */
Takashi Iwai a1094b
+			if (!cn->notifier_head.head) {
Takashi Iwai a1094b
+				srcu_cleanup_notifier_head(&cn->notifier_head);
Takashi Iwai a1094b
+				list_del(&cn->node);
Takashi Iwai a1094b
+				kfree(cn);
Takashi Iwai a1094b
+			}
Takashi Iwai a1094b
+			break;
Takashi Iwai a1094b
 		}
Takashi Iwai a1094b
-
Takashi Iwai a1094b
-	} else {
Takashi Iwai a1094b
-		ret = -ENOENT;
Takashi Iwai a1094b
 	}
Takashi Iwai a1094b
 
Takashi Iwai a1094b
 	clk_prepare_unlock();
Takashi Iwai a1094b
-- 
Takashi Iwai a1094b
2.26.2
Takashi Iwai a1094b