l2tp: pass tunnel pointer to ->session_create()
authorGuillaume Nault <g.nault@alphalink.fr>
Fri, 1 Sep 2017 15:58:51 +0000 (17:58 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 Sep 2017 18:04:21 +0000 (11:04 -0700)
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>
net/l2tp/l2tp_core.h
net/l2tp/l2tp_eth.c
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c

index 4593d48df9530019730707ba3fed4e220775e294..a305e0c5925a2ccb202383642a9f7220282d7489 100644 (file)
@@ -201,7 +201,9 @@ struct l2tp_tunnel {
 };
 
 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);
 };
 
index 4de2ec94b08cbf5aba016da754b799c46d5f378a..87da9ef61860886d9bf5cc668524ef8b48a60c31 100644 (file)
@@ -262,24 +262,19 @@ static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel,
        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;
        struct net_device *dev;
        char name[IFNAMSIZ];
-       struct l2tp_tunnel *tunnel;
        struct l2tp_session *session;
        struct l2tp_eth *priv;
        struct l2tp_eth_sess *spriv;
        int rc;
        struct l2tp_eth_net *pn;
 
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (!tunnel) {
-               rc = -ENODEV;
-               goto out;
-       }
-
        if (cfg->ifname) {
                strlcpy(name, cfg->ifname, IFNAMSIZ);
                name_assign_type = NET_NAME_USER;
index 57427d430f107897322441d7578ce9e97b8017bf..7135f4645d3aa64ae2c37f1c99544de84c650aaa 100644 (file)
@@ -643,10 +643,10 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                break;
        }
 
-       ret = -EPROTONOSUPPORT;
-       if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create)
-               ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
-                       session_id, peer_session_id, &cfg);
+       ret = l2tp_nl_cmd_ops[cfg.pw_type]->session_create(net, tunnel,
+                                                          session_id,
+                                                          peer_session_id,
+                                                          &cfg);
 
        if (ret >= 0) {
                session = l2tp_session_get(net, tunnel, session_id, false);
index f0edb720907946eb5e79f47017133d8a1c60ada7..50e3ee9a9d612e6c033ef761d8dfeb1e6f209541 100644 (file)
@@ -788,25 +788,20 @@ end:
 
 #ifdef CONFIG_L2TP_V3
 
-/* Called when creating sessions via the netlink interface.
- */
-static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+/* Called when creating sessions via the netlink interface. */
+static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
+                                  u32 session_id, u32 peer_session_id,
+                                  struct l2tp_session_cfg *cfg)
 {
        int error;
-       struct l2tp_tunnel *tunnel;
        struct l2tp_session *session;
        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 */
-       if (tunnel->sock == NULL)
+       if (!tunnel->sock) {
+               error = -ENOENT;
                goto out;
+       }
 
        /* Default MTU values. */
        if (cfg->mtu == 0)