Thank you for your contribution! Sashiko AI review found 1 potential issue(s) 
to consider:
- [High] Percpu counters are permanently leaked when module alloc_tags fall 
back to regular module memory.
--

commit e3319858bb95e951205b0e09569d4ef2ec702635
Author: Hao Ge <[email protected]>

module: allocate codetag sections before the regular module layout

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.

Link: 
https://lore.kernel.org/all/[email protected]/ [1]

> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 15ad6c54bb1c3..f020293b3a496 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c

[ ... ]

> @@ -2947,6 +2908,49 @@ 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;

[Severity: High]
Does this error fallback path lead to a permanent percpu memory leak?

When the dedicated tag memory area is full and tags_addressable() returns
false, reserve_module_tags() returns -EAGAIN. This code bypasses the error via
continue, falling back to allocating the .alloc_tags section as a regular
module data section instead of failing the module load.

However, mm/alloc_tag.c:load_module() still unconditionally allocates percpu
counters for these tags:

    tag->counters = alloc_percpu(struct alloc_tag_counters);

When the module later unloads, mm/alloc_tag.c:release_module_tags() attempts
to clean up:

    if (!val) /* module not found */
        goto out;

Since the module's tags fell back to regular memory, the module is not found
in the mod_area_mt maple tree, and release_module_tags() immediately returns.
This skips clean_unused_counters() and appears to permanently leak the percpu
counters for every tag in the module.

Could this eventual exhaustion of percpu memory be avoided by either skipping
the percpu allocation or ensuring the cleanup logic can find modules that fell
back to regular memory?

> +             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);
> +             else
> +                     memset(dest, 0, shdr->sh_size);
> +             shdr->sh_addr = (unsigned long)dest;
> +             shdr->sh_entsize = SH_ENTSIZE_STANDALONE;
> +     }
> +
> +     return 0;
> +}
> +

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=4

Reply via email to