
Research repository for CVE-2026-68121, a Linux kernel PPPoE use-after-free in pppoe_sendmsg() enabling local privilege escalation, with PoC, root-cause analysis, and lab setup.
PPPoEject
A Linux kernel memory-corruption vulnerability in the PPPoE transmit path,
caused by a stale pointer to an sk_buff header after a device header callback
reallocates the skb head.
This repository is intended for authorized security research, kernel vulnerability analysis, CTF environments, and defensive testing only.
Do not execute proof-of-concept code against systems without explicit authorization.
The CVE record identifies the vulnerability as a stale PPPoE header pointer that
can become invalid when dev_hard_header() reallocates the skb head.
The vulnerability exists in:
drivers/net/ppp/pppoe.c
within:
pppoe_sendmsg()
The vulnerable sequence is conceptually:
pppoe_sendmsg()
│
▼
Save PPPoE header pointer
│
▼
dev_hard_header()
│
▼
skb head may be reallocated
│
▼
Old pointer becomes stale
│
▼
PPPoE writes through stale pointer
│
▼
Use-After-Free
│
▼
Kernel memory corruption
Linux networking code allows device header callbacks to reallocate the
sk_buff head. A pointer into the old head therefore cannot safely be reused
after dev_hard_header() returns.
The core issue is a lifetime violation.
pppoe_sendmsg() obtains a pointer to the PPPoE header before invoking:
dev_hard_header()
However, that callback can cause the skb head to move.
Conceptually:
Before callback:
skb
┌──────────────────────────────┐
│ Ethernet │ PPPoE │ Payload │
└──────────┴───────┴───────────┘
▲
│
stale pointer
After skb expansion:
old skb head ──X──► freed
new skb head
┌────────────────────────────────────┐
│ Ethernet │ PPPoE │ Payload │
└──────────┴───────┴─────────────────┘
▲
│
valid location
The old pointer still references the freed allocation.
When PPPoE subsequently writes the header through that pointer, the kernel performs a use-after-free write.
The documented trigger involves a race around copy_from_user() and changes
to a team device's header operations.
One described sequence is:
PPPoE sendmsg()
│
▼
copy_from_user() blocks
│
│
├───────────────┐
│ │
▼ ▼
Team device changes First non-Ethernet
header operations port is added
│
▼
Delegated GRE callback
│
▼
skb head expansion
│ │
└───────────────┘
│
▼
stale PPPoE pointer
│
▼
use-after-free write
The CVE record notes that this can occur when the first non-Ethernet port is added to an empty team device and the delegated GRE header callback expands the skb head.
The vulnerability can result in:
The CVE's published CVSS vector is:
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
with a base score of 7.8 High.
The relevant components are:
PF_PPPOX / PPPoE socket
│
▼
pppoe_sendmsg()
│
▼
sk_buff (skb)
│
▼
dev_hard_header()
│
▼
Network device header callback
│
▼
Potential skb head expansion
│
▼
PPPoE stale header pointer
│
▼
UAF write
The vulnerable code is therefore not simply a generic PPPoE packet parser; the critical condition is the interaction between PPPoE socket transmission and dynamic skb head reallocation.
The upstream fix is titled:
pppoe: reload header pointer after dev_hard_header()
The fix reloads the PPPoE header through the skb's network-header offset after device header creation.
The important property is:
Before:
header pointer
│
▼
dev_hard_header()
│
▼
skb moves
│
▼
pointer = stale ❌
After:
dev_hard_header()
│
▼
skb may move
│
▼
reload header using skb offset
│
▼
pointer = valid ✅
pskb_expand_head() updates the relevant skb offset when the skb head is
relocated, making the offset-based lookup safe after reallocation.
A controlled laboratory can be structured as:
┌───────────────────────────────────────────────┐
│ Linux VM │
│ │
│ ┌───────────────┐ │
│ │ PPPoE Socket │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ pppoe_sendmsg │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Team │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ GRE │ │
│ └───────────────┘ │
│ │
└───────────────────────────────────────────────┘
Useful kernel debugging tools:
gdb
pwndbg
gef
crash
objdump
readelf
pahole
Monitor kernel messages:
sudo dmesg -w
Inspect PPPoE support:
lsmod | grep pppoe
Check available PPP modules:
find /lib/modules/$(uname -r) -iname '*pppoe*'
Check the currently running kernel:
uname -r
Check PPPoE-related configuration:
grep -E 'CONFIG_PPP|CONFIG_PPPOE' \
/boot/config-$(uname -r)
Typical relevant options include:
CONFIG_PPP
CONFIG_PPP_ASYNC
CONFIG_PPP_SYNC_TTY
CONFIG_PPPOE
For controlled kernel research:
01. Build vulnerable kernel
↓
02. Boot isolated VM
↓
03. Enable PPPoE support
↓
04. Create controlled networking topology
↓
05. Configure team/GRE interaction
↓
06. Exercise PPPoE sendmsg()
↓
07. Monitor skb lifetime
↓
08. Capture kernel diagnostics
↓
09. Apply upstream patch
↓
10. Repeat and compare
The objective is to reproduce the memory-lifetime violation safely and compare vulnerable and patched behavior.
CVE-2026-68121-PPPoEject/
│
├── README.md
│
├── exploit/
│ ├── poc.c
│ └── Makefile
│
├── analysis/
│ ├── root-cause.md
│ ├── pppoe-sendmsg.md
│ ├── skb-lifetime.md
│ └── patch-analysis.md
│
├── kernel/
│ ├── vulnerable/
│ └── patched/
│
├── lab/
│ ├── setup.sh
│ ├── cleanup.sh
│ └── topology.md
│
├── screenshots/
│
├── docs/
│ └── research-notes.md
│
└── LICENSE
The recommended mitigation is to update to a Linux kernel containing the upstream fix or an appropriate distribution backport.
For Debian/Kali:
sudo apt update
sudo apt full-upgrade
Then reboot:
sudo reboot
Verify the running kernel:
uname -r
Distribution backports can use different version numbers, so administrators should verify their installed package against the distribution's security advisory. Debian currently lists fixed versions including 6.1.187-1 for Bookworm and 6.12.101-1 for Trixie.
The Linux stable trees contain the fix across multiple maintained branches. The CVE record lists the corresponding stable commits and identifies the affected source file as:
drivers/net/ppp/pppoe.c
The vulnerable history begins with the Linux kernel PPPoE implementation and
the fixed commit series terminates at the upstream fix represented by
7a56e7c9b08e08fd55a1bcada24cf4fe3782b722 in the CVE data.
A pointer into an skb cannot be assumed valid after a callback capable of reallocating the skb head.
Networking callbacks may change underlying memory layout.
The patch demonstrates why an skb-relative offset is safer than retaining a raw pointer across a potentially relocating operation.
The vulnerable state depends on concurrent activity around packet transmission and network-device configuration.
A stale pointer in kernel networking code can become a memory corruption primitive with confidentiality, integrity, and availability consequences.
drivers/net/ppp/pppoe.cpppoe_sendmsg()pppoe: reload header pointer after dev_hard_header()Linux Kernel · PPPoE · Use-After-Free · Kernel Security · LPE
Research • Analyze • Reproduce • Harden
| Field | Details |
|---|
| CVE | CVE-2026-68121 |
| Codename | PPPoEject |
| Component | Linux Kernel |
| Subsystem | PPPoE / Networking |
| Affected File | drivers/net/ppp/pppoe.c |
| Primary Function | pppoe_sendmsg() |
| Bug Class | Use-After-Free |
| Impact | Kernel memory corruption |
| Potential Impact | Local Privilege Escalation |
| CVSS v3.1 | 7.8 — High |
| Attack Vector | Local |
| Attack Complexity | Low |
| Privileges Required | Low |
| User Interaction | None |
| Status | Patched |
| Security Property | Vulnerable | Patched |
|---|
| Header pointer saved before callback | ✅ | — |
| skb head can move | ✅ | ✅ |
| Pointer refreshed after callback | ❌ | ✅ |
| Stale pointer dereference | Possible | Prevented |
| Use-after-free write | Possible | Mitigated |
| Kernel memory corruption | Possible | Mitigated |