Cloudanix VulnDB

CVE-2026-68398

High · 7.8

CVSS

7.8

EPSS

0.2%

Published

Aug 10, 2026

CISA due date

—

Cloudanix analysis

Monitor only SSVC: Track

A flaw in the Linux kernel's handling of certain network connections can let a regular user crash the system or potentially gain higher privileges.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
Low
Impact
Full Compromise
Component
OS kernel
Class
Use After Free
Remediation
Patch
Effort
Low
Patch risk
Low

What it actually does

Use-after-free in the PPP L2TP receive path where pppol2tp_recv calls ppp_input on a struct channel that can be kfree'd by a concurrent close without an RCU grace period when the channel is bound but not attached or bridged.

Why it matters to the business

Local unprivileged users can trigger kernel memory corruption leading to crashes or potential privilege escalation on systems using PPP over L2TP, increasing risk of denial of service or full host compromise.

How an attack unfolds

An attacker opens a PPPoL2TP socket and binds a channel without connecting it, then closes the socket from another thread while a UDP packet triggers pppol2tp_recv under RCU; the channel pointer is dereferenced after the kfree in ppp_release_channel.

How to fix it

Upgrade to a Linux kernel containing the fix that replaces the direct kfree with call_rcu in ppp_release_channel for the unbound channel case; apply the patch that ensures RCU grace period before freeing struct channel.

How to confirm the fix worked

Confirm the kernel source contains the call_rcu change in ppp_release_channel and that teardown paths for bound channels continue to use synchronize_net or synchronize_rcu; test by reproducing the bind-without-connect close race under RCU read lock.

Typical attack path

  1. Create PPPoL2TP data socket and issue PPPIOCGCHAN to bind channel
  2. Trigger concurrent close of socket to invoke ppp_unregister_channel and kfree without synchronize_rcu
  3. Send L2TP UDP packet to invoke l2tp_udp_encap_recv -> pppol2tp_recv -> ppp_input on freed channel

How to detect it

Search kernel logs for use-after-free warnings or oops involving ppp_input, pppol2tp_recv, or struct channel; inspect audit logs for unusual sequences of PPPIOCGCHAN followed immediately by socket close on L2TP devices.

What your security team should do

  • Prioritize kernel updates on any system exposing PPPoL2TP sockets to unprivileged users
  • Monitor for local privilege-escalation attempts via L2TP sockets until patched
  • Restrict unprivileged access to PPP and L2TP interfaces where feasible

The record

In the Linux kernel, the following vulnerability has been resolved: ppp: defer channel free to an RCU grace period to fix pppol2tp RX UAF pppol2tp_recv() runs in the L2TP UDP-encap softirq RX path: l2tp_udp_encap_recv() -> l2tp_recv_common() -> pppol2tp_recv() -> ppp_input(&po->chan) It runs under rcu_read_lock() holding only an l2tp_session reference and takes NO reference on the internal PPP channel (struct channel, chan->ppp) that ppp_input() dereferences. The pppox socket is SOCK_RCU_FREE, so 'po' and the embedded ppp_channel are RCU-safe. But the internal struct channel is a separate allocation that ppp_release_channel() frees with a plain kfree(): close(data socket) -> pppol2tp_release() -> pppox_unbind_sock() -> ppp_unregister_channel() -> ppp_release_channel() -> kfree(pch) For a channel that is bound (PPPIOCGCHAN) but not attached to a ppp unit (no PPPIOCCONNECT, pch->ppp == NULL) and not bridged, teardown skips both ppp_disconnect_channel()'s synchronize_net() and ppp_unbridge_channels()'s synchronize_rcu(), so the kfree() has no grace period. rcu_read_lock() in pppol2tp_recv() does not protect against a plain kfree(), so an in-flight ppp_input() on one CPU can dereference the channel just freed by close() on another CPU. The bug is reachable by an unprivileged user. Defer the channel free to an RCU callback via call_rcu() so the grace period fences any in-flight ppp_input(). The disconnect and unbridge teardown paths already fence with synchronize_net()/synchronize_rcu(); call_rcu() does the same here without stalling the close() path.

Affected packages

Ecosystem Package Introduced Fixed