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 21/27] l2tp: prevent creation of sessions on terminated tunnels
Date: Fri, 22 May 2020 00:57:34 +0100	[thread overview]
Message-ID: <20200521235740.191338-22-gprocida@google.com> (raw)
In-Reply-To: <20200521235740.191338-1-gprocida@google.com>

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

commit f3c66d4e144a0904ea9b95d23ed9f8eb38c11bfb upstream.

l2tp_tunnel_destruct() sets tunnel->sock to NULL, then removes the
tunnel from the pernet list and finally closes all its sessions.
Therefore, it's possible to add a session to a tunnel that is still
reachable, but for which tunnel->sock has already been reset. This can
make l2tp_session_create() dereference a NULL pointer when calling
sock_hold(tunnel->sock).

This patch adds the .acpt_newsess field to struct l2tp_tunnel, which is
used by l2tp_tunnel_closeall() to prevent addition of new sessions to
tunnels. Resetting tunnel->sock is done after l2tp_tunnel_closeall()
returned, so that l2tp_session_add_to_tunnel() can safely take a
reference on it when .acpt_newsess is true.

The .acpt_newsess field is modified in l2tp_tunnel_closeall(), rather
than in l2tp_tunnel_destruct(), so that it benefits all tunnel removal
mechanisms. E.g. on UDP tunnels, a session could be added to a tunnel
after l2tp_udp_encap_destroy() proceeded. This would prevent the tunnel
from being removed because of the references held by this new session
on the tunnel and its socket. Even though the session could be removed
manually later on, this defeats the purpose of
commit 9980d001cec8 ("l2tp: add udp encap socket destroy handler").

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_core.c | 41 ++++++++++++++++++++++++++++-------------
 net/l2tp/l2tp_core.h |  4 ++++
 2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index e5210cf8cb59..ba11e72a2365 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -328,13 +328,21 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
 	struct hlist_head *g_head;
 	struct hlist_head *head;
 	struct l2tp_net *pn;
+	int err;
 
 	head = l2tp_session_id_hash(tunnel, session->session_id);
 
 	write_lock_bh(&tunnel->hlist_lock);
+	if (!tunnel->acpt_newsess) {
+		err = -ENODEV;
+		goto err_tlock;
+	}
+
 	hlist_for_each_entry(session_walk, head, hlist)
-		if (session_walk->session_id == session->session_id)
-			goto exist;
+		if (session_walk->session_id == session->session_id) {
+			err = -EEXIST;
+			goto err_tlock;
+		}
 
 	if (tunnel->version == L2TP_HDR_VER_3) {
 		pn = l2tp_pernet(tunnel->l2tp_net);
@@ -342,12 +350,21 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
 						session->session_id);
 
 		spin_lock_bh(&pn->l2tp_session_hlist_lock);
+
 		hlist_for_each_entry(session_walk, g_head, global_hlist)
-			if (session_walk->session_id == session->session_id)
-				goto exist_glob;
+			if (session_walk->session_id == session->session_id) {
+				err = -EEXIST;
+				goto err_tlock_pnlock;
+			}
 
+		l2tp_tunnel_inc_refcount(tunnel);
+		sock_hold(tunnel->sock);
 		hlist_add_head_rcu(&session->global_hlist, g_head);
+
 		spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+	} else {
+		l2tp_tunnel_inc_refcount(tunnel);
+		sock_hold(tunnel->sock);
 	}
 
 	hlist_add_head(&session->hlist, head);
@@ -355,12 +372,12 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
 
 	return 0;
 
-exist_glob:
+err_tlock_pnlock:
 	spin_unlock_bh(&pn->l2tp_session_hlist_lock);
-exist:
+err_tlock:
 	write_unlock_bh(&tunnel->hlist_lock);
 
-	return -EEXIST;
+	return err;
 }
 
 /* Lookup a tunnel by id
@@ -1251,7 +1268,6 @@ static void l2tp_tunnel_destruct(struct sock *sk)
 	/* Remove hooks into tunnel socket */
 	sk->sk_destruct = tunnel->old_sk_destruct;
 	sk->sk_user_data = NULL;
-	tunnel->sock = NULL;
 
 	/* Remove the tunnel struct from the tunnel list */
 	pn = l2tp_pernet(tunnel->l2tp_net);
@@ -1261,6 +1277,8 @@ static void l2tp_tunnel_destruct(struct sock *sk)
 	atomic_dec(&l2tp_tunnel_count);
 
 	l2tp_tunnel_closeall(tunnel);
+
+	tunnel->sock = NULL;
 	l2tp_tunnel_dec_refcount(tunnel);
 
 	/* Call the original destructor */
@@ -1285,6 +1303,7 @@ void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
 		  tunnel->name);
 
 	write_lock_bh(&tunnel->hlist_lock);
+	tunnel->acpt_newsess = false;
 	for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
 again:
 		hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
@@ -1588,6 +1607,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
 	tunnel->magic = L2TP_TUNNEL_MAGIC;
 	sprintf(&tunnel->name[0], "tunl %u", tunnel_id);
 	rwlock_init(&tunnel->hlist_lock);
+	tunnel->acpt_newsess = true;
 
 	/* The net we belong to */
 	tunnel->l2tp_net = net;
@@ -1838,11 +1858,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
 			return ERR_PTR(err);
 		}
 
-		l2tp_tunnel_inc_refcount(tunnel);
-
-		/* Ensure tunnel socket isn't deleted */
-		sock_hold(tunnel->sock);
-
 		/* Ignore management session in session count value */
 		if (session->session_id != 0)
 			atomic_inc(&l2tp_session_count);
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 0d4590b25592..8a5d51cff2f3 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -165,6 +165,10 @@ struct l2tp_tunnel {
 
 	struct rcu_head rcu;
 	rwlock_t		hlist_lock;	/* protect session_hlist */
+	bool			acpt_newsess;	/* Indicates whether this
+						 * tunnel accepts new sessions.
+						 * Protected by hlist_lock.
+						 */
 	struct hlist_head	session_hlist[L2TP_HASH_SIZE];
 						/* hashed list of sessions,
 						 * hashed by id */
-- 
2.27.0.rc0.183.gde8f92d652-goog


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

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-21 23:57 [PATCH 00/27] more l2tp locking and ordering fixes Giuliano Procida
2020-05-21 23:57 ` [PATCH 01/27] l2tp: lock socket before checking flags in connect() Giuliano Procida
2020-05-21 23:57 ` [PATCH 02/27] l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind() Giuliano Procida
2020-05-21 23:57 ` [PATCH 03/27] l2tp: hold session while sending creation notifications Giuliano Procida
2020-05-21 23:57 ` [PATCH 04/27] l2tp: take a reference on sessions used in genetlink handlers Giuliano Procida
2020-05-21 23:57 ` [PATCH 05/27] l2tp: don't use l2tp_tunnel_find() in l2tp_ip and l2tp_ip6 Giuliano Procida
2020-05-21 23:57 ` [PATCH 06/27] net: l2tp: export debug flags to UAPI Giuliano Procida
2020-05-21 23:57 ` [PATCH 07/27] net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_* Giuliano Procida
2020-05-26 16:17   ` Asbjørn Sloth Tønnesen
2020-05-21 23:57 ` [PATCH 08/27] net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_* Giuliano Procida
2020-05-21 23:57 ` [PATCH 09/27] New kernel function to get IP overhead on a socket Giuliano Procida
2020-05-21 23:57 ` [PATCH 10/27] L2TP:Adjust intf MTU, add underlay L3, L2 hdrs Giuliano Procida
2020-05-21 23:57 ` [PATCH 11/27] l2tp: remove useless duplicate session detection in l2tp_netlink Giuliano Procida
2020-05-21 23:57 ` [PATCH 12/27] l2tp: remove l2tp_session_find() Giuliano Procida
2020-05-21 23:57 ` [PATCH 13/27] l2tp: define parameters of l2tp_session_get*() as "const" Giuliano Procida
2020-05-21 23:57 ` [PATCH 14/27] l2tp: define parameters of l2tp_tunnel_find*() " Giuliano Procida
2020-05-21 23:57 ` [PATCH 15/27] l2tp: initialise session's refcount before making it reachable Giuliano Procida
2020-05-21 23:57 ` [PATCH 16/27] l2tp: hold tunnel while looking up sessions in l2tp_netlink Giuliano Procida
2020-05-21 23:57 ` [PATCH 17/27] l2tp: hold tunnel while processing genl delete command Giuliano Procida
2020-05-21 23:57 ` [PATCH 18/27] l2tp: hold tunnel while handling genl tunnel updates Giuliano Procida
2020-05-21 23:57 ` [PATCH 19/27] l2tp: hold tunnel while handling genl TUNNEL_GET commands Giuliano Procida
2020-05-21 23:57 ` [PATCH 20/27] l2tp: hold tunnel used while creating sessions with netlink Giuliano Procida
2020-05-21 23:57 ` Giuliano Procida [this message]
2020-05-21 23:57 ` [PATCH 22/27] l2tp: pass tunnel pointer to ->session_create() Giuliano Procida
2020-05-21 23:57 ` [PATCH 23/27] l2tp: fix l2tp_eth module loading Giuliano Procida
2020-05-21 23:57 ` [PATCH 24/27] l2tp: don't register sessions in l2tp_session_create() Giuliano Procida
2020-05-21 23:57 ` [PATCH 25/27] l2tp: initialise l2tp_eth sessions before registering them Giuliano Procida
2020-05-21 23:57 ` [PATCH 26/27] l2tp: protect sock pointer of struct pppol2tp_session with RCU Giuliano Procida
2020-05-21 23:57 ` [PATCH 27/27] l2tp: initialise PPP sessions before registering them Giuliano Procida
2020-05-26 10:54 ` [PATCH 00/27] more 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=20200521235740.191338-22-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).