VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45837

CVE-2026-45837

Description

In the Linux kernel, the following vulnerability has been resolved:

bpf: Fix use-after-free in arena_vm_close on fork

arena_vm_open() only bumps vml->mmap_count but never registers the child VMA in arena->vma_list. The vml->vma always points at the parent VMA, so after parent munmap the pointer dangles. If the child then calls bpf_arena_free_pages(), zap_pages() reads the stale vml->vma triggering use-after-free.

Fix this by preventing the arena VMA from being inherited across fork with VM_DONTCOPY, and preventing VMA splits via the may_split callback.

Also reject mremap with a .mremap callback returning -EINVAL. A same-size mremap(MREMAP_FIXED) on the full arena VMA reaches copy_vma() through the following path:

check_prep_vma() - returns 0 early: new_len == old_len skips VM_DONTEXPAND check prep_move_vma() - vm_start == old_addr and vm_end == old_addr + old_len so may_split is never called move_vma() copy_vma_and_data() copy_vma() vm_area_dup() - copies vm_private_data (vml pointer) vm_ops->open() - bumps vml->mmap_count vm_ops->mremap() - returns -EINVAL, rollback unmaps new VMA

The refcount ensures the rollback's arena_vm_close does not free the vml shared with the original VMA.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A use-after-free in the Linux kernel's BPF arena VMA handling occurs when a forked child accesses the parent's freed VMA pointer.

Vulnerability

A use-after-free vulnerability exists in the Linux kernel's BPF arena virtual memory area (VMA) handling, specifically in arena_vm_close during fork. The bug arises because arena_vm_open() increments vml->mmap_count but does not register the child VMA in arena->vma_list. The vml->vma pointer always points to the parent VMA; after the parent calls munmap, this pointer becomes dangling. If a child process then invokes bpf_arena_free_pages(), zap_pages() dereferences the stale vml->vma, leading to a use-after-free. The vulnerability affects stable kernel versions prior to the fix commit 723b9fa930cc.

Exploitation

An attacker must first create a BPF arena and then fork a child process. The parent must subsequently unmap (munmap) its arena VMA, leaving the child with a dangling vml->vma pointer. No special privileges beyond the ability to create BPF arenas and fork are required; the attack sequence relies on normal process operations. The child then triggers the use-after-free by calling bpf_arena_free_pages(), which reads the freed VMA.

Impact

Successful exploitation results in a use-after-free condition that can lead to arbitrary read or write of kernel memory, potentially escalating to privilege escalation (arbitrary code execution). The attacker gains control over freed kernel memory, with the ability to corrupt kernel structures, likely achieving full system compromise.

Mitigation

The fix is applied in Linux kernel commits [1], [2]; patched versions include kernels containing commit 723b9fa930cc277c15ce6b9ec9feec828cfac9d7. The fix prevents VMA inheritance across fork by setting VM_DONTCOPY and blocking VMA splits via the may_split callback. Additionally, mremap is rejected with an -EINVAL return. Users must update to a patched kernel version; no workaround is available for unpatched kernels.

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

8
201128fcc7b2

bpf: Fix use-after-free in arena_vm_close on fork

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitAlexei StarovoitovApr 13, 2026Fixed in 7.0.7via kernel-cna
1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index f355cf1c1a1693..9c68c9b0b24adf 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -341,6 +341,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -417,6 +427,8 @@ out_unlock_sigsegv:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -486,10 +498,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
723b9fa930cc

bpf: Fix use-after-free in arena_vm_close on fork

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitAlexei StarovoitovApr 13, 2026Fixed in 6.12.88via kernel-cna
1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index 8c775a1401d3ed..4ce6786d393514 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -236,6 +236,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -299,6 +309,8 @@ out:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -368,10 +380,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
d18099f19e53

bpf: Fix use-after-free in arena_vm_close on fork

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitAlexei StarovoitovApr 13, 2026Fixed in 6.18.30via kernel-cna
1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index 1074ac4459f2ca..c67525847687f9 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -246,6 +246,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -307,6 +317,8 @@ out:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -376,10 +388,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
4fddde2a732d

bpf: Fix use-after-free in arena_vm_close on fork

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitAlexei StarovoitovApr 13, 2026Fixed in 7.1-rc1via kernel-cna
1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index f355cf1c1a1693..9c68c9b0b24adf 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -341,6 +341,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -417,6 +427,8 @@ out_unlock_sigsegv:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -486,10 +498,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
d18099f19e53

