Can confirm this happens on my machine with the 147 kernel also. I let
Claude have a look at it, and this are it's findings:

Also reproducible on 6.8.0-147.147 (noble) -- the bad hunk is still present, so
this is not fixed by the -147 update.

System: Dell Latitude 5530, BIOS 1.29.1, Ubuntu 24.04.
VPN: NetworkManager-l2tp (kl2tpd / go-l2tp) + strongSwan, i.e. L2TP over IPsec.
Last known good: 6.8.0-142.142. I have not tested -146 myself; I went straight
from -142 to -147.

Reproducer: activate an L2TP/IPsec connection. The machine hard-freezes within
30-120 seconds of ppp0 coming up (no panic written to disk, no shutdown
sequence in the journal, power cycle required). Happened on 2/2 attempts on
-147; reverting to -142 makes it go away completely.


WHAT THE JOURNAL SHOWS

The first warning fires in the same second ppp0 is created, from the L2TP UDP
RX softirq path:

    ------------[ cut here ]------------
    refcount_t: addition on 0; use-after-free.
    WARNING: CPU: 0 PID: 2872 at lib/refcount.c:25 
refcount_warn_saturate+0x12e/0x150
    CPU: 0 PID: 2872 Comm: kworker/0:5 Not tainted 6.8.0-147-generic #147-Ubuntu
    Hardware name: Dell Inc. Latitude 5530/0RN5CP, BIOS 1.29.1 04/10/2025
    Workqueue: events xfrm_trans_reinject
    RIP: 0010:refcount_warn_saturate+0x12e/0x150
    Call Trace:
     <TASK>
     l2tp_tunnel_get_session+0xc8/0xd0 [l2tp_core]
     l2tp_udp_recv_core+0xb1/0x350 [l2tp_core]
     ? __pfx_l2tp_udp_encap_recv+0x10/0x10 [l2tp_core]
     l2tp_udp_encap_recv+0x2c/0x54 [l2tp_core]
     udp_queue_rcv_one_skb+0x278/0x550
     udp_queue_rcv_skb+0x4f/0x80
     udp_unicast_rcv_skb+0x7a/0xa0
     __udp4_lib_rcv+0x627/0x6f0
     udp_rcv+0x25/0x40
     ip_protocol_deliver_rcu+0xd8/0x210
     ip_local_deliver_finish+0x77/0xa0
     ip_local_deliver+0x6e/0x120
     ? __pfx_ip_local_deliver_finish+0x10/0x10
     xfrm4_rcv_encap_finish2+0x3c/0x60
     xfrm_trans_reinject+0xe2/0x170
     process_one_work+0x181/0x3a0
     worker_thread+0x18b/0x330
     kthread+0xef/0x120
     ret_from_fork+0x44/0x70
     ret_from_fork_asm+0x1b/0x30
     </TASK>
    ---[ end trace 0000000000000000 ]---

Immediately followed by "refcount_t: underflow; use-after-free" in
l2tp_session_dec_refcount+0xbb/0xd0 [l2tp_core] and "refcount_t: saturated;
leaking memory" in l2tp_tunnel_get_session+0xbc/0xd0 [l2tp_core], all from the
same RX path.

Two seconds later the TX side starts tripping over the same freed object, and
from then on it warns on *every* packet:

    WARNING: CPU: 3 PID: 1094 at net/l2tp/l2tp_ppp.c:166 
pppol2tp_xmit+0x1e1/0x220 [l2tp_ppp]
    CPU: 3 PID: 1094 Comm: systemd-resolve Tainted: G        W   
6.8.0-147-generic #147-Ubuntu
    Call Trace:
     <TASK>
     ppp_push+0xaf/0x110
     ppp_send_frame+0x1e8/0x530
     __ppp_xmit_process+0x88/0x100
     ppp_xmit_process+0x3d/0xb0
     ppp_start_xmit+0x159/0x200
     dev_hard_start_xmit+0x62/0x1e0
     __dev_queue_xmit+0x709/0x910
     neigh_direct_output+0x13/0x20
     ip_finish_output2+0x196/0x480
     ...

