stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Giuliano Procida <gprocida@google.com>
To: greg@kroah.com
Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,
	"David S . Miller" <davem@davemloft.net>,
	Giuliano Procida <gprocida@google.com>
Subject: [PATCH v2 22/22] l2tp: initialise PPP sessions before registering them
Date: Fri, 22 May 2020 00:39:37 +0100	[thread overview]
Message-ID: <20200521233937.175182-23-gprocida@google.com> (raw)
In-Reply-To: <20200521233937.175182-1-gprocida@google.com>

From: Guillaume Nault <g.nault@alphalink.fr>

commit f98be6c6359e7e4a61aaefb9964c1db31cb9ec0c upstream.

pppol2tp_connect() initialises L2TP sessions after they've been exposed
to the rest of the system by l2tp_session_register(). This puts
sessions into transient states that are the source of several races, in
particular with session's deletion path.

This patch centralises the initialisation code into
pppol2tp_session_init(), which is called before the registration phase.
The only field that can't be set before session registration is the
pppol2tp socket pointer, which has already been converted to RCU. So
pppol2tp_connect() should now be race-free.

The session's .session_close() callback is now set before registration.
Therefore, it's always called when l2tp_core deletes the session, even
if it was created by pppol2tp_session_create() and hasn't been plugged
to a pppol2tp socket yet. That'd prevent session free because the extra
reference taken by pppol2tp_session_close() wouldn't be dropped by the
socket's ->sk_destruct() callback (pppol2tp_session_destruct()).
We could set .session_close() only while connecting a session to its
pppol2tp socket, or teach pppol2tp_session_close() to avoid grabbing a
reference when the session isn't connected, but that'd require adding
some form of synchronisation to be race free.

Instead of that, we can just let the pppol2tp socket hold a reference
on the session as soon as it starts depending on it (that is, in
pppol2tp_connect()). Then we don't need to utilise
pppol2tp_session_close() to hold a reference at the last moment to
prevent l2tp_core from dropping it.

When releasing the socket, pppol2tp_release() now deletes the session
using the standard l2tp_session_delete() function, instead of merely
removing it from hash tables. l2tp_session_delete() drops the reference
the sessions holds on itself, but also makes sure it doesn't remove a
session twice. So it can safely be called, even if l2tp_core already
tried, or is concurrently trying, to remove the session.
Finally, pppol2tp_session_destruct() drops the reference held by the
socket.

Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 net/l2tp/l2tp_ppp.c | 69 +++++++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 31 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 9eb07c1a993e..979fa868a4f1 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -449,9 +449,6 @@ static void pppol2tp_session_close(struct l2tp_session *session)
 			inet_shutdown(sk->sk_socket, SEND_SHUTDOWN);
 		sock_put(sk);
 	}
-
-	/* Don't let the session go away before our socket does */
-	l2tp_session_inc_refcount(session);
 }
 
 /* Really kill the session socket. (Called from sock_put() if
@@ -507,8 +504,7 @@ static int pppol2tp_release(struct socket *sock)
 	if (session != NULL) {
 		struct pppol2tp_session *ps;
 
-		__l2tp_session_unhash(session);
-		l2tp_session_queue_purge(session);
+		l2tp_session_delete(session);
 
 		ps = l2tp_session_priv(session);
 		mutex_lock(&ps->sk_lock);
@@ -600,6 +596,35 @@ static void pppol2tp_show(struct seq_file *m, void *arg)
 }
 #endif
 
+static void pppol2tp_session_init(struct l2tp_session *session)
+{
+	struct pppol2tp_session *ps;
+	struct dst_entry *dst;
+
+	session->recv_skb = pppol2tp_recv;
+	session->session_close = pppol2tp_session_close;
+#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
+	session->show = pppol2tp_show;
+#endif
+
+	ps = l2tp_session_priv(session);
+	mutex_init(&ps->sk_lock);
+	ps->tunnel_sock = session->tunnel->sock;
+	ps->owner = current->pid;
+
+	/* If PMTU discovery was enabled, use the MTU that was discovered */
+	dst = sk_dst_get(session->tunnel->sock);
+	if (dst) {
+		u32 pmtu = dst_mtu(dst);
+
+		if (pmtu) {
+			session->mtu = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+			session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+		}
+		dst_release(dst);
+	}
+}
+
 /* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
  */
 static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
