diff options
author | David S. Miller <davem@davemloft.net> | 2017-09-25 17:44:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-09-25 17:44:41 -0400 |
commit | 016576d531c1923f604a0f8410312c39e25b26a1 (patch) | |
tree | bff46ce62caf374bf2bf49e8f8a8110696c2a6d2 | |
parent | 5c346525d3591cb032eca86d0f904cc01f1069ff (diff) | |
parent | b228a94066406b6c456321d69643b0d7ce11cfa6 (diff) |
Merge branch 'l2tp-fix-some-races-in-session-deletion'
Guillaume Nault says:
====================
l2tp: fix some races in session deletion
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/
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/l2tp/l2tp_core.c | 6 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 1 | ||||
-rw-r--r-- | net/l2tp/l2tp_ppp.c | 8 |
3 files changed, 11 insertions, 4 deletions
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 @@ again: | |||
1314 | 1314 | ||
1315 | hlist_del_init(&session->hlist); | 1315 | hlist_del_init(&session->hlist); |
1316 | 1316 | ||
1317 | if (test_and_set_bit(0, &session->dead)) | ||
1318 | goto again; | ||
1319 | |||
1317 | if (session->ref != NULL) | 1320 | if (session->ref != NULL) |
1318 | (*session->ref)(session); | 1321 | (*session->ref)(session); |
1319 | 1322 | ||
@@ -1750,6 +1753,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash); | |||
1750 | */ | 1753 | */ |
1751 | int l2tp_session_delete(struct l2tp_session *session) | 1754 | int l2tp_session_delete(struct l2tp_session *session) |
1752 | { | 1755 | { |
1756 | if (test_and_set_bit(0, &session->dead)) | ||
1757 | return 0; | ||
1758 | |||
1753 | if (session->ref) | 1759 | if (session->ref) |
1754 | (*session->ref)(session); | 1760 | (*session->ref)(session); |
1755 | __l2tp_session_unhash(session); | 1761 | __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 { | |||
76 | struct l2tp_session { | 76 | struct l2tp_session { |
77 | int magic; /* should be | 77 | int magic; /* should be |
78 | * L2TP_SESSION_MAGIC */ | 78 | * L2TP_SESSION_MAGIC */ |
79 | long dead; | ||
79 | 80 | ||
80 | struct l2tp_tunnel *tunnel; /* back pointer to tunnel | 81 | struct l2tp_tunnel *tunnel; /* back pointer to tunnel |
81 | * context */ | 82 | * context */ |
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) | |||
437 | 437 | ||
438 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | 438 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); |
439 | 439 | ||
440 | if (sock) { | 440 | if (sock) |
441 | inet_shutdown(sock, SEND_SHUTDOWN); | 441 | inet_shutdown(sock, SEND_SHUTDOWN); |
442 | /* Don't let the session go away before our socket does */ | 442 | |
443 | l2tp_session_inc_refcount(session); | 443 | /* Don't let the session go away before our socket does */ |
444 | } | 444 | l2tp_session_inc_refcount(session); |
445 | } | 445 | } |
446 | 446 | ||
447 | /* Really kill the session socket. (Called from sock_put() if | 447 | /* Really kill the session socket. (Called from sock_put() if |