netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net 0/2] l2tp: fix some races in session deletion
@ 2017-09-22 13:39 Guillaume Nault
  2017-09-22 13:39 ` [PATCH net 1/2] l2tp: ensure sessions are freed after their PPPOL2TP socket Guillaume Nault
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Guillaume Nault @ 2017-09-22 13:39 UTC (permalink / raw)
  To: netdev; +Cc: James Chapman, Tom Parkin, Sabrina Dubroca

L2TP provides several interfaces for deleting sessions. Using two of
them concurrently can lead to use-after-free bugs.

Patch #2 uses a flag to prevent double removal of L2TP sessions.
Patch #1 fixes a bug found in the way. Fixing this bug is also
necessary for patch #2 to handle all cases.


This issue is similar to the tunnel deletion bug being worked on by
Sabrina: https://patchwork.ozlabs.org/patch/814173/

Guillaume Nault (2):
  l2tp: ensure sessions are freed after their PPPOL2TP socket
  l2tp: fix race between l2tp_session_delete() and
    l2tp_tunnel_closeall()

 net/l2tp/l2tp_core.c | 6 ++++++
 net/l2tp/l2tp_core.h | 1 +
 net/l2tp/l2tp_ppp.c  | 8 ++++----
 3 files changed, 11 insertions(+), 4 deletions(-)

-- 
2.14.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH net 1/2] l2tp: ensure sessions are freed after their PPPOL2TP socket
  2017-09-22 13:39 [PATCH net 0/2] l2tp: fix some races in session deletion Guillaume Nault
@ 2017-09-22 13:39 ` Guillaume Nault
  2017-09-22 13:39 ` [PATCH net 2/2] l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall() Guillaume Nault
  2017-09-25 21:45 ` [PATCH net 0/2] l2tp: fix some races in session deletion David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Guillaume Nault @ 2017-09-22 13:39 UTC (permalink / raw)
  To: netdev; +Cc: James Chapman, Tom Parkin, Sabrina Dubroca

If l2tp_tunnel_delete() or l2tp_tunnel_closeall() deletes a session
right after pppol2tp_release() orphaned its socket, then the 'sock'
variable of the pppol2tp_session_close() callback is NULL. Yet the
session is still used by pppol2tp_release().

Therefore we need to take an extra reference in any case, to prevent
l2tp_tunnel_delete() or l2tp_tunnel_closeall() from freeing the session.

Since the pppol2tp_session_close() callback is only set if the session
is associated to a PPPOL2TP socket and that both l2tp_tunnel_delete()
and l2tp_tunnel_closeall() hold the PPPOL2TP socket before calling
pppol2tp_session_close(), we're sure that pppol2tp_session_close() and
pppol2tp_session_destruct() are paired and called in the right order.
So the reference taken by the former will be released by the later.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_ppp.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 50e3ee9a9d61..bc6e8bfc5be4 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -437,11 +437,11 @@ static void pppol2tp_session_close(struct l2tp_session *session)
 
 	BUG_ON(session->magic != L2TP_SESSION_MAGIC);
 
-	if (sock) {
+	if (sock)
 		inet_shutdown(sock, SEND_SHUTDOWN);
-		/* Don't let the session go away before our socket does */
-		l2tp_session_inc_refcount(session);
-	}
+
+	/* 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
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH net 2/2] l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
  2017-09-22 13:39 [PATCH net 0/2] l2tp: fix some races in session deletion Guillaume Nault
  2017-09-22 13:39 ` [PATCH net 1/2] l2tp: ensure sessions are freed after their PPPOL2TP socket Guillaume Nault
@ 2017-09-22 13:39 ` Guillaume Nault
  2017-09-25 21:45 ` [PATCH net 0/2] l2tp: fix some races in session deletion David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Guillaume Nault @ 2017-09-22 13:39 UTC (permalink / raw)
  To: netdev; +Cc: James Chapman, Tom Parkin, Sabrina Dubroca

There are several ways to remove L2TP sessions:

  * deleting a session explicitly using the netlink interface (with
    L2TP_CMD_SESSION_DELETE),
  * deleting the session's parent tunnel (either by closing the
    tunnel's file descriptor or using the netlink interface),
  * closing the PPPOL2TP file descriptor of a PPP pseudo-wire.

In some cases, when these methods are used concurrently on the same
session, the session can be removed twice, leading to use-after-free
bugs.

This patch adds a 'dead' flag, used by l2tp_session_delete() and
l2tp_tunnel_closeall() to prevent them from stepping on each other's
toes.

The session deletion path used when closing a PPPOL2TP file descriptor
doesn't need to be adapted. It already has to ensure that a session
remains valid for the lifetime of its PPPOL2TP file descriptor.
So it takes an extra reference on the session in the ->session_close()
callback (pppol2tp_session_close()), which is eventually dropped
in the ->sk_destruct() callback of the PPPOL2TP socket
(pppol2tp_session_destruct()).
Still, __l2tp_session_unhash() and l2tp_session_queue_purge() can be
called twice and even concurrently for a given session, but thanks to
proper locking and re-initialisation of list fields, this is not an
issue.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_core.c | 6 ++++++
 net/l2tp/l2tp_core.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index ee485df73ccd..d8c2a89a76e1 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1314,6 +1314,9 @@ void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
 
 			hlist_del_init(&session->hlist);
 
+			if (test_and_set_bit(0, &session->dead))
+				goto again;
+
 			if (session->ref != NULL)
 				(*session->ref)(session);
 
@@ -1750,6 +1753,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash);
  */
 int l2tp_session_delete(struct l2tp_session *session)
 {
+	if (test_and_set_bit(0, &session->dead))
+		return 0;
+
 	if (session->ref)
 		(*session->ref)(session);
 	__l2tp_session_unhash(session);
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index a305e0c5925a..70a12df40a5f 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -76,6 +76,7 @@ struct l2tp_session_cfg {
 struct l2tp_session {
 	int			magic;		/* should be
 						 * L2TP_SESSION_MAGIC */
+	long			dead;
 
 	struct l2tp_tunnel	*tunnel;	/* back pointer to tunnel
 						 * context */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net 0/2] l2tp: fix some races in session deletion
  2017-09-22 13:39 [PATCH net 0/2] l2tp: fix some races in session deletion Guillaume Nault
  2017-09-22 13:39 ` [PATCH net 1/2] l2tp: ensure sessions are freed after their PPPOL2TP socket Guillaume Nault
  2017-09-22 13:39 ` [PATCH net 2/2] l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall() Guillaume Nault
@ 2017-09-25 21:45 ` David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2017-09-25 21:45 UTC (permalink / raw)
  To: g.nault; +Cc: netdev, jchapman, tparkin, sd

From: Guillaume Nault <g.nault@alphalink.fr>
Date: Fri, 22 Sep 2017 15:39:22 +0200

> L2TP provides several interfaces for deleting sessions. Using two of
> them concurrently can lead to use-after-free bugs.
> 
> Patch #2 uses a flag to prevent double removal of L2TP sessions.
> Patch #1 fixes a bug found in the way. Fixing this bug is also
> necessary for patch #2 to handle all cases.
> 
> This issue is similar to the tunnel deletion bug being worked on by
> Sabrina: https://patchwork.ozlabs.org/patch/814173/

Series applied and queued up for -stable, thanks.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-09-25 21:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-22 13:39 [PATCH net 0/2] l2tp: fix some races in session deletion Guillaume Nault
2017-09-22 13:39 ` [PATCH net 1/2] l2tp: ensure sessions are freed after their PPPOL2TP socket Guillaume Nault
2017-09-22 13:39 ` [PATCH net 2/2] l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall() Guillaume Nault
2017-09-25 21:45 ` [PATCH net 0/2] l2tp: fix some races in session deletion David Miller

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).