@@ -611,7 +636,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 	struct l2tp_session *session = NULL;
 	struct l2tp_tunnel *tunnel;
 	struct pppol2tp_session *ps;
-	struct dst_entry *dst;
 	struct l2tp_session_cfg cfg = { 0, };
 	int error = 0;
 	u32 tunnel_id, peer_tunnel_id;
@@ -760,8 +784,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 			goto end;
 		}
 
+		pppol2tp_session_init(session);
 		ps = l2tp_session_priv(session);
-		mutex_init(&ps->sk_lock);
 		l2tp_session_inc_refcount(session);
 
 		mutex_lock(&ps->sk_lock);
@@ -774,26 +798,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 		drop_refcnt = true;
 	}
 
-	ps->owner	     = current->pid;
-	ps->tunnel_sock = tunnel->sock;
-
-	session->recv_skb	= pppol2tp_recv;
-	session->session_close	= pppol2tp_session_close;
-#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
-	session->show		= pppol2tp_show;
-#endif
-
-	/* If PMTU discovery was enabled, use the MTU that was discovered */
-	dst = sk_dst_get(tunnel->sock);
-	if (dst != NULL) {
-		u32 pmtu = dst_mtu(dst);
-
-		if (pmtu != 0)
-			session->mtu = session->mru = pmtu -
-				PPPOL2TP_HEADER_OVERHEAD;
-		dst_release(dst);
-	}
-
 	/* Special case: if source & dest session_id == 0x0000, this
 	 * socket is being created to manage the tunnel. Just set up
 	 * the internal context for use by ioctl() and sockopt()
@@ -827,6 +831,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 	rcu_assign_pointer(ps->sk, sk);
 	mutex_unlock(&ps->sk_lock);
 
+	/* Keep the reference we've grabbed on the session: sk doesn't expect
+	 * the session to disappear. pppol2tp_session_destruct() is responsible
+	 * for dropping it.
+	 */
+	drop_refcnt = false;
+
 	sk->sk_state = PPPOX_CONNECTED;
 	l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
 		  session->name);
@@ -848,7 +858,6 @@ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
 {
 	int error;
 	struct l2tp_session *session;
-	struct pppol2tp_session *ps;
 
 	/* Error if tunnel socket is not prepped */
 	if (!tunnel->sock) {
@@ -871,9 +880,7 @@ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
 		goto err;
 	}
 
-	ps = l2tp_session_priv(session);
-	mutex_init(&ps->sk_lock);
-	ps->tunnel_sock = tunnel->sock;
+	pppol2tp_session_init(session);
 
 	error = l2tp_session_register(session, tunnel);
 	if (error < 0)
-- 
2.27.0.rc0.183.gde8f92d652-goog


  parent reply	other threads:[~2020-05-21 23:40 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-21 14:40 [PATCH 00/22] l2tp locking and ordering fixes Giuliano Procida
2020-05-21 14:40 ` [PATCH 01/22] net: l2tp: export debug flags to UAPI Giuliano Procida
2020-05-21 14:40 ` [PATCH 02/22] net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_* Giuliano Procida
2020-05-21 14:40 ` [PATCH 03/22] net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_* Giuliano Procida
2020-05-21 14:40 ` [PATCH 04/22] New kernel function to get IP overhead on a socket Giuliano Procida
2020-05-21 14:40 ` [PATCH 05/22] L2TP:Adjust intf MTU, add underlay L3, L2 hdrs Giuliano Procida
2020-05-21 14:40 ` [PATCH 06/22] l2tp: remove useless duplicate session detection in l2tp_netlink Giuliano Procida
2020-05-21 14:40 ` [PATCH 07/22] l2tp: remove l2tp_session_find() Giuliano Procida
2020-05-21 14:40 ` [PATCH 08/22] l2tp: define parameters of l2tp_session_get*() as "const" Giuliano Procida
2020-05-21 14:40 ` [PATCH 09/22] l2tp: define parameters of l2tp_tunnel_find*() " Giuliano Procida
2020-05-21 14:40 ` [PATCH 10/22] l2tp: initialise session's refcount before making it reachable Giuliano Procida
2020-05-21 14:40 ` [PATCH 11/22] l2tp: hold tunnel while looking up sessions in l2tp_netlink Giuliano Procida
2020-05-21 14:40 ` [PATCH 12/22] l2tp: hold tunnel while processing genl delete command Giuliano Procida
2020-05-21 14:40 ` [PATCH 13/22] l2tp: hold tunnel while handling genl tunnel updates Giuliano Procida
2020-05-21 14:40 ` [PATCH 14/22] l2tp: hold tunnel while handling genl TUNNEL_GET commands Giuliano Procida
2020-05-21 14:40 ` [PATCH 15/22] l2tp: hold tunnel used while creating sessions with netlink Giuliano Procida
2020-05-21 14:40 ` [PATCH 16/22] l2tp: prevent creation of sessions on terminated tunnels Giuliano Procida
2020-05-21 14:40 ` [PATCH 17/22] l2tp: pass tunnel pointer to ->session_create() Giuliano Procida
2020-05-21 14:40 ` [PATCH 18/22] l2tp: fix l2tp_eth module loading Giuliano Procida
2020-05-21 14:40 ` [PATCH 19/22] l2tp: don't register sessions in l2tp_session_create() Giuliano Procida
2020-05-21 14:40 ` [PATCH 20/22] l2tp: initialise l2tp_eth sessions before registering them Giuliano Procida
2020-05-21 14:40 ` [PATCH 21/22] l2tp: protect sock pointer of struct pppol2tp_session with RCU Giuliano Procida
2020-05-21 14:41 ` [PATCH 22/22] l2tp: initialise PPP sessions before registering them Giuliano Procida
2020-05-21 23:39 ` [PATCH v2 00/22] l2tp locking and ordering fixes Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 01/22] net: l2tp: export debug flags to UAPI Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 02/22] net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_* Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 03/22] net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_* Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 04/22] New kernel function to get IP overhead on a socket Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 05/22] L2TP:Adjust intf MTU, add underlay L3, L2 hdrs Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 06/22] l2tp: remove useless duplicate session detection in l2tp_netlink Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 07/22] l2tp: remove l2tp_session_find() Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 08/22] l2tp: define parameters of l2tp_session_get*() as "const" Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 09/22] l2tp: define parameters of l2tp_tunnel_find*() " Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 10/22] l2tp: initialise session's refcount before making it reachable Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 11/22] l2tp: hold tunnel while looking up sessions in l2tp_netlink Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 12/22] l2tp: hold tunnel while processing genl delete command Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 13/22] l2tp: hold tunnel while handling genl tunnel updates Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 14/22] l2tp: hold tunnel while handling genl TUNNEL_GET commands Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 15/22] l2tp: hold tunnel used while creating sessions with netlink Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 16/22] l2tp: prevent creation of sessions on terminated tunnels Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 17/22] l2tp: pass tunnel pointer to ->session_create() Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 18/22] l2tp: fix l2tp_eth module loading Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 19/22] l2tp: don't register sessions in l2tp_session_create() Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 20/22] l2tp: initialise l2tp_eth sessions before registering them Giuliano Procida
2020-05-21 23:39   ` [PATCH v2 21/22] l2tp: protect sock pointer of struct pppol2tp_session with RCU Giuliano Procida
2020-05-21 23:39   ` Giuliano Procida [this message]
2020-05-22 12:15   ` [PATCH v2 00/22] l2tp locking and ordering fixes Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200521233937.175182-23-gprocida@google.com \
    --to=gprocida@google.com \
    --cc=davem@davemloft.net \
    --cc=g.nault@alphalink.fr \
    --cc=greg@kroah.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).