From nobody Mon May 25 04:33:49 2026 Received: from mail-qt1-f178.google.com (mail-qt1-f178.google.com [209.85.160.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60BD83A1B5 for ; Mon, 18 May 2026 18:35:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779129306; cv=none; b=it7HAVP99PR94Di7IDgr8PGJeyNtO9Yx/BF9NvDiuHwe3BDP+0AKnG1eeI98jtyDkDGl8apLxuwcyOV1VdZmVW4MDZEa6E5AigxeUQY+QXfTOm5x2FTmnjoH0A7U4m1d9iu14cR+1BNXVMq/VVRosZMlnF7i/vOz0FW69Tg7l90= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779129306; c=relaxed/simple; bh=LuRPaFKS8OgFMkLFrIeH1PJ5pkp7C5RsHRnqAViwGZU=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=hPzDUw0CvI85DTJYU5R/kLcgKBePG+CIp33RcvFex59O4cBx3ufi6FY33R046wEFru/XbJm/qy4X2Ttykke3WG57paXGiCu7p4AptxztMyweMlzyAm3jBzVB/lQaQoUXA2n2DLyYrrKHmp4ydugJLxYIrZ5NYe4ww3/XZUchOI8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mz3q6FHk; arc=none smtp.client-ip=209.85.160.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mz3q6FHk" Received: by mail-qt1-f178.google.com with SMTP id d75a77b69052e-50e5c7eb565so32992161cf.3 for ; Mon, 18 May 2026 11:35:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779129303; x=1779734103; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=HefdEi5yJeys6v2Xvf3SK5unmpenCeIO1ZUw+aAUkeI=; b=mz3q6FHkhV0VIuGdMGfA1fLS36M+wV0pWJfFDSu1VTxkkoatTGh8wcvglwcjK9Qy1j buBZqnbXndE7qkM39RmqfoNAQ4tTIweTXxO6v1PyD0rv8aWuqnFBtztoe6slXZwq0UCo /yX4NfXa05AHCvQy69F2vMyaZn3tsIY8QcJw09uYEWf5gsfET8zmCQbzSaNmIyjmwyS4 Z0XrugnDikHEUaZuBGRisre/WO0qQe6MeYVI5fhLAZ/ty2ILJ4+/yVmc6U/NYVfZebm1 fXbD1jJp6sBMm5xEPzBl1P4rbCcyEsT3Z4GxetTGMGeMp/TNuLzfw2gPr/J2toUv4Ank JG8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779129303; x=1779734103; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=HefdEi5yJeys6v2Xvf3SK5unmpenCeIO1ZUw+aAUkeI=; b=KpWf0Bj64UDOOIPiG8A34kvuMM7p//8Cw0pM/+Wo3XtAAVBubc8w6k5tfAbWwnEOGX bf0xUYcVXAzJ1urfSc9AO6vf0NIuWRDnuSih7iV0Xi/zUgttwS7nyfVGpNH6G4Rr51mV XQtth9z3YOKHSnEZCbFe/XFOX0K0FRzdXPYFr/tkf48wZ0c/ocexbkO4C9P1e7dvR5m/ emcVt2lXtNmvQ0t4wvdYAHxionfDUnCo5JxxfSkD5EUi7kE3uj2tXq/rJLptfA4Q9PCc vbv1ayzxOtHgMsCbqRndyP2/ukf34im00z1s96f7RggkhdVcte68IypM/yWJoRZ1Aux5 1Jow== X-Forwarded-Encrypted: i=1; AFNElJ/mQa81Iv8f4laTn9tkSX2MfwzjxoyKJZDgfXiSHVZiqg0tHA9TyoJAZ6AkHNYbZqFz31h7a+X1JRtHE7g=@vger.kernel.org X-Gm-Message-State: AOJu0YxxWzak4KXkXuGuMJVlp7pIZE44midyX0tMz/Y2tiBXDKR96KOt /3tv0q0lR8vYHKD41P8cDYYI4l8lFJJcc9GR2gpRB3Smbpp79/cnX30I X-Gm-Gg: Acq92OFnspKsK0IfC00lU5VlG0UaJEW1/XWVzLU9u37EfnU3GVefFUzsCMss/b7dNHi QcA00ihE/T31luUIpPyRiwkwnJ9y3hRep0dn/Y25UEWfrlWL1tzM0RMAA9dzcDN+6c+YNTqt10Y JE5GKtM2wKOVN3tcTe6jVkfd5rf5I3zOx2BZHbRDSO5ziC9SUaOJBiI4PrJ89WMvx8B0Rk3eX0n S06AEezkpMB4ECNtKf++YciRFuRvyVgG3WmfCsm8RUNNRWzILIef7p/negCRQIOOtY1bebFN+jV 6FmYrbzY71Rb5bB8AGoEb3t9YvGcjw0afJe4cNlZlU7loBvevnKsIMMnoFXMgNKaPexxosuy9VJ xPKRCV6bmxqWrFKLJKfP8UL7kFlWf/9m9C4B8xRdq+mLwahZmQWiVruZOO2ZicoSUZivSgaHdAz 83fD9OnvuVv9tcHcsWPR4tv9hhE6lLlP5IJxJaRWFL0PDTD/R9LVux8zfgE0uaR/WJ8vsDuTxXp 9WszJMVflObS+yNHCNv X-Received: by 2002:a05:622a:19a2:b0:50d:8080:2a7 with SMTP id d75a77b69052e-5165a0d1052mr213761201cf.21.1779129303092; Mon, 18 May 2026 11:35:03 -0700 (PDT) Received: from server0 (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-5168c968930sm50315401cf.0.2026.05.18.11.35.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 May 2026 11:35:02 -0700 (PDT) From: Michael Bommarito To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: James Chapman , Tom Parkin , Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net] l2tp: use list_del_rcu in l2tp_session_unhash Date: Mon, 18 May 2026 14:34:47 -0400 Message-ID: <20260518183447.64078-1-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" An unprivileged local user can pin a host CPU indefinitely in l2tp_session_get_by_ifname() by issuing L2TP_CMD_SESSION_GET on L2TP_ATTR_IFNAME concurrently with L2TP_CMD_SESSION_CREATE and L2TP_CMD_SESSION_DELETE on the same tunnel. All three commands take GENL_UNS_ADMIN_PERM, so CAP_NET_ADMIN in the netns user namespace suffices; on any host that has l2tp_core loaded the trigger is reachable from a standard `unshare -Urn` sandbox. l2tp_session_unhash() removes a session from tunnel->session_list with list_del_init(), but that list is walked by l2tp_session_get_by_ifname() with list_for_each_entry_rcu() under rcu_read_lock_bh(). list_del_init() leaves the deleted entry's next/prev self-pointing; a reader that has loaded the entry and then advances pos->list.next reads &session->list, container_of()s back to the same session, and list_for_each_entry_rcu() never reaches the list head. The CPU stays in strcmp() inside the walker, with BH and preemption disabled, so RCU grace periods on the host stall behind it and the wedged thread cannot be killed (SIGKILL is delivered on syscall return). Use list_del_rcu() to match the existing list_add_rcu() in l2tp_session_register(); the deleted session remains visible to in-flight walkers with consistent next/prev pointers until kfree_rcu() in l2tp_session_free() releases it. tunnel->session_list has exactly one list_del_init() call site; the list_del_init (&session->clist) at l2tp_core.c:533 operates on the per-collision list, which is not walked under RCU. list_empty(&session->list) is not used anywhere in net/l2tp/ after the unhash point, so dropping the post-delete self-init is safe; the fix has no userspace-visible behavior change. Fixes: 89b768ec2dfef ("l2tp: use rcu list add/del when updating lists") Cc: stable@vger.kernel.org # 6.11+ Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito --- Distro reachability: l2tp_core / l2tp_netlink autoload via the genl family alias net-pf-16-proto-16-family-l2tp on first AF_NETLINK CTRL_CMD_GETFAMILY lookup; this autoload does not require CAP_NET_ADMIN. Verified on Ubuntu 26.04 dev as uid 1000 with no capabilities: `ip l2tp show tunnel` triggers the load. The userns CAP_NET_ADMIN gate is open to a standard unprivileged user on Debian 11/12, Ubuntu 22.04 LTS, Arch, Alpine, and (via snap / podman / firejail with a userns-permitting AppArmor profile) Ubuntu 23.10+ / 24.04+. RHEL 8/9 and Fedora 31+ blacklist l2tp_netlink in /etc/modprobe.d/ by default, so those distros require admin enablement before the surface is reachable; once the module is loaded (e.g. on a host running xl2tpd, NetworkManager-l2tp, or any L2TPv3 VPN endpoint), the gate is open there too. Reproduced on QEMU/x86_64 (KASAN + LOCKDEP + PROVE_RCU + PREEMPT (full), SMP=3D4) and on bare-metal Ubuntu 7.0.0-14-generic with a small create / delete + ifname-get harness. Stock kernel: first rcu_preempt self-detected stall at 27 s, recurring every ~80 s, 8 stalls in a 600 s run; bare metal produced softlockup BUG: CPU stuck for 26 s with RIP at l2tp_session_get_by_ifname+0x90 within 30 s of harness start, and the CPU remained pinned after harness exit. Patched kernel under the same harness for 600 s: 282943 create/delete pairs plus 15381066 getter calls completed with zero anomalies. The kernel ships no tools/testing/selftests/net/l2tp/ binaries and no l2tp KUnit module. Harness source available on request. net/l2tp/l2tp_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 157fc23ce4e14..1455f67e01ddb 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1360,7 +1360,7 @@ static void l2tp_session_unhash(struct l2tp_session *= session) spin_lock_bh(&pn->l2tp_session_idr_lock); /* Remove from the per-tunnel list */ - list_del_init(&session->list); + list_del_rcu(&session->list); /* Remove from per-net IDR */ if (tunnel->version =3D=3D L2TP_HDR_VER_3) { -- 2.46.0