The reservation is already stored in the maple tree when
vm_module_tags_populate() fails. A failed load never unloads the
module, so nothing releases the entry. Release it and roll
module_tags.size back. Without the rollback a concurrent load that
already passed needs_section_mem() can reuse the freed gap, skip
vm_module_tags_populate() and write to unmapped memory.

vmap_pages_range() may have installed some PTEs before failing. A
retry to populate the same range would BUG on them, so undo them,
but only if vmap actually ran.

Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression")
Fixes: 0f9b685626da ("alloc_tag: populate memory for module tags as needed")
Reported-by: Sashiko <[email protected]>
Cc: [email protected]
Signed-off-by: Hao Ge <[email protected]>
---
 mm/alloc_tag.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index e7a79116ad81..e7a40a276ed9 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -812,6 +812,13 @@ static int vm_module_tags_populate(void)
                                     next_page, PAGE_SHIFT) < 0) {
                        release_pages_arg arg = { .pages = next_page };
 
+                       /*
+                        * vmap_pages_range() only runs once all pages were
+                        * allocated, and it may have installed some mappings
+                        * before failing. Undo them.
+                        */
+                       if (nr == more_pages)
+                               vunmap_range(phys_end, phys_end + (nr << 
PAGE_SHIFT));
                        /* Clean up and error out */
                        release_pages(arg, nr);
                        return -ENOMEM;
@@ -955,6 +962,7 @@ static void *reserve_module_tags(struct module *mod, 
unsigned long size,
                return ret;
 
        if (module_tags.size < offset + size) {
+               unsigned long prev_size = module_tags.size;
                int grow_res;
 
                module_tags.size = offset + size;
@@ -969,6 +977,8 @@ static void *reserve_module_tags(struct module *mod, 
unsigned long size,
                        shutdown_mem_profiling(true);
                        pr_err("Failed to allocate memory for allocation tags 
in the module %s. Memory allocation profiling is disabled!\n",
                               mod->name);
+                       release_module_tags(mod, false);
+                       module_tags.size = prev_size;
                        return ERR_PTR(grow_res);
                }
        }
-- 
2.25.1


Reply via email to