Commit a75facf4bb3e for kernel

commit a75facf4bb3e866103ddca4f47a6f3ca4b090d8b
Author: Hengyu Liang <hengyul@cs.unc.edu>
Date:   Thu Oct 29 23:26:17 2026 -0400

    l2tp: only return sessions of the given tunnel in l2tp_session_get()

    Commit 5f77c18ea556 ("l2tp: use IDR for all session lookups") made
    pppol2tp_connect() and the netlink session commands find sessions with
    l2tp_session_get(), passing the socket of the tunnel they name.

    L2TPv3 session IDs are unique per network namespace, except that
    sessions carried over UDP are only unique per UDP socket, the socket of
    their tunnel. However, l2tp_v3_session_get() only checks the socket when
    another session has the same session ID. Otherwise it returns the
    session, whichever tunnel it belongs to. As of now, a session command
    that names the wrong tunnel acts on a session of another tunnel, and a
    PPPoL2TP socket for a second L2TPv3 tunnel fails with EEXIST, because it
    finds session 0 of the first tunnel.

    The issue can be reproduced with:

        ip l2tp add tunnel tunnel_id 3 peer_tunnel_id 3 encap udp \
            local 127.0.0.1 remote 127.0.0.1 udp_sport 5003 udp_dport 6003
        ip l2tp add tunnel tunnel_id 4 peer_tunnel_id 4 encap udp \
            local 127.0.0.1 remote 127.0.0.1 udp_sport 5004 udp_dport 6004
        ip l2tp add session tunnel_id 3 session_id 7 peer_session_id 7
        ip l2tp del session tunnel_id 4 session_id 7
        ip l2tp show session

    Before that commit, the delete fails with "No such device", and session
    7 of tunnel 3 is still listed. After that commit, the delete succeeds,
    and session 7 of tunnel 3 is gone.

    This patch will make l2tp_session_get() return NULL when the L2TPv3
    session it finds does not belong to the given socket. The receive path
    calls l2tp_v3_session_get() directly and is not changed.

    Fixes: 5f77c18ea556 ("l2tp: use IDR for all session lookups")
    Cc: stable@vger.kernel.org
    Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
    Acked-by: Guillaume Nault <gnault@redhat.com>
    Link: https://patch.msgid.link/20261030032617.4065353-1-hengyul@cs.unc.edu
    Signed-off-by: Paolo Abeni <pabeni@redhat.com>

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 7e042a3e648c..0cd3e38bf662 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -315,10 +315,19 @@ EXPORT_SYMBOL_GPL(l2tp_v2_session_get);
 struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, int pver,
 				      u32 tunnel_id, u32 session_id)
 {
+	struct l2tp_session *session;
+
 	if (pver == L2TP_HDR_VER_2)
 		return l2tp_v2_session_get(net, tunnel_id, session_id);
-	else
-		return l2tp_v3_session_get(net, sk, session_id);
+
+	/* l2tp_v3_session_get() doesn't check sk if the ID hasn't collided */
+	session = l2tp_v3_session_get(net, sk, session_id);
+	if (session && session->tunnel->sock != sk) {
+		l2tp_session_put(session);
+		return NULL;
+	}
+
+	return session;
 }
 EXPORT_SYMBOL_GPL(l2tp_session_get);