diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2017-09-01 11:58:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-09-03 14:04:21 -0400 |
commit | f026bc29a8e093edfbb2a77700454b285c97e8ad (patch) | |
tree | 7dfc0aa94822a5d36f1f63f2e07fa7dae339a6c2 | |
parent | f3c66d4e144a0904ea9b95d23ed9f8eb38c11bfb (diff) |
l2tp: pass tunnel pointer to ->session_create()
Using l2tp_tunnel_find() in pppol2tp_session_create() and
l2tp_eth_create() is racy, because no reference is held on the
returned session. These functions are only used to implement the
->session_create callback which is run by l2tp_nl_cmd_session_create().
Therefore searching for the parent tunnel isn't necessary because
l2tp_nl_cmd_session_create() already has a pointer to it and holds a
reference.
This patch modifies ->session_create()'s prototype to directly pass the
the parent tunnel as parameter, thus avoiding searching for it in
pppol2tp_session_create() and l2tp_eth_create().
Since we have to touch the ->session_create() call in
l2tp_nl_cmd_session_create(), let's also remove the useless conditional:
we know that ->session_create isn't NULL at this point because it's
already been checked earlier in this same function.
Finally, one might be tempted to think that the removed
l2tp_tunnel_find() calls were harmless because they would return the
same tunnel as the one held by l2tp_nl_cmd_session_create() anyway.
But that tunnel might be removed and a new one created with same tunnel
Id before the l2tp_tunnel_find() call. In this case l2tp_tunnel_find()
would return the new tunnel which wouldn't be protected by the
reference held by l2tp_nl_cmd_session_create().
Fixes: 309795f4bec2 ("l2tp: Add netlink control API for L2TP")
Fixes: d9e31d17ceba ("l2tp: Add L2TP ethernet pseudowire support")
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/l2tp/l2tp_core.h | 4 | ||||
-rw-r--r-- | net/l2tp/l2tp_eth.c | 11 | ||||
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 8 | ||||
-rw-r--r-- | net/l2tp/l2tp_ppp.c | 19 |
4 files changed, 17 insertions, 25 deletions
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 4593d48df953..a305e0c5925a 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -201,7 +201,9 @@ struct l2tp_tunnel { | |||
201 | }; | 201 | }; |
202 | 202 | ||
203 | struct l2tp_nl_cmd_ops { | 203 | struct l2tp_nl_cmd_ops { |
204 | int (*session_create)(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); | 204 | int (*session_create)(struct net *net, struct l2tp_tunnel *tunnel, |
205 | u32 session_id, u32 peer_session_id, | ||
206 | struct l2tp_session_cfg *cfg); | ||
205 | int (*session_delete)(struct l2tp_session *session); | 207 | int (*session_delete)(struct l2tp_session *session); |
206 | }; | 208 | }; |
207 | 209 | ||
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 4de2ec94b08c..87da9ef61860 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
@@ -262,24 +262,19 @@ static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel, | |||
262 | dev->needed_headroom += session->hdr_len; | 262 | dev->needed_headroom += session->hdr_len; |
263 | } | 263 | } |
264 | 264 | ||
265 | static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | 265 | static int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel, |
266 | u32 session_id, u32 peer_session_id, | ||
267 | struct l2tp_session_cfg *cfg) | ||
266 | { | 268 | { |
267 | unsigned char name_assign_type; | 269 | unsigned char name_assign_type; |
268 | struct net_device *dev; | 270 | struct net_device *dev; |
269 | char name[IFNAMSIZ]; | 271 | char name[IFNAMSIZ]; |
270 | struct l2tp_tunnel *tunnel; | ||
271 | struct l2tp_session *session; | 272 | struct l2tp_session *session; |
272 | struct l2tp_eth *priv; | 273 | struct l2tp_eth *priv; |
273 | struct l2tp_eth_sess *spriv; | 274 | struct l2tp_eth_sess *spriv; |
274 | int rc; | 275 | int rc; |
275 | struct l2tp_eth_net *pn; | 276 | struct l2tp_eth_net *pn; |
276 | 277 | ||
277 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
278 | if (!tunnel) { | ||
279 | rc = -ENODEV; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | if (cfg->ifname) { | 278 | if (cfg->ifname) { |
284 | strlcpy(name, cfg->ifname, IFNAMSIZ); | 279 | strlcpy(name, cfg->ifname, IFNAMSIZ); |
285 | name_assign_type = NET_NAME_USER; | 280 | name_assign_type = NET_NAME_USER; |
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 57427d430f10..7135f4645d3a 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -643,10 +643,10 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
643 | break; | 643 | break; |
644 | } | 644 | } |
645 | 645 | ||
646 | ret = -EPROTONOSUPPORT; | 646 | ret = l2tp_nl_cmd_ops[cfg.pw_type]->session_create(net, tunnel, |
647 | if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create) | 647 | session_id, |
648 | ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id, | 648 | peer_session_id, |
649 | session_id, peer_session_id, &cfg); | 649 | &cfg); |
650 | 650 | ||
651 | if (ret >= 0) { | 651 | if (ret >= 0) { |
652 | session = l2tp_session_get(net, tunnel, session_id, false); | 652 | session = l2tp_session_get(net, tunnel, session_id, false); |
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index f0edb7209079..50e3ee9a9d61 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
@@ -788,25 +788,20 @@ end: | |||
788 | 788 | ||
789 | #ifdef CONFIG_L2TP_V3 | 789 | #ifdef CONFIG_L2TP_V3 |
790 | 790 | ||
791 | /* Called when creating sessions via the netlink interface. | 791 | /* Called when creating sessions via the netlink interface. */ |
792 | */ | 792 | static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel, |
793 | static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | 793 | u32 session_id, u32 peer_session_id, |
794 | struct l2tp_session_cfg *cfg) | ||
794 | { | 795 | { |
795 | int error; | 796 | int error; |
796 | struct l2tp_tunnel *tunnel; | ||
797 | struct l2tp_session *session; | 797 | struct l2tp_session *session; |
798 | struct pppol2tp_session *ps; | 798 | struct pppol2tp_session *ps; |
799 | 799 | ||
800 | tunnel = l2tp_tunnel_find(net, tunnel_id); | ||
801 | |||
802 | /* Error if we can't find the tunnel */ | ||
803 | error = -ENOENT; | ||
804 | if (tunnel == NULL) | ||
805 | goto out; | ||
806 | |||
807 | /* Error if tunnel socket is not prepped */ | 800 | /* Error if tunnel socket is not prepped */ |
808 | if (tunnel->sock == NULL) | 801 | if (!tunnel->sock) { |
802 | error = -ENOENT; | ||
809 | goto out; | 803 | goto out; |
804 | } | ||
810 | 805 | ||
811 | /* Default MTU values. */ | 806 | /* Default MTU values. */ |
812 | if (cfg->mtu == 0) | 807 | if (cfg->mtu == 0) |