All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.