> commit 68883203f0583fb1a8d79536f5c8945542974abd
> Author: Jiri Olsa <[email protected]>
> Date: Tue May 26 22:58:31 2026 +0200
>
> uprobes/x86: Unmap trampoline vma object in case it's unused
>
> In case the optimization fails, we leak new-ly created trampoline
> vma mapping (in case we just created it), let's unmap it.
>
> Fixes: ba2bfc97b462 ("uprobes/x86: Add support to optimize uprobes")
> Signed-off-by: Jiri Olsa <[email protected]>
Should this Fixes: tag point to a9fe6f54968c instead? The vma leak bug
was actually introduced by commit a9fe6f54968c ("uprobes/x86: Remove
struct uprobe_trampoline object"), not ba2bfc97b462. Commit a9fe6f54968c
removed the destroy_uprobe_trampoline() cleanup call, and its commit
message explicitly states: "The new vma leak is fixed in following
change."
Suggested: Fixes: a9fe6f54968c ("uprobes/x86: Remove struct
uprobe_trampoline object")
> diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
> index c8af41ed681a..af5af7d67999 100644
> --- a/arch/x86/kernel/uprobes.c
> +++ b/arch/x86/kernel/uprobes.c
> @@ -677,11 +677,14 @@ static unsigned long find_nearest_trampoline(unsigned
> long vaddr)
> return high_tramp;
> }
>
> -static struct vm_area_struct *get_uprobe_trampoline(struct mm_struct *mm,
> unsigned long vaddr)
> +static struct vm_area_struct *get_uprobe_trampoline(struct mm_struct *mm,
> unsigned long vaddr,
> + bool *new_mapping)
> {
> VMA_ITERATOR(vmi, mm, 0);
> struct vm_area_struct *vma;
>
> + *new_mapping = false;
> +
> if (vaddr > TASK_SIZE || vaddr < PAGE_SIZE)
> return ERR_PTR(-EINVAL);
>
Does this fix address the VMA leak scenario across fork chains? In v2,
sashiko-bot raised a concern about inherited-but-not-tracked VMAs:
https://lore.kernel.org/bpf/[email protected]/
When VM_DONTCOPY is removed, child processes inherit trampoline VMAs
but their tracking list (mm->uprobes_state.head_tramps) is empty. When
the child executes a uprobe, get_uprobe_trampoline() fails to find the
inherited VMA and creates a duplicate trampoline.
Child fork:
dup_mmap()
copies trampoline VMA to child
mm_init_uprobes_state()
initializes head_tramps as empty (parent's state not copied)
Child executes uprobe:
arch_uprobe_optimize()
get_uprobe_trampoline()
head_tramps is empty, fails to find inherited VMA
create_uprobe_trampoline()
find_nearest_trampoline() finds new unmapped area
installs second duplicate trampoline VMA
In a deep fork chain, each generation inherits all previous VMAs, has an
empty head_tramps list, and creates a new VMA. Can this cause linear
accumulation of redundant VMAs, eventually exhausting vm.max_map_count?
While this patch addresses unmapping failed optimization attempts, it
does not prevent the inherited-but-not-tracked VMA leak scenario in fork
chains.
> @@ -696,6 +699,7 @@ static struct vm_area_struct
> *get_uprobe_trampoline(struct mm_struct *mm, unsign
> if (IS_ERR_VALUE(vaddr))
> return ERR_PTR(vaddr);
>
> + *new_mapping = true;
> return _install_special_mapping(mm, vaddr, PAGE_SIZE,
> VM_READ|VM_EXEC|VM_MAYEXEC|VM_MAYREAD|VM_IO,
> &tramp_mapping);
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/26475828601