jffs2: Fix list_del corruption if compressors initialized failed
authorZhang Xiaoxu <zhangxiaoxu5@huawei.com>
Thu, 27 Oct 2022 12:49:06 +0000 (20:49 +0800)
committerRichard Weinberger <richard@nod.at>
Thu, 2 Feb 2023 20:13:55 +0000 (21:13 +0100)
There is a list_del corruption when remove the jffs2 module:

  list_del corruption, ffffffffa0623e60->next is NULL
  WARNING: CPU: 6 PID: 6332 at lib/list_debug.c:49 __list_del_entry_valid+0x98/0x130
  Modules linked in: jffs2(-) ]
  CPU: 6 PID: 6332 Comm: rmmod Tainted: G        W          6.1.0-rc2+ #5
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014
  RIP: 0010:__list_del_entry_valid+0x98/0x130
  ...
  Call Trace:
   <TASK>
   jffs2_unregister_compressor+0x3e/0xe0 [jffs2]
   jffs2_zlib_exit+0x11/0x30 [jffs2]
   jffs2_compressors_exit+0x1e/0x30 [jffs2]
   exit_jffs2_fs+0x16/0x44f [jffs2]
   __do_sys_delete_module.constprop.0+0x244/0x370
   do_syscall_64+0x35/0x80
   entry_SYSCALL_64_after_hwframe+0x46/0xb0

If one of the compressor initialize failed, the module always insert
success since jffs2_compressors_init() always return success, then
something bad may happen during remove the module.

For this scenario, let's insmod failed.

Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
fs/jffs2/compr.c

index afe74c6..764f19d 100644 (file)
@@ -364,12 +364,24 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 
 int __init jffs2_compressors_init(void)
 {
+       int ret = 0;
 /* Registering compressors */
-       jffs2_zlib_init();
-       jffs2_rtime_init();
-       jffs2_rubinmips_init();
-       jffs2_dynrubin_init();
-       jffs2_lzo_init();
+       ret = jffs2_zlib_init();
+       if (ret)
+               goto exit;
+       ret = jffs2_rtime_init();
+       if (ret)
+               goto exit_zlib;
+       ret = jffs2_rubinmips_init();
+       if (ret)
+               goto exit_rtime;
+       ret = jffs2_dynrubin_init();
+       if (ret)
+               goto exit_runinmips;
+       ret = jffs2_lzo_init();
+       if (ret)
+               goto exit_dynrubin;
+
 
 /* Setting default compression mode */
 #ifdef CONFIG_JFFS2_CMODE_NONE
@@ -389,6 +401,17 @@ int __init jffs2_compressors_init(void)
 #endif
 #endif
        return 0;
+
+exit_dynrubin:
+       jffs2_dynrubin_exit();
+exit_runinmips:
+       jffs2_rubinmips_exit();
+exit_rtime:
+       jffs2_rtime_exit();
+exit_zlib:
+       jffs2_zlib_exit();
+exit:
+       return ret;
 }
 
 int jffs2_compressors_exit(void)