
CVE-2026-68398 Ubuntu PPPoL2TP use-after-free local privilege escalation

This repository contains a build-specific local privilege-escalation exploit
for CVE-2026-68398, a use-after-free race between PPPoL2TP receive
processing and destruction of an unattached PPP channel. It was validated in
QEMU against the official Ubuntu 22.04 package
linux-image-5.15.0-187-generic (5.15.0-187.197).
The final test starts as a dedicated UID 1001 user with no supplementary
groups, no capabilities and no sudo access, then obtains initial-namespace
UID 0. KASLR, SMEP, SMAP and AppArmor remain enabled. The guest is not booted
with nokaslr, nopti, nosmep or nosmap.
Warning
This code intentionally corrupts kernel heap state and is tied to one exact Ubuntu kernel build. A failed race can panic or corrupt the system. Run it only in an isolated, disposable VM that you own.
pppol2tp_recv() executes in the L2TP UDP receive path under an RCU read-side
critical section and eventually calls ppp_input(&po->chan). The PPPoX socket
and its embedded ppp_channel are RCU-safe, but the internal struct channel
used by ppp_input() is a separate allocation.
For a channel bound with PPPIOCGCHAN but neither attached to a PPP unit nor
bridged, the close path freed that internal object immediately:
RX: l2tp_udp_encap_recv -> pppol2tp_recv -> ppp_input(channel)
CLOSE: pppol2tp_release -> pppox_unbind_sock
-> ppp_unregister_channel -> ppp_release_channel -> kfree(channel)
The receive path can consequently operate on the freed channel's skb queue and
waitqueue. The fix adds an RCU callback to struct channel and defers the queue
purge and free until an RCU grace period has elapsed.
The vulnerability was discovered and fixed upstream by
Norbert Szetei of Doyensec.
The mainline fix is
ec4215683e47424c9c4762fd3c60f552a3119142.
The Linux CNA record identifies the vulnerable lineage as beginning with Linux 4.15. Vendor kernels may carry the fix under a different version number, so the exact source or package changelog takes precedence over this table.
Older supported vendor lines require a backport. As of 2026-08-12, the
Ubuntu CVE tracker
marks Jammy's linux package as needs-triage; no corrected Ubuntu Jammy
package was identified. The tested 5.15.0-187.197 source still calls
kfree(pch) directly and is vulnerable.
The kernel was not recompiled. The minimal cloud image lacked
linux-modules-extra-5.15.0-187-generic, so that official Ubuntu package was
installed to provide l2tp_ppp. A normal Jammy installation using the
linux-generic metapackage already depends on the matching modules-extra
package. The protocol module autoloads when the exploit creates its PPPoL2TP
socket.
The automatic KASLR detector uses an x86 prefetch timing side channel and
requires RDTSCP with KPTI inactive. The tested host CPU exposes rdtscp,
smep and smap and is not affected by Meltdown, so Ubuntu leaves KPTI
inactive without any boot override. On a CPU where /proc/cpuinfo reports the
pti flag, the detector refuses to run. That is an exploit-specific hardware
condition: the underlying CVE remains reachable, but this release does not
claim a KASLR bypass on a KPTI-active system. A manually supplied slide exists
only for controlled diagnostics.
struct channel. The still-running RX
path treats controlled key bytes as its skb queue and waitqueue.core_pattern as disclosure
scratch and exposes a key-allocation pointer.override_creds() with the forged cred.
UID/GID fields, capabilities and the required user, namespace, ucount and
group pointers match the exact Ubuntu build./proc/self/exe to a
unique file in /tmp, changes it to root-owned mode 4755 and verifies those
attributes./usr/bin/id.The last bridge is necessary because override_creds() changes subjective
credentials for the active kernel task; installing and executing the verified
SUID copy turns that short-lived primitive into normal process credentials.
The Makefile statically links the exploit. The timing-sensitive prefetch object
is deliberately compiled at -O0; the exploit itself uses -O2.
make
Equivalent commands:
gcc -O0 -Wall -Wextra -Werror -c -o build/kaslr_prefetch.o kaslr_prefetch.c
gcc -O2 -static -pthread -Wall -Wextra -Werror \
-o build/CVE-2026-68398 exploit.c build/kaslr_prefetch.o
From the ordinary user account on the exact validated kernel:
id
grep '^Cap' /proc/self/status
./CVE-2026-68398 auto 60
The source checks uname() and refuses any release other than
5.15.0-187-generic. The race is probabilistic; reboot a disposable snapshot
before retrying after a miss or crash.
A successful run ends with:
[KASLR] image_base=0xffffffffb9200000 slide=0x38200000
CVE-2026-68398 Ubuntu local privilege-escalation exploit
uid=1001 euid=1001 slide=0x38200000
...
[9/9] invoking override_creds and installing the SUID transition...
override callback: uid=0 euid=0 gid=0 egid=0
installed root-owned mode 4755 helper: /tmp/.cve-2026-68398-root-948
SUID helper ready; executing it from the original unprivileged task...
SUID transition: uid=0 euid=0 gid=0 egid=0
uid=0(root) gid=0(root) groups=0(root),1001(poc)
The complete concise transcript from that real QEMU run is in
docs/example-output.txt.
The chain completed on three fresh, normally randomized Ubuntu boots. The
automatically recovered image bases were 0xffffffff90800000,
0xffffffffa5a00000 and 0xffffffffb9200000. The final run used the dedicated
non-administrative UID 1001 account described above, and verified that the
temporary SUID file was removed afterward.
The same final race was also run for 60 seconds on the exact upstream fix
commit with KASAN enabled and the same four-vCPU topology. It completed 5,969
channel/key cycles, reported stage 1: no controlled reclaim, and produced no
KASAN report or exploit stage transition.
Checked on 2026-08-12 before this private repository was created. SearchSploit/Exploit-DB returned no exploit; Packet Storm returned no matching file; GitHub exact-code search returned 22 CVE/advisory mirrors and no PoC; and exact web searches found only the upstream fix and metadata. This is a point-in-time result, not a guarantee that another PoC will not appear later.
kaslr_prefetch.cThe exploit was written by A. Ramos <[email protected]> (Twitter:
@aramosf). Vulnerability discovery and the
upstream fix are credited to Norbert Szetei (Doyensec).
exploit.c is GPL-2.0-only. kaslr_prefetch.c and kaslr_prefetch.h are MIT
licensed and retain the KASLD attribution and full permission notice in the
source files.
| Kernel line | First fixed release | Fix commit |
|---|
| 6.6.y | 6.6.148 | 4bb84e964ff0 |
| 6.12.y | 6.12.101 | 3ab32218d718 |
| 6.18.y | 6.18.42 | c9574b8a8ede |
| 7.1.y | 7.1.6 | 06213c85d8c0 |
| Mainline | 7.2-rc4 | ec4215683e47 |
| Property | Value |
|---|
| Distribution | Ubuntu 22.04.5 LTS (Jammy) |
| Kernel package | linux-image-5.15.0-187-generic / 5.15.0-187.197 |
| Kernel release | 5.15.0-187-generic #197-Ubuntu |
| Architecture | x86-64 |
| VM | QEMU/KVM, -cpu host, four vCPUs, 5 GiB RAM |
| Initial identity | uid=1001(poc) gid=1001(poc) groups=1001(poc) |
| Initial capabilities | inheritable, permitted, effective and ambient all zero |
| Final identity | uid=0(root) gid=0(root) in the initial namespaces |
| Boot changes | None; stock command line, KASLR enabled |
| Requirement | Ubuntu 5.15.0-187 state | Exploit use |
|---|
| PPP | CONFIG_PPP=y | Built in |
| L2TP / PPPoL2TP | CONFIG_L2TP=m, CONFIG_PPPOL2TP=m | Official linux-modules-extra module |
| User keys | CONFIG_KEYS=y | Reclaims the freed kmalloc-256 channel |
| AppArmor | CONFIG_SECURITY_APPARMOR=y | Remains active; the fake cred includes a valid unconfined label |
| KASLR | CONFIG_RANDOMIZE_BASE=y | Remains active; slide is recovered at runtime |
| SMAP | CONFIG_X86_SMAP=y | Remains active |
| User/network namespaces | Enabled by Ubuntu, but not used | No namespace setup or capability gain is required |
/dev/ppp | Not required | The channel is bound but never connected to a PPP unit |