bpf: Fix use-after-free in arena_vm_close on fork

1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index 1074ac4459f2ca..c67525847687f9 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -246,6 +246,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -307,6 +317,8 @@ out:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -376,10 +388,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
201128fcc7b2

bpf: Fix use-after-free in arena_vm_close on fork

1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index f355cf1c1a1693..9c68c9b0b24adf 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -341,6 +341,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -417,6 +427,8 @@ out_unlock_sigsegv:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -486,10 +498,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
4fddde2a732d

bpf: Fix use-after-free in arena_vm_close on fork

1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index f355cf1c1a1693..9c68c9b0b24adf 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -341,6 +341,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -417,6 +427,8 @@ out_unlock_sigsegv:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -486,10 +498,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    
723b9fa930cc

bpf: Fix use-after-free in arena_vm_close on fork

1 file changed · +16 4
  • kernel/bpf/arena.c+16 4 modified
    diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
    index 8c775a1401d3ed..4ce6786d393514 100644
    --- a/kernel/bpf/arena.c
    +++ b/kernel/bpf/arena.c
    @@ -236,6 +236,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
     	refcount_inc(&vml->mmap_count);
     }
     
    +static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
    +{
    +	return -EINVAL;
    +}
    +
    +static int arena_vm_mremap(struct vm_area_struct *vma)
    +{
    +	return -EINVAL;
    +}
    +
     static void arena_vm_close(struct vm_area_struct *vma)
     {
     	struct bpf_map *map = vma->vm_file->private_data;
    @@ -299,6 +309,8 @@ out:
     
     static const struct vm_operations_struct arena_vm_ops = {
     	.open		= arena_vm_open,
    +	.may_split	= arena_vm_may_split,
    +	.mremap		= arena_vm_mremap,
     	.close		= arena_vm_close,
     	.fault          = arena_vm_fault,
     };
    @@ -368,10 +380,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
     	arena->user_vm_end = vma->vm_end;
     	/*
     	 * bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
    -	 * clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
    -	 * potential change of user_vm_start.
    +	 * clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
    +	 * of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
    +	 * being copied into the child process on fork.
     	 */
    -	vm_flags_set(vma, VM_DONTEXPAND);
    +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
     	vma->vm_ops = &arena_vm_ops;
     	return 0;
     }
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing VMA inheritance control on fork allows a child process to hold a stale pointer to a parent's freed VMA."

Attack vector

An attacker with the ability to `mmap` a BPF arena and then `fork()` can trigger a use-after-free. After fork, the child process inherits the arena VMA, but `arena_vm_open()` only bumps the refcount without registering the child VMA in `arena->vma_list` — `vml->vma` still points to the parent's VMA. If the parent then `munmap`s its arena VMA, the pointer in the child becomes stale. When the child subsequently calls `bpf_arena_free_pages()`, `zap_pages()` reads the dangling `vml->vma`, causing a use-after-free [patch_id=2654239]. Additionally, a same-size `mremap(MREMAP_FIXED)` on the full arena VMA can bypass `VM_DONTEXPAND` and `may_split` checks, reaching `copy_vma()` which duplicates the `vml` pointer and bumps the refcount; the subsequent `mremap` callback returns `-EINVAL`, but the refcount-based rollback prevents freeing the shared `vml` [patch_id=2654239].

Affected code

The vulnerability is in `kernel/bpf/arena.c` in the `arena_vm_open`, `arena_vm_close`, and `arena_map_mmap` functions. The `arena_vm_open()` bumps `vml->mmap_count` but never registers a child VMA in `arena->vma_list`, and `vml->vma` always points at the parent VMA [patch_id=2654239].

What the fix does

The patch applies three changes in `kernel/bpf/arena.c`. First, `VM_DONTCOPY` is added to the VMA flags in `arena_map_mmap()` so the arena VMA is not inherited by child processes after `fork()`, eliminating the dangling-pointer scenario. Second, a new `arena_vm_may_split` callback returns `-EINVAL`, preventing VMA splits that could lead to inconsistent state. Third, a new `arena_vm_mremap` callback returns `-EINVAL`, rejecting `mremap` operations that could otherwise bypass existing protections via `copy_vma()` duplicating the `vml` pointer [patch_id=2654239].

Preconditions

  • inputThe attacker must be able to mmap a BPF arena and then fork a child process.
  • inputThe parent process must munmap its arena VMA while the child still holds a reference.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.