From: Hao Ge <hao.ge@linux.dev>
To: Luis Chamberlain <mcgrof@kernel.org>,
Petr Pavlu <petr.pavlu@suse.com>,
Daniel Gomez <da.gomez@kernel.org>,
Sami Tolvanen <samitolvanen@google.com>,
Aaron Tomlin <atomlin@atomlin.com>,
Suren Baghdasaryan <surenb@google.com>, Hao Ge <hao.ge@linux.dev>,
Andrew Morton <akpm@linux-foundation.org>
Cc: linux-modules@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, Sashiko <sashiko-bot@kernel.org>,
stable@vger.kernel.org
Subject: [PATCH v7 3/4] module: allocate codetag sections before the regular module layout
Date: Wed, 2 Sep 2026 16:18:01 +0800 [thread overview]
Message-ID: <20260902081802.146145-4-hao.ge@linux.dev> (raw)
In-Reply-To: <20260902081802.146145-1-hao.ge@linux.dev>
Whether a codetag section goes to the codetag region is decided by
layout_sections() and asked again in move_module(). A concurrent
load can shut profiling down in between, and move_module() then
copies the section to offset 0 of its regular destination,
overwriting whatever is there.
Decide and allocate in one pass, before the layout. Allocation
errors fail the load. On a tag area overflow profiling is already
disabled, so -EAGAIN makes the section fall back to regular module
data and the module still loads.
When profiling was toggled off the overflow check did not run, a
module could load with more tags than the page flags can address,
and re-enabling profiling then silently corrupted /proc/allocinfo.
The check no longer depends on mem_alloc_profiling_enabled().
Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Based-on-a-patch-by: Petr Pavlu <petr.pavlu@suse.com>
Link: https://lore.kernel.org/all/499bb60c-c6e3-43a3-bd92-95a0567ece5e@suse.com/
Cc: stable@vger.kernel.org
Signed-off-by: Hao Ge <hao.ge@linux.dev>
---
kernel/module/main.c | 99 +++++++++++++++++++++++---------------------
mm/alloc_tag.c | 8 ++--
2 files changed, 57 insertions(+), 50 deletions(-)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 078dae188aba..d0a8ac9b3ee5 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1717,20 +1717,6 @@ static void __layout_sections(struct module *mod, struct load_info *info, bool i
if (WARN_ON_ONCE(type == MOD_INVALID))
continue;
- /*
- * Do not allocate codetag memory as we load it into
- * preallocated contiguous memory.
- */
- if (codetag_needs_module_section(mod, sname, s->sh_size)) {
- /*
- * s->sh_entsize won't be used but populate the
- * type field to avoid confusion.
- */
- s->sh_entsize = ((unsigned long)(type) & SH_ENTSIZE_TYPE_MASK)
- << SH_ENTSIZE_TYPE_SHIFT;
- continue;
- }
-
s->sh_entsize = module_get_offset_and_type(mod, type, s, i);
pr_debug("\t%s\n", sname);
}
@@ -2777,7 +2763,6 @@ static int move_module(struct module *mod, struct load_info *info)
{
int i, ret;
enum mod_mem_type t = MOD_MEM_NUM_TYPES;
- bool codetag_section_found = false;
for_each_mod_mem_type(type) {
if (!mod->mem[type].size) {
@@ -2797,35 +2782,13 @@ static int move_module(struct module *mod, struct load_info *info)
for (i = 0; i < info->hdr->e_shnum; i++) {
void *dest;
Elf_Shdr *shdr = &info->sechdrs[i];
- const char *sname;
if (!(shdr->sh_flags & SHF_ALLOC)
|| shdr->sh_entsize == SH_ENTSIZE_STANDALONE)
continue;
- sname = info->secstrings + shdr->sh_name;
- /*
- * Load codetag sections separately as they might still be used
- * after module unload.
- */
- if (codetag_needs_module_section(mod, sname, shdr->sh_size)) {
- dest = codetag_alloc_module_section(mod, sname, shdr->sh_size,
- arch_mod_section_prepend(mod, i), shdr->sh_addralign);
- if (WARN_ON(!dest)) {
- ret = -EINVAL;
- goto out_err;
- }
- if (IS_ERR(dest)) {
- ret = PTR_ERR(dest);
- goto out_err;
- }
- codetag_section_found = true;
- } else {
- enum mod_mem_type type = shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT;
- unsigned long offset = shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK;
-
- dest = mod->mem[type].base + offset;
- }
+ dest = mod->mem[shdr->sh_entsize >> SH_ENTSIZE_TYPE_SHIFT].base +
+ (shdr->sh_entsize & SH_ENTSIZE_OFFSET_MASK);
if (shdr->sh_type != SHT_NOBITS) {
/*
@@ -2857,8 +2820,6 @@ static int move_module(struct module *mod, struct load_info *info)
module_memory_restore_rox(mod);
while (t--)
module_memory_free(mod, t);
- if (codetag_section_found)
- codetag_free_module_sections(mod);
return ret;
}
@@ -2929,6 +2890,47 @@ static bool blacklisted(const char *module_name)
}
core_param(module_blacklist, module_blacklist, charp, 0400);
+/*
+ * Allocate codetag sections separately. They are loaded into preallocated
+ * contiguous memory because they may still be used after the module is
+ * unloaded.
+ *
+ * If the separate allocation overflows, allocate the section normally
+ * so that the module can still be loaded.
+ */
+static int allocate_codetag_sections(struct load_info *info)
+{
+ for (unsigned int i = 1; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
+ const char *sname = info->secstrings + shdr->sh_name;
+ void *dest;
+
+ if (!codetag_needs_module_section(info->mod, sname, shdr->sh_size))
+ continue;
+
+ dest = codetag_alloc_module_section(info->mod, sname, shdr->sh_size,
+ arch_mod_section_prepend(info->mod, i), shdr->sh_addralign);
+ if (WARN_ON(!dest)) {
+ codetag_free_module_sections(info->mod);
+ return -EINVAL;
+ }
+ if (dest == ERR_PTR(-EAGAIN))
+ /* Allocate the section as a regular section. */
+ continue;
+ if (IS_ERR(dest)) {
+ codetag_free_module_sections(info->mod);
+ return PTR_ERR(dest);
+ }
+
+ if (shdr->sh_type != SHT_NOBITS)
+ memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
+ shdr->sh_addr = (unsigned long)dest;
+ shdr->sh_entsize = SH_ENTSIZE_STANDALONE;
+ }
+
+ return 0;
+}
+
static struct module *layout_and_allocate(struct load_info *info, int flags)
{
struct module *mod;
@@ -2961,18 +2963,21 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
*/
module_mark_ro_after_init(info->hdr, info->sechdrs, info->secstrings);
- /*
- * Determine total sizes, and put offsets in sh_entsize. For now
- * this is done generically; there doesn't appear to be any
- * special cases for the architectures.
- */
+ /* Allow codetag sections to be allocated separately first. */
+ err = allocate_codetag_sections(info);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Determine total sizes and put offsets in sh_entsize. */
layout_sections(info->mod, info);
layout_symtab(info->mod, info);
/* Allocate and move to the final place */
err = move_module(info->mod, info);
- if (err)
+ if (err) {
+ codetag_free_module_sections(info->mod);
return ERR_PTR(err);
+ }
/* Module has been copied to its final place now: return it. */
mod = (void *)info->sechdrs[info->index.mod].sh_addr;
diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index e7a79116ad81..248496470904 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -958,10 +958,12 @@ static void *reserve_module_tags(struct module *mod, unsigned long size,
int grow_res;
module_tags.size = offset + size;
- if (mem_alloc_profiling_enabled() && !tags_addressable()) {
+ if (!tags_addressable()) {
shutdown_mem_profiling(true);
- pr_warn("With module %s there are too many tags to fit in %d page flag bits. Memory allocation profiling is disabled!\n",
- mod->name, NR_UNUSED_PAGEFLAG_BITS);
+ pr_warn_once("With module %s there are too many tags to fit in %d page flag bits. Memory allocation profiling is disabled!\n",
+ mod->name, NR_UNUSED_PAGEFLAG_BITS);
+ release_module_tags(mod, false);
+ return ERR_PTR(-EAGAIN);
}
grow_res = vm_module_tags_populate();
--
2.25.1
next prev parent reply other threads:[~2026-09-02 8:17 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 8:17 [PATCH v7 0/4] alloc_tag and module codetag section fixes Hao Ge
2026-09-02 8:17 ` [PATCH v7 1/4] alloc_tag: move release_module_tags() above reserve_module_tags() Hao Ge
2026-09-02 8:18 ` [PATCH v7 2/4] module: introduce SH_ENTSIZE_STANDALONE for separately allocated sections Hao Ge
2026-09-04 16:10 ` Petr Pavlu
2026-09-02 8:18 ` Hao Ge [this message]
2026-09-02 8:18 ` [PATCH v7 4/4] alloc_tag: release the reservation when populate fails Hao Ge
2026-09-02 22:05 ` [PATCH v7 0/4] alloc_tag and module codetag section fixes Andrew Morton
2026-09-03 6:30 ` Hao Ge
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260902081802.146145-4-hao.ge@linux.dev \
--to=hao.ge@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=atomlin@atomlin.com \
--cc=da.gomez@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-modules@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=petr.pavlu@suse.com \
--cc=samitolvanen@google.com \
--cc=sashiko-bot@kernel.org \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox