mm/mseal: update VMA end correctly on merge
Vulnerability discovered by Antonius / Blue Dragon Security
| Field | Detail |
|---|---|
| CVE ID | CVE-2026-23416 |
| Subsystem | mm/mseal — mm/vma.c |
| Affected | Linux kernel 6.17 through 7.0-rc5 |
| Fixed in | Linux 7.0-rc6, stable backports 6.18.21, 6.19.11 |
| Access required | Unprivileged user (UID 1000, no capabilities) |
| Syscalls used | memfd_create, mmap, mseal |
| Reproducibility | 100% deterministic, < 1 second |
| Reserved | 2026-01-13 |
| Published | 2026-04-02 |
The bug resides in mseal_apply() inside mm/mseal.c. When iterating over VMAs to apply the mseal(2) syscall, the function tracks position using curr_start and curr_end:
/* Simplified pre-fix logic */
curr_end = vma->vm_end;
/* ... process VMA ... */
curr_start = curr_end; /* advance to next VMA */The problem: vma_modify_flags() — called during the iteration — can merge VMAs, changing vma->vm_end in place. This makes the curr_end value that was captured before the merge stale. On the next iteration, curr_start is set to the now-stale curr_end, producing an incorrect starting address.
In debug kernels (CONFIG_DEBUG_VM), this inconsistent vmg state triggers:
VM_WARN_ON_VMG(middle &&
((middle != prev && vmg->start != middle->vm_start) ||
vmg->end > middle->vm_end))
at mm/vma.c:830, producing a kernel WARNING.
In production kernels (WARN compiled to no-op), the stale curr_start proceeds silently — meaning VM_SEALED may be applied to an incorrect address range without any visible error, undermining the security guarantee that mseal(2) is designed to provide.
mseal(2)
└─ do_mseal() [mm/mseal.c]
└─ mseal_apply()
└─ vma_modify_flags() [mm/vma.c]
└─ vma_modify()
└─ vma_merge_existing_range()
└─ VM_WARN_ON_VMG fires at line 830
/* BEFORE fix — mm/mseal.c mseal_apply() */
curr_end = vma->vm_end; // captured here
/* ... vma_modify_flags() may merge VMAs, changing vma->vm_end ... */
curr_start = curr_end; // stale! merge is not reflectedThe fix sets curr_end = vma->vm_end unconditionally on each iteration after any potential merge, and additionally clamps curr_start/curr_end as const values derived from the input range and VMA boundaries:
/* AFTER fix */
curr_end = vma->vm_end; // unconditional, always freshThe PoC constructs the following layout before the second mseal() call:
[0x21da6000 - 0x21de5fff] VMA-A (fd2, MAP_SHARED|MAP_FIXED) ← VM_SEALED after step 1
[0x21de6000 - 0x21e82fff] VMA-B (fd2, MAP_SHARED|MAP_FIXED) ← NOT sealed
[0x21e83000 - 0x21e84fff] VMA-C (leftover)
The second mseal(m2, 0x70000) targets [0x21da6000 – 0x21e15fff], spanning VMA-A (sealed) into VMA-B (not sealed). Inside mseal_apply(), the stale curr_end from VMA-A is used as curr_start when processing VMA-B, creating the inconsistent vmg state.
- Reachable from unprivileged userspace — only requires
memfd_create + mmap + mseal, noCAP_*needed. mseal(2)is a security primitive — it protects VMA immutability. A logic error in its application meansVM_SEALEDmay be silently misapplied when spanning VMAs with mixed seal states.- Silent in production — on non-debug kernels, the inconsistent state proceeds without any warning, potentially leaving the VMA tree with incorrect seal state.
File: cve-2026-23416-poc.c
gcc -o poc cve-2026-23416-poc.c./poc============================================
CVE-2026-23416-POC
Discovered by : Antonius / Blue Dragon Security
https://bluedragonsec.com
https://github.com/bluedragonsecurity
============================================
[iter 0]
[iter 1]
...
[+] WARNING triggered N times total
Check dmesg for:
WARNING: CPU: X PID: Y at mm/vma.c:830 vma_merge_existing_range+0x...
- Linux kernel 6.17 – 7.0-rc5
CONFIG_DEBUG_VM=yto observe theVM_WARN_ON_VMG(on production kernels the bug is still present but silent)- No root or special capabilities required
Three upstream fix commits (applied in 7.0-rc6 and stable backports):
| Commit | Tree |
|---|---|
40b3f4700e55 |
stable |
83737e34b83a |
stable |
2697dd8ae721 |
stable |
Fixed kernel versions: 7.0-rc6, 6.18.21, 6.19.11
- CVE-2026-23416 — cve.org
- CVE-2026-23416 — NVD
- Technical writeup — Medium (@w1sdom)
- Blue Dragon Security
| Date | Event |
|---|---|
| 2026-01-13 | CVE ID reserved |
| 2026-04-02 | CVE published, fix commits merged |
Antonius (@w1sdom)
Blue Dragon Security — Tangerang, Indonesia
GitHub: bluedragonsecurity
This PoC is released for educational and research purposes.