That is the WARN_ON(session->magic != L2TP_SESSION_MAGIC) inside the inlined
pppol2tp_sock_to_session(). I counted 704 of these in ~2 minutes (24 in the
first minute, 90, then 241 in the third). Each one dumps the full module list
and a stack trace, which is what ultimately wedges the box.


ANALYSIS

I compared the shipped modules from -142 and -147:

  * l2tp_core.ko is byte-identical between the two (objdump -d output diffs
    clean apart from the filename), so l2tp_core itself did not change.
  * l2tp_ppp.ko changed in exactly two functions: pppol2tp_connect (+7 bytes,
    one added store, from the ppp RCU-free backport) and pppol2tp_ioctl
    (+126 bytes).

The pppol2tp_ioctl change is the -146 backport of

    l2tp: pppol2tp: hold reference to session in pppol2tp_ioctl()
    (upstream stable patchset 2026-08-21, LP: #2164796 // CVE-2026-53262)

and I believe it has been applied incorrectly for this tree. Disassembly of
pppol2tp_ioctl in 6.8.0-147:

    1a78:  mov    0x18(%r8),%rbx              ; rbx = sock->sk
    1aa6:  lock xadd %eax,0x80(%rbx)          ; sock_hold(sk)  -> ref on the 
SOCKET
    1ac1:  mov    0x278(%rbx),%r13            ; session = sk->sk_user_data
    1ad1:  cmpl   $0xc04eb7d,0x0(%r13)        ; session->magic == 
L2TP_SESSION_MAGIC
    ...
    1b0c:  call   l2tp_session_dec_refcount   ; -> ref dropped on the SESSION

It takes the reference on the socket (6.8's pppol2tp_sock_to_session() still
does sock_hold(sk)) but releases it on the session. Counting relocations in
the two builds:

                      l2tp_tunnel_get_session   l2tp_session_dec_refcount
    6.8.0-142                 1                           2
    6.8.0-147                 1                           3

In -142 both dec_refcount calls pair with the single l2tp_tunnel_get_session()
in the PPPIOCGL2TPSTATS peer-session path. In -147 there are three, and the two
extra ones are on the generic exit paths, where nothing ever took a session
reference. The matching sock_put(sk) only happens on the !session / bad-magic
error paths, so on every *successful* ioctl the socket refcount is leaked and
the session refcount is decremented once too often.

The ioctl handler in -147 accepts 0x40047452, 0x40047459, 0x80047453,
0x8004745a and 0x80487436, i.e. PPPIOCSMRU, PPPIOCSFLAGS, PPPIOCGMRU,
PPPIOCGFLAGS and PPPIOCGL2TPSTATS. pppd issues PPPIOCSMRU and PPPIOCSFLAGS on
the PPPoL2TP session socket during link setup, so session->ref_count is driven
to zero within a second of the tunnel coming up. The session is freed while
still linked into the tunnel, l2tp_tunnel_get_session() then hits "addition on
0" on the next inbound packet, and pppol2tp_xmit()'s magic check fails forever
after -- exactly the sequence above.

Suggested fix: on 6.8, where pppol2tp_sock_to_session() returns with a
sock_hold() on sk, those exit paths need sock_put(sk) rather than
l2tp_session_dec_refcount(session). The upstream commit applies to a tree
where the lookup helper hands back a session-refcounted pointer, which is why
it does not transplant as-is.

(Caveat: this is binary-level analysis of the shipped modules, I have not
built a test kernel to confirm it.)

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2169477

Title:
  [regression] 6.8.0-146: l2tp/pppol2tp use-after-free -> kernel panic /
  soft lockup (L2TP/IPsec, xl2tpd)

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2169477/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to