[RFC PATCH 4/9] module: Allocate MOD_INIT_TEXT from the MOD_TEXT ROX allocation

Ard Biesheuvel <[email protected]>
Newsgroups org.kernel.vger.linux-modules,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-trace-kernel,org.kvack.linux-mm
Message-ID <[email protected]>
From: Ard Biesheuvel <[email protected]>

When execmem ROX caches are used for module text and inittext, place
them adjacently in memory, by allocating space for both initially, and
splitting off the space for MOD_INIT_TEXT as needed.

This avoids the corner case on arm64, where .init.text being placed far
from .text results in a lot of complexity wrt indirect branches and PLTs
that we'd prefer to avoid.

Signed-off-by: Ard Biesheuvel <[email protected]>
---
 kernel/module/main.c | 22 ++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..2d6213496359 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1342,7 +1342,7 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type)
 {
 	unsigned int size = PAGE_ALIGN(mod->mem[type].size);
 	enum execmem_type execmem_type;
-	void *ptr;
+	void *ptr = NULL;
 
 	mod->mem[type].size = size;
 
@@ -1351,11 +1351,25 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type)
 	else
 		execmem_type = EXECMEM_MODULE_TEXT;
 
-	ptr = execmem_alloc_rw(execmem_type, size);
+	bool is_rox = execmem_is_rox(execmem_type);
+	if (is_rox) {
+		/*
+		 * Special case for MOD_TEXT / MOD_INIT_TEXT: allocate the
+		 * latter by splitting off required space from the former
+		 * so that they are always placed close together.
+		 */
+		if (type == MOD_TEXT)
+			size += PAGE_ALIGN(mod->mem[MOD_INIT_TEXT].size);
+		else if (type == MOD_INIT_TEXT)
+			ptr = execmem_split(mod->mem[MOD_TEXT].base, size);
+	}
+
+	if (!ptr)
+		ptr = execmem_alloc_rw(execmem_type, size);
 	if (!ptr)
 		return -ENOMEM;
 
-	mod->mem[type].is_rox = execmem_is_rox(execmem_type);
+	mod->mem[type].is_rox = is_rox;
 
 	/*
 	 * The pointer to these blocks of memory are stored on the module
@@ -1368,7 +1382,7 @@ static int module_memory_alloc(struct module *mod, enum mod_mem_type type)
 	 * *do* eventually get freed, but let's just keep things simple
 	 * and avoid *any* false positives.
 	 */
-	if (!mod->mem[type].is_rox)
+	if (!is_rox)
 		kmemleak_not_leak(ptr);
 
 	memset(ptr, 0, size);
-- 
2.55.0.860.g4b6b3295ed-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.