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


Reply via email to