aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2017-04-03 06:03:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-03 11:36:35 -0400
commitb7902607693fb63b3c31af97e93465128e635269 (patch)
treed6f6f8e45c704fe1d5a329a54173dacd89c2668f /net/l2tp
parent1f49c8cd2c9a53ea04bd86bce01247415d12aa26 (diff)
l2tp: take reference on sessions being dumped
[ Upstream commit e08293a4ccbcc993ded0fdc46f1e57926b833d63 ] Take a reference on the sessions returned by l2tp_session_find_nth() (and rename it l2tp_session_get_nth() to reflect this change), so that caller is assured that the session isn't going to disappear while processing it. For procfs and debugfs handlers, the session is held in the .start() callback and dropped in .show(). Given that pppol2tp_seq_session_show() dereferences the associated PPPoL2TP socket and that l2tp_dfs_seq_session_show() might call pppol2tp_show(), we also need to call the session's .ref() callback to prevent the socket from going away from under us. Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Fixes: 0ad6614048cf ("l2tp: Add debugfs files for dumping l2tp debug info") Fixes: 309795f4bec2 ("l2tp: Add netlink control API for L2TP") Signed-off-by: Guillaume Nault <g.nault@alphalink.fr> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c8
-rw-r--r--net/l2tp/l2tp_core.h3
-rw-r--r--net/l2tp/l2tp_debugfs.c10
-rw-r--r--net/l2tp/l2tp_netlink.c7
-rw-r--r--net/l2tp/l2tp_ppp.c10
5 files changed, 27 insertions, 11 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index a2ed3bda4ddc..e702cb95b89b 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -278,7 +278,8 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn
278} 278}
279EXPORT_SYMBOL_GPL(l2tp_session_find); 279EXPORT_SYMBOL_GPL(l2tp_session_find);
280 280
281struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) 281struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
282 bool do_ref)
282{ 283{
283 int hash; 284 int hash;
284 struct l2tp_session *session; 285 struct l2tp_session *session;
@@ -288,6 +289,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
288 for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 289 for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
289 hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { 290 hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) {
290 if (++count > nth) { 291 if (++count > nth) {
292 l2tp_session_inc_refcount(session);
293 if (do_ref && session->ref)
294 session->ref(session);
291 read_unlock_bh(&tunnel->hlist_lock); 295 read_unlock_bh(&tunnel->hlist_lock);
292 return session; 296 return session;
293 } 297 }
@@ -298,7 +302,7 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
298 302
299 return NULL; 303 return NULL;
300} 304}
301EXPORT_SYMBOL_GPL(l2tp_session_find_nth); 305EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
302 306
303/* Lookup a session by interface name. 307/* Lookup a session by interface name.
304 * This is very inefficient but is only used by management interfaces. 308 * This is very inefficient but is only used by management interfaces.
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 181e755c2fc4..e7233bad65e0 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -243,7 +243,8 @@ out:
243struct l2tp_session *l2tp_session_find(struct net *net, 243struct l2tp_session *l2tp_session_find(struct net *net,
244 struct l2tp_tunnel *tunnel, 244 struct l2tp_tunnel *tunnel,
245 u32 session_id); 245 u32 session_id);
246struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); 246struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
247 bool do_ref);
247struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); 248struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname);
248struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); 249struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
249struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); 250struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
index 2d6760a2ae34..d100aed3d06f 100644
--- a/net/l2tp/l2tp_debugfs.c
+++ b/net/l2tp/l2tp_debugfs.c
@@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
53 53
54static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) 54static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
55{ 55{
56 pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); 56 pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true);
57 pd->session_idx++; 57 pd->session_idx++;
58 58
59 if (pd->session == NULL) { 59 if (pd->session == NULL) {
@@ -238,10 +238,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v)
238 } 238 }
239 239
240 /* Show the tunnel or session context */ 240 /* Show the tunnel or session context */
241 if (pd->session == NULL) 241 if (!pd->session) {
242 l2tp_dfs_seq_tunnel_show(m, pd->tunnel); 242 l2tp_dfs_seq_tunnel_show(m, pd->tunnel);
243 else 243 } else {
244 l2tp_dfs_seq_session_show(m, pd->session); 244 l2tp_dfs_seq_session_show(m, pd->session);
245 if (pd->session->deref)
246 pd->session->deref(pd->session);
247 l2tp_session_dec_refcount(pd->session);
248 }
245 249
246out: 250out:
247 return 0; 251 return 0;
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index bf3117771822..9f66272b163b 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -844,7 +844,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
844 goto out; 844 goto out;
845 } 845 }
846 846
847 session = l2tp_session_find_nth(tunnel, si); 847 session = l2tp_session_get_nth(tunnel, si, false);
848 if (session == NULL) { 848 if (session == NULL) {
849 ti++; 849 ti++;
850 tunnel = NULL; 850 tunnel = NULL;
@@ -854,8 +854,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
854 854
855 if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, 855 if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,
856 cb->nlh->nlmsg_seq, NLM_F_MULTI, 856 cb->nlh->nlmsg_seq, NLM_F_MULTI,
857 session, L2TP_CMD_SESSION_GET) < 0) 857 session, L2TP_CMD_SESSION_GET) < 0) {
858 l2tp_session_dec_refcount(session);
858 break; 859 break;
860 }
861 l2tp_session_dec_refcount(session);
859 862
860 si++; 863 si++;
861 } 864 }
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 51c190dc2582..4db33174fe89 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1555,7 +1555,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
1555 1555
1556static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) 1556static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
1557{ 1557{
1558 pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); 1558 pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true);
1559 pd->session_idx++; 1559 pd->session_idx++;
1560 1560
1561 if (pd->session == NULL) { 1561 if (pd->session == NULL) {
@@ -1682,10 +1682,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v)
1682 1682
1683 /* Show the tunnel or session context. 1683 /* Show the tunnel or session context.
1684 */ 1684 */
1685 if (pd->session == NULL) 1685 if (!pd->session) {
1686 pppol2tp_seq_tunnel_show(m, pd->tunnel); 1686 pppol2tp_seq_tunnel_show(m, pd->tunnel);
1687 else 1687 } else {
1688 pppol2tp_seq_session_show(m, pd->session); 1688 pppol2tp_seq_session_show(m, pd->session);
1689 if (pd->session->deref)
1690 pd->session->deref(pd->session);
1691 l2tp_session_dec_refcount(pd->session);
1692 }
1689 1693
1690out: 1694out:
1691 return 0; 1695 return 0;