Commit f026bc29 authored by Guillaume Nault's avatar Guillaume Nault Committed by David S. Miller

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: 309795f4 ("l2tp: Add netlink control API for L2TP")
Fixes: d9e31d17 ("l2tp: Add L2TP ethernet pseudowire support")
Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f3c66d4e
...@@ -201,7 +201,9 @@ struct l2tp_tunnel { ...@@ -201,7 +201,9 @@ struct l2tp_tunnel {
}; };
struct l2tp_nl_cmd_ops { struct l2tp_nl_cmd_ops {
int (*session_create)(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); int (*session_create)(struct net *net, struct l2tp_tunnel *tunnel,
u32 session_id, u32 peer_session_id,
struct l2tp_session_cfg *cfg);
int (*session_delete)(struct l2tp_session *session); int (*session_delete)(struct l2tp_session *session);
}; };
......
...@@ -262,24 +262,19 @@ static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel, ...@@ -262,24 +262,19 @@ static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel,
dev->needed_headroom += session->hdr_len; dev->needed_headroom += session->hdr_len;
} }
static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) static int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel,
u32 session_id, u32 peer_session_id,
struct l2tp_session_cfg *cfg)
{ {
unsigned char name_assign_type; unsigned char name_assign_type;
struct net_device *dev; struct net_device *dev;
char name[IFNAMSIZ]; char name[IFNAMSIZ];
struct l2tp_tunnel *tunnel;
struct l2tp_session *session; struct l2tp_session *session;
struct l2tp_eth *priv; struct l2tp_eth *priv;
struct l2tp_eth_sess *spriv; struct l2tp_eth_sess *spriv;
int rc; int rc;
struct l2tp_eth_net *pn; struct l2tp_eth_net *pn;
tunnel = l2tp_tunnel_find(net, tunnel_id);
if (!tunnel) {
rc = -ENODEV;
goto out;
}
if (cfg->ifname) { if (cfg->ifname) {
strlcpy(name, cfg->ifname, IFNAMSIZ); strlcpy(name, cfg->ifname, IFNAMSIZ);
name_assign_type = NET_NAME_USER; name_assign_type = NET_NAME_USER;
......
...@@ -643,10 +643,10 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf ...@@ -643,10 +643,10 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
break; break;
} }
ret = -EPROTONOSUPPORT; ret = l2tp_nl_cmd_ops[cfg.pw_type]->session_create(net, tunnel,
if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create) session_id,
ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id, peer_session_id,
session_id, peer_session_id, &cfg); &cfg);
if (ret >= 0) { if (ret >= 0) {
session = l2tp_session_get(net, tunnel, session_id, false); session = l2tp_session_get(net, tunnel, session_id, false);
......
...@@ -788,25 +788,20 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -788,25 +788,20 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
#ifdef CONFIG_L2TP_V3 #ifdef CONFIG_L2TP_V3
/* Called when creating sessions via the netlink interface. /* Called when creating sessions via the netlink interface. */
*/ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) u32 session_id, u32 peer_session_id,
struct l2tp_session_cfg *cfg)
{ {
int error; int error;
struct l2tp_tunnel *tunnel;
struct l2tp_session *session; struct l2tp_session *session;
struct pppol2tp_session *ps; struct pppol2tp_session *ps;
tunnel = l2tp_tunnel_find(net, tunnel_id);
/* Error if we can't find the tunnel */
error = -ENOENT;
if (tunnel == NULL)
goto out;
/* Error if tunnel socket is not prepped */ /* Error if tunnel socket is not prepped */
if (tunnel->sock == NULL) if (!tunnel->sock) {
error = -ENOENT;
goto out; goto out;
}
/* Default MTU values. */ /* Default MTU values. */
if (cfg->mtu == 0) if (cfg->mtu == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment