[PATCH] ubi: Revert "ubi: wl: Close down wear-leveling before nand is suspended"

Zhihao Cheng posted 1 patch 1 year ago
drivers/mtd/ubi/ubi.h |  2 --
drivers/mtd/ubi/wl.c  | 21 ---------------------
2 files changed, 23 deletions(-)
[PATCH] ubi: Revert "ubi: wl: Close down wear-leveling before nand is suspended"
Posted by Zhihao Cheng 1 year ago
Commit 5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is
suspended") added a reboot notification in UBI layer to shutdown the
wear-leveling subsystem, which imported an UAF problem[1]. Besides that,
the method also brings other potential UAF problems, for example:
       reboot             kworker
 ubi_wl_reboot_notifier
  ubi_wl_close
   ubi_fastmap_close
    kfree(ubi->fm)
                     update_fastmap_work_fn
		      ubi_update_fastmap
		       old_fm = ubi->fm
		       if (old_fm && old_fm->e[i]) // UAF!

Actually, the problem fixed by commit 5580cdae05ae ("ubi: wl: Close down
wear-leveling before nand is suspended") has been solved by commit
8cba323437a4 ("mtd: rawnand: protect access to rawnand devices while in
suspend"), which was discussed in [2]. So we can revert the commit
5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is
suspended") directly.

[1] https://lore.kernel.org/linux-mtd/20241208175211.9406-2-dennis.lamerice@gmail.com/
[2] https://lore.kernel.org/all/9bf76f5d-12a4-46ff-90d4-4a7f0f47c381@axis.com/

Fixes: 5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is suspended")
Reported-by: Dennis Lam <dennis.lamerice@gmail.com>
Closes: https://lore.kernel.org/linux-mtd/20241208175211.9406-2-dennis.lamerice@gmail.com/
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
---
 drivers/mtd/ubi/ubi.h |  2 --
 drivers/mtd/ubi/wl.c  | 21 ---------------------
 2 files changed, 23 deletions(-)

diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 26cc53ad34ec..c792b9bcab9b 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -549,7 +549,6 @@ struct ubi_debug_info {
  * @peb_buf: a buffer of PEB size used for different purposes
  * @buf_mutex: protects @peb_buf
  * @ckvol_mutex: serializes static volume checking when opening
- * @wl_reboot_notifier: close all wear-leveling work before reboot
  *
  * @dbg: debugging information for this UBI device
  */
@@ -652,7 +651,6 @@ struct ubi_device {
 	void *peb_buf;
 	struct mutex buf_mutex;
 	struct mutex ckvol_mutex;
-	struct notifier_block wl_reboot_notifier;
 
 	struct ubi_debug_info dbg;
 };
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 4f6f339d8fb8..fbd399cf6503 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -89,7 +89,6 @@
 #include <linux/crc32.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
-#include <linux/reboot.h>
 #include "ubi.h"
 #include "wl.h"
 
@@ -128,8 +127,6 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi,
 				 struct ubi_wl_entry *e, struct rb_root *root);
 static int self_check_in_pq(const struct ubi_device *ubi,
 			    struct ubi_wl_entry *e);
-static int ubi_wl_reboot_notifier(struct notifier_block *n,
-				  unsigned long state, void *cmd);
 
 /**
  * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
@@ -1953,13 +1950,6 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 	if (!ubi->ro_mode && !ubi->fm_disabled)
 		ubi_ensure_anchor_pebs(ubi);
 #endif
-
-	if (!ubi->wl_reboot_notifier.notifier_call) {
-		ubi->wl_reboot_notifier.notifier_call = ubi_wl_reboot_notifier;
-		ubi->wl_reboot_notifier.priority = 1; /* Higher than MTD */
-		register_reboot_notifier(&ubi->wl_reboot_notifier);
-	}
-
 	return 0;
 
 out_free:
@@ -2005,17 +1995,6 @@ void ubi_wl_close(struct ubi_device *ubi)
 	kfree(ubi->lookuptbl);
 }
 
-static int ubi_wl_reboot_notifier(struct notifier_block *n,
-				  unsigned long state, void *cmd)
-{
-	struct ubi_device *ubi;
-
-	ubi = container_of(n, struct ubi_device, wl_reboot_notifier);
-	ubi_wl_close(ubi);
-
-	return NOTIFY_DONE;
-}
-
 /**
  * self_check_ec - make sure that the erase counter of a PEB is correct.
  * @ubi: UBI device description object
-- 
2.46.1
Re: [PATCH] ubi: Revert "ubi: wl: Close down wear-leveling before nand is suspended"
Posted by Marten Lindahl 1 year ago
Hi Zhihao Cheng!

Yes, we discussed this issue in [2], and I thought 5580cdae05ae ("ubi: 
wl: Close down wear-leveling before nand is suspended") was dropped, but 
I see now it got merged.

I agree it should be reverted.

Acked-by: Mårten Lindahl <marten.lindahl@axis.com>

Kind regards

Mårten

On 12/14/24 12:01, Zhihao Cheng wrote:
> Commit 5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is
> suspended") added a reboot notification in UBI layer to shutdown the
> wear-leveling subsystem, which imported an UAF problem[1]. Besides that,
> the method also brings other potential UAF problems, for example:
>         reboot             kworker
>   ubi_wl_reboot_notifier
>    ubi_wl_close
>     ubi_fastmap_close
>      kfree(ubi->fm)
>                       update_fastmap_work_fn
> 		      ubi_update_fastmap
> 		       old_fm = ubi->fm
> 		       if (old_fm && old_fm->e[i]) // UAF!
>
> Actually, the problem fixed by commit 5580cdae05ae ("ubi: wl: Close down
> wear-leveling before nand is suspended") has been solved by commit
> 8cba323437a4 ("mtd: rawnand: protect access to rawnand devices while in
> suspend"), which was discussed in [2]. So we can revert the commit
> 5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is
> suspended") directly.
>
> [1] https://lore.kernel.org/linux-mtd/20241208175211.9406-2-dennis.lamerice@gmail.com/
> [2] https://lore.kernel.org/all/9bf76f5d-12a4-46ff-90d4-4a7f0f47c381@axis.com/
>
> Fixes: 5580cdae05ae ("ubi: wl: Close down wear-leveling before nand is suspended")
> Reported-by: Dennis Lam <dennis.lamerice@gmail.com>
> Closes: https://lore.kernel.org/linux-mtd/20241208175211.9406-2-dennis.lamerice@gmail.com/
> Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
> ---
>   drivers/mtd/ubi/ubi.h |  2 --
>   drivers/mtd/ubi/wl.c  | 21 ---------------------
>   2 files changed, 23 deletions(-)
>
> diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
> index 26cc53ad34ec..c792b9bcab9b 100644
> --- a/drivers/mtd/ubi/ubi.h
> +++ b/drivers/mtd/ubi/ubi.h
> @@ -549,7 +549,6 @@ struct ubi_debug_info {
>    * @peb_buf: a buffer of PEB size used for different purposes
>    * @buf_mutex: protects @peb_buf
>    * @ckvol_mutex: serializes static volume checking when opening
> - * @wl_reboot_notifier: close all wear-leveling work before reboot
>    *
>    * @dbg: debugging information for this UBI device
>    */
> @@ -652,7 +651,6 @@ struct ubi_device {
>   	void *peb_buf;
>   	struct mutex buf_mutex;
>   	struct mutex ckvol_mutex;
> -	struct notifier_block wl_reboot_notifier;
>   
>   	struct ubi_debug_info dbg;
>   };
> diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
> index 4f6f339d8fb8..fbd399cf6503 100644
> --- a/drivers/mtd/ubi/wl.c
> +++ b/drivers/mtd/ubi/wl.c
> @@ -89,7 +89,6 @@
>   #include <linux/crc32.h>
>   #include <linux/freezer.h>
>   #include <linux/kthread.h>
> -#include <linux/reboot.h>
>   #include "ubi.h"
>   #include "wl.h"
>   
> @@ -128,8 +127,6 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi,
>   				 struct ubi_wl_entry *e, struct rb_root *root);
>   static int self_check_in_pq(const struct ubi_device *ubi,
>   			    struct ubi_wl_entry *e);
> -static int ubi_wl_reboot_notifier(struct notifier_block *n,
> -				  unsigned long state, void *cmd);
>   
>   /**
>    * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
> @@ -1953,13 +1950,6 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
>   	if (!ubi->ro_mode && !ubi->fm_disabled)
>   		ubi_ensure_anchor_pebs(ubi);
>   #endif
> -
> -	if (!ubi->wl_reboot_notifier.notifier_call) {
> -		ubi->wl_reboot_notifier.notifier_call = ubi_wl_reboot_notifier;
> -		ubi->wl_reboot_notifier.priority = 1; /* Higher than MTD */
> -		register_reboot_notifier(&ubi->wl_reboot_notifier);
> -	}
> -
>   	return 0;
>   
>   out_free:
> @@ -2005,17 +1995,6 @@ void ubi_wl_close(struct ubi_device *ubi)
>   	kfree(ubi->lookuptbl);
>   }
>   
> -static int ubi_wl_reboot_notifier(struct notifier_block *n,
> -				  unsigned long state, void *cmd)
> -{
> -	struct ubi_device *ubi;
> -
> -	ubi = container_of(n, struct ubi_device, wl_reboot_notifier);
> -	ubi_wl_close(ubi);
> -
> -	return NOTIFY_DONE;
> -}
> -
>   /**
>    * self_check_ec - make sure that the erase counter of a PEB is correct.
>    * @ubi: UBI device description object