Patch "modules: wait do_free_init correctly" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    modules: wait do_free_init correctly

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     modules-wait-do_free_init-correctly.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 6c99fc8352b37d884db4a999b5b06f2b6656bfd5
Author: Changbin Du <changbin.du@xxxxxxxxxx>
Date:   Tue Feb 27 10:35:46 2024 +0800

    modules: wait do_free_init correctly
    
    [ Upstream commit 8f8cd6c0a43ed637e620bbe45a8d0e0c2f4d5130 ]
    
    The synchronization here is to ensure the ordering of freeing of a module
    init so that it happens before W+X checking.  It is worth noting it is not
    that the freeing was not happening, it is just that our sanity checkers
    raced against the permission checkers which assume init memory is already
    gone.
    
    Commit 1a7b7d922081 ("modules: Use vmalloc special flag") moved calling
    do_free_init() into a global workqueue instead of relying on it being
    called through call_rcu(..., do_free_init), which used to allowed us call
    do_free_init() asynchronously after the end of a subsequent grace period.
    The move to a global workqueue broke the gaurantees for code which needed
    to be sure the do_free_init() would complete with rcu_barrier().  To fix
    this callers which used to rely on rcu_barrier() must now instead use
    flush_work(&init_free_wq).
    
    Without this fix, we still could encounter false positive reports in W+X
    checking since the rcu_barrier() here can not ensure the ordering now.
    
    Even worse, the rcu_barrier() can introduce significant delay.  Eric
    Chanudet reported that the rcu_barrier introduces ~0.1s delay on a
    PREEMPT_RT kernel.
    
      [    0.291444] Freeing unused kernel memory: 5568K
      [    0.402442] Run /sbin/init as init process
    
    With this fix, the above delay can be eliminated.
    
    Link: https://lkml.kernel.org/r/20240227023546.2490667-1-changbin.du@xxxxxxxxxx
    Fixes: 1a7b7d922081 ("modules: Use vmalloc special flag")
    Signed-off-by: Changbin Du <changbin.du@xxxxxxxxxx>
    Tested-by: Eric Chanudet <echanude@xxxxxxxxxx>
    Acked-by: Luis Chamberlain <mcgrof@xxxxxxxxxx>
    Cc: Xiaoyi Su <suxiaoyi@xxxxxxxxxx>
    Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h
index 001b2ce83832e..89b1e0ed98114 100644
--- a/include/linux/moduleloader.h
+++ b/include/linux/moduleloader.h
@@ -115,6 +115,14 @@ int module_finalize(const Elf_Ehdr *hdr,
 		    const Elf_Shdr *sechdrs,
 		    struct module *mod);
 
+#ifdef CONFIG_MODULES
+void flush_module_init_free_work(void);
+#else
+static inline void flush_module_init_free_work(void)
+{
+}
+#endif
+
 /* Any cleanup needed when module leaves. */
 void module_arch_cleanup(struct module *mod);
 
diff --git a/init/main.c b/init/main.c
index e24b0780fdff7..9e6ab6d593bd8 100644
--- a/init/main.c
+++ b/init/main.c
@@ -88,6 +88,7 @@
 #include <linux/sched/task_stack.h>
 #include <linux/context_tracking.h>
 #include <linux/random.h>
+#include <linux/moduleloader.h>
 #include <linux/list.h>
 #include <linux/integrity.h>
 #include <linux/proc_ns.h>
@@ -1402,11 +1403,11 @@ static void mark_readonly(void)
 	if (rodata_enabled) {
 		/*
 		 * load_module() results in W+X mappings, which are cleaned
-		 * up with call_rcu().  Let's make sure that queued work is
+		 * up with init_free_wq. Let's make sure that queued work is
 		 * flushed so that we don't hit false positives looking for
 		 * insecure pages which are W+X.
 		 */
-		rcu_barrier();
+		flush_module_init_free_work();
 		mark_rodata_ro();
 		rodata_test();
 	} else
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 98fedfdb8db52..34d9e718c2c7d 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2486,6 +2486,11 @@ static void do_free_init(struct work_struct *w)
 	}
 }
 
+void flush_module_init_free_work(void)
+{
+	flush_work(&init_free_wq);
+}
+
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "module."
 /* Default value for module->async_probe_requested */
@@ -2590,8 +2595,8 @@ static noinline int do_init_module(struct module *mod)
 	 * Note that module_alloc() on most architectures creates W+X page
 	 * mappings which won't be cleaned up until do_free_init() runs.  Any
 	 * code such as mark_rodata_ro() which depends on those mappings to
-	 * be cleaned up needs to sync with the queued work - ie
-	 * rcu_barrier()
+	 * be cleaned up needs to sync with the queued work by invoking
+	 * flush_module_init_free_work().
 	 */
 	if (llist_add(&freeinit->node, &init_free_list))
 		schedule_work(&init_free_wq);




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux