]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 May 2020 12:14:44 +0000 (14:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 May 2020 12:14:44 +0000 (14:14 +0200)
added patches:
l2tp-adjust-intf-mtu-add-underlay-l3-l2-hdrs.patch
l2tp-define-parameters-of-l2tp_session_get-as-const.patch
l2tp-define-parameters-of-l2tp_tunnel_find-as-const.patch
l2tp-don-t-register-sessions-in-l2tp_session_create.patch
l2tp-fix-l2tp_eth-module-loading.patch
l2tp-hold-tunnel-used-while-creating-sessions-with-netlink.patch
l2tp-hold-tunnel-while-handling-genl-tunnel-updates.patch
l2tp-hold-tunnel-while-handling-genl-tunnel_get-commands.patch
l2tp-hold-tunnel-while-looking-up-sessions-in-l2tp_netlink.patch
l2tp-hold-tunnel-while-processing-genl-delete-command.patch
l2tp-initialise-l2tp_eth-sessions-before-registering-them.patch
l2tp-initialise-ppp-sessions-before-registering-them.patch
l2tp-initialise-session-s-refcount-before-making-it-reachable.patch
l2tp-pass-tunnel-pointer-to-session_create.patch
l2tp-prevent-creation-of-sessions-on-terminated-tunnels.patch
l2tp-protect-sock-pointer-of-struct-pppol2tp_session-with-rcu.patch
l2tp-remove-l2tp_session_find.patch
l2tp-remove-useless-duplicate-session-detection-in-l2tp_netlink.patch
net-l2tp-deprecate-pppol2tp_msg_-in-favour-of-l2tp_msg_.patch
net-l2tp-export-debug-flags-to-uapi.patch
net-l2tp-ppp-change-pppol2tp_msg_-l2tp_msg_.patch
new-kernel-function-to-get-ip-overhead-on-a-socket.patch

23 files changed:
queue-4.9/l2tp-adjust-intf-mtu-add-underlay-l3-l2-hdrs.patch [new file with mode: 0644]
queue-4.9/l2tp-define-parameters-of-l2tp_session_get-as-const.patch [new file with mode: 0644]
queue-4.9/l2tp-define-parameters-of-l2tp_tunnel_find-as-const.patch [new file with mode: 0644]
queue-4.9/l2tp-don-t-register-sessions-in-l2tp_session_create.patch [new file with mode: 0644]
queue-4.9/l2tp-fix-l2tp_eth-module-loading.patch [new file with mode: 0644]
queue-4.9/l2tp-hold-tunnel-used-while-creating-sessions-with-netlink.patch [new file with mode: 0644]
queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel-updates.patch [new file with mode: 0644]
queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel_get-commands.patch [new file with mode: 0644]
queue-4.9/l2tp-hold-tunnel-while-looking-up-sessions-in-l2tp_netlink.patch [new file with mode: 0644]
queue-4.9/l2tp-hold-tunnel-while-processing-genl-delete-command.patch [new file with mode: 0644]
queue-4.9/l2tp-initialise-l2tp_eth-sessions-before-registering-them.patch [new file with mode: 0644]
queue-4.9/l2tp-initialise-ppp-sessions-before-registering-them.patch [new file with mode: 0644]
queue-4.9/l2tp-initialise-session-s-refcount-before-making-it-reachable.patch [new file with mode: 0644]
queue-4.9/l2tp-pass-tunnel-pointer-to-session_create.patch [new file with mode: 0644]
queue-4.9/l2tp-prevent-creation-of-sessions-on-terminated-tunnels.patch [new file with mode: 0644]
queue-4.9/l2tp-protect-sock-pointer-of-struct-pppol2tp_session-with-rcu.patch [new file with mode: 0644]
queue-4.9/l2tp-remove-l2tp_session_find.patch [new file with mode: 0644]
queue-4.9/l2tp-remove-useless-duplicate-session-detection-in-l2tp_netlink.patch [new file with mode: 0644]
queue-4.9/net-l2tp-deprecate-pppol2tp_msg_-in-favour-of-l2tp_msg_.patch [new file with mode: 0644]
queue-4.9/net-l2tp-export-debug-flags-to-uapi.patch [new file with mode: 0644]
queue-4.9/net-l2tp-ppp-change-pppol2tp_msg_-l2tp_msg_.patch [new file with mode: 0644]
queue-4.9/new-kernel-function-to-get-ip-overhead-on-a-socket.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/l2tp-adjust-intf-mtu-add-underlay-l3-l2-hdrs.patch b/queue-4.9/l2tp-adjust-intf-mtu-add-underlay-l3-l2-hdrs.patch
new file mode 100644 (file)
index 0000000..f6a8751
--- /dev/null
@@ -0,0 +1,113 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:20 +0100
+Subject: L2TP:Adjust intf MTU, add underlay L3, L2 hdrs.
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, "R. Parameswaran" <parameswaran.r7@gmail.com>,  "R . Parameswaran" <rparames@brocade.com>, "David S . Miller" <davem@davemloft.net>,  Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-6-gprocida@google.com>
+
+From: "R. Parameswaran" <parameswaran.r7@gmail.com>
+
+commit b784e7ebfce8cfb16c6f95e14e8532d0768ab7ff upstream.
+
+Existing L2TP kernel code does not derive the optimal MTU for Ethernet
+pseudowires and instead leaves this to a userspace L2TP daemon or
+operator. If an MTU is not specified, the existing kernel code chooses
+an MTU that does not take account of all tunnel header overheads, which
+can lead to unwanted IP fragmentation. When L2TP is used without a
+control plane (userspace daemon), we would prefer that the kernel does a
+better job of choosing a default pseudowire MTU, taking account of all
+tunnel header overheads, including IP header options, if any. This patch
+addresses this.
+
+Change-set here uses the new kernel function, kernel_sock_ip_overhead(),
+to factor the outer IP overhead on the L2TP tunnel socket (including
+IP Options, if any) when calculating the default MTU for an Ethernet
+pseudowire, along with consideration of the inner Ethernet header.
+
+Signed-off-by: R. Parameswaran <rparames@brocade.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_eth.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 51 insertions(+), 4 deletions(-)
+
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -30,6 +30,9 @@
+ #include <net/xfrm.h>
+ #include <net/net_namespace.h>
+ #include <net/netns/generic.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/udp.h>
+ #include "l2tp_core.h"
+@@ -206,6 +209,53 @@ static void l2tp_eth_show(struct seq_fil
+ }
+ #endif
++static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel,
++                              struct l2tp_session *session,
++                              struct net_device *dev)
++{
++      unsigned int overhead = 0;
++      struct dst_entry *dst;
++      u32 l3_overhead = 0;
++
++      /* if the encap is UDP, account for UDP header size */
++      if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
++              overhead += sizeof(struct udphdr);
++              dev->needed_headroom += sizeof(struct udphdr);
++      }
++      if (session->mtu != 0) {
++              dev->mtu = session->mtu;
++              dev->needed_headroom += session->hdr_len;
++              return;
++      }
++      l3_overhead = kernel_sock_ip_overhead(tunnel->sock);
++      if (l3_overhead == 0) {
++              /* L3 Overhead couldn't be identified, this could be
++               * because tunnel->sock was NULL or the socket's
++               * address family was not IPv4 or IPv6,
++               * dev mtu stays at 1500.
++               */
++              return;
++      }
++      /* Adjust MTU, factor overhead - underlay L3, overlay L2 hdr
++       * UDP overhead, if any, was already factored in above.
++       */
++      overhead += session->hdr_len + ETH_HLEN + l3_overhead;
++
++      /* If PMTU discovery was enabled, use discovered MTU on L2TP device */
++      dst = sk_dst_get(tunnel->sock);
++      if (dst) {
++              /* dst_mtu will use PMTU if found, else fallback to intf MTU */
++              u32 pmtu = dst_mtu(dst);
++
++              if (pmtu != 0)
++                      dev->mtu = pmtu;
++              dst_release(dst);
++      }
++      session->mtu = dev->mtu - overhead;
++      dev->mtu = session->mtu;
++      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)
+ {
+       struct net_device *dev;
+@@ -249,10 +299,7 @@ static int l2tp_eth_create(struct net *n
+       }
+       dev_net_set(dev, net);
+-      if (session->mtu == 0)
+-              session->mtu = dev->mtu - session->hdr_len;
+-      dev->mtu = session->mtu;
+-      dev->needed_headroom += session->hdr_len;
++      l2tp_eth_adjust_mtu(tunnel, session, dev);
+       priv = netdev_priv(dev);
+       priv->dev = dev;
diff --git a/queue-4.9/l2tp-define-parameters-of-l2tp_session_get-as-const.patch b/queue-4.9/l2tp-define-parameters-of-l2tp_session_get-as-const.patch
new file mode 100644 (file)
index 0000000..d76667f
--- /dev/null
@@ -0,0 +1,73 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:23 +0100
+Subject: l2tp: define parameters of l2tp_session_get*() as "const"
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-9-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 9aaef50c44f132e040dcd7686c8e78a3390037c5 upstream.
+
+Make l2tp_pernet()'s parameter constant, so that l2tp_session_get*() can
+declare their "net" variable as "const".
+Also constify "ifname" in l2tp_session_get_by_ifname().
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |    7 ++++---
+ net/l2tp/l2tp_core.h |    5 +++--
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -119,7 +119,7 @@ static inline struct l2tp_tunnel *l2tp_t
+       return sk->sk_user_data;
+ }
+-static inline struct l2tp_net *l2tp_pernet(struct net *net)
++static inline struct l2tp_net *l2tp_pernet(const struct net *net)
+ {
+       BUG_ON(!net);
+@@ -231,7 +231,7 @@ l2tp_session_id_hash(struct l2tp_tunnel
+ /* Lookup a session. A new reference is held on the returned session.
+  * Optionally calls session->ref() too if do_ref is true.
+  */
+-struct l2tp_session *l2tp_session_get(struct net *net,
++struct l2tp_session *l2tp_session_get(const struct net *net,
+                                     struct l2tp_tunnel *tunnel,
+                                     u32 session_id, bool do_ref)
+ {
+@@ -306,7 +306,8 @@ EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
+ /* Lookup a session by interface name.
+  * This is very inefficient but is only used by management interfaces.
+  */
+-struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
++struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
++                                              const char *ifname,
+                                               bool do_ref)
+ {
+       struct l2tp_net *pn = l2tp_pernet(net);
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -231,12 +231,13 @@ out:
+       return tunnel;
+ }
+-struct l2tp_session *l2tp_session_get(struct net *net,
++struct l2tp_session *l2tp_session_get(const struct net *net,
+                                     struct l2tp_tunnel *tunnel,
+                                     u32 session_id, bool do_ref);
+ struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
+                                         bool do_ref);
+-struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
++struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
++                                              const char *ifname,
+                                               bool do_ref);
+ struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
+ struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
diff --git a/queue-4.9/l2tp-define-parameters-of-l2tp_tunnel_find-as-const.patch b/queue-4.9/l2tp-define-parameters-of-l2tp_tunnel_find-as-const.patch
new file mode 100644 (file)
index 0000000..ffe82e3
--- /dev/null
@@ -0,0 +1,56 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:24 +0100
+Subject: l2tp: define parameters of l2tp_tunnel_find*() as "const"
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-10-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 2f858b928bf5a8174911aaec76b8b72a9ca0533d upstream.
+
+l2tp_tunnel_find() and l2tp_tunnel_find_nth() don't modify "net".
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |    4 ++--
+ net/l2tp/l2tp_core.h |    4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -378,7 +378,7 @@ exist:
+ /* Lookup a tunnel by id
+  */
+-struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
++struct l2tp_tunnel *l2tp_tunnel_find(const struct net *net, u32 tunnel_id)
+ {
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_net *pn = l2tp_pernet(net);
+@@ -396,7 +396,7 @@ struct l2tp_tunnel *l2tp_tunnel_find(str
+ }
+ EXPORT_SYMBOL_GPL(l2tp_tunnel_find);
+-struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth)
++struct l2tp_tunnel *l2tp_tunnel_find_nth(const struct net *net, int nth)
+ {
+       struct l2tp_net *pn = l2tp_pernet(net);
+       struct l2tp_tunnel *tunnel;
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -239,8 +239,8 @@ struct l2tp_session *l2tp_session_get_nt
+ struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
+                                               const char *ifname,
+                                               bool do_ref);
+-struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
+-struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
++struct l2tp_tunnel *l2tp_tunnel_find(const struct net *net, u32 tunnel_id);
++struct l2tp_tunnel *l2tp_tunnel_find_nth(const struct net *net, int nth);
+ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id,
+                      u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg,
diff --git a/queue-4.9/l2tp-don-t-register-sessions-in-l2tp_session_create.patch b/queue-4.9/l2tp-don-t-register-sessions-in-l2tp_session_create.patch
new file mode 100644 (file)
index 0000000..f3cd705
--- /dev/null
@@ -0,0 +1,204 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:34 +0100
+Subject: l2tp: don't register sessions in l2tp_session_create()
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-20-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 3953ae7b218df4d1e544b98a393666f9ae58a78c upstream.
+
+Sessions created by l2tp_session_create() aren't fully initialised:
+some pseudo-wire specific operations need to be done before making the
+session usable. Therefore the PPP and Ethernet pseudo-wires continue
+working on the returned l2tp session while it's already been exposed to
+the rest of the system.
+This can lead to various issues. In particular, the session may enter
+the deletion process before having been fully initialised, which will
+confuse the session removal code.
+
+This patch moves session registration out of l2tp_session_create(), so
+that callers can control when the session is exposed to the rest of the
+system. This is done by the new l2tp_session_register() function.
+
+Only pppol2tp_session_create() can be easily converted to avoid
+modifying its session after registration (the debug message is dropped
+in order to avoid the need for holding a reference on the session).
+
+For pppol2tp_connect() and l2tp_eth_create()), more work is needed.
+That'll be done in followup patches. For now, let's just register the
+session right after its creation, like it was done before. The only
+difference is that we can easily take a reference on the session before
+registering it, so, at least, we're sure it's not going to be freed
+while we're working on it.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |   21 +++++++--------------
+ net/l2tp/l2tp_core.h |    3 +++
+ net/l2tp/l2tp_eth.c  |    9 +++++++++
+ net/l2tp/l2tp_ppp.c  |   27 +++++++++++++++++++--------
+ 4 files changed, 38 insertions(+), 22 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -321,8 +321,8 @@ struct l2tp_session *l2tp_session_get_by
+ }
+ EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname);
+-static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
+-                                    struct l2tp_session *session)
++int l2tp_session_register(struct l2tp_session *session,
++                        struct l2tp_tunnel *tunnel)
+ {
+       struct l2tp_session *session_walk;
+       struct hlist_head *g_head;
+@@ -370,6 +370,10 @@ static int l2tp_session_add_to_tunnel(st
+       hlist_add_head(&session->hlist, head);
+       write_unlock_bh(&tunnel->hlist_lock);
++      /* Ignore management session in session count value */
++      if (session->session_id != 0)
++              atomic_inc(&l2tp_session_count);
++
+       return 0;
+ err_tlock_pnlock:
+@@ -379,6 +383,7 @@ err_tlock:
+       return err;
+ }
++EXPORT_SYMBOL_GPL(l2tp_session_register);
+ /* Lookup a tunnel by id
+  */
+@@ -1788,7 +1793,6 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_heade
+ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+ {
+       struct l2tp_session *session;
+-      int err;
+       session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL);
+       if (session != NULL) {
+@@ -1845,17 +1849,6 @@ struct l2tp_session *l2tp_session_create
+               l2tp_session_inc_refcount(session);
+-              err = l2tp_session_add_to_tunnel(tunnel, session);
+-              if (err) {
+-                      kfree(session);
+-
+-                      return ERR_PTR(err);
+-              }
+-
+-              /* Ignore management session in session count value */
+-              if (session->session_id != 0)
+-                      atomic_inc(&l2tp_session_count);
+-
+               return session;
+       }
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -259,6 +259,9 @@ struct l2tp_session *l2tp_session_create
+                                        struct l2tp_tunnel *tunnel,
+                                        u32 session_id, u32 peer_session_id,
+                                        struct l2tp_session_cfg *cfg);
++int l2tp_session_register(struct l2tp_session *session,
++                        struct l2tp_tunnel *tunnel);
++
+ void __l2tp_session_unhash(struct l2tp_session *session);
+ int l2tp_session_delete(struct l2tp_session *session);
+ void l2tp_session_free(struct l2tp_session *session);
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -267,6 +267,13 @@ static int l2tp_eth_create(struct net *n
+               goto out;
+       }
++      l2tp_session_inc_refcount(session);
++      rc = l2tp_session_register(session, tunnel);
++      if (rc < 0) {
++              kfree(session);
++              goto out;
++      }
++
+       dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN,
+                          l2tp_eth_dev_setup);
+       if (!dev) {
+@@ -298,6 +305,7 @@ static int l2tp_eth_create(struct net *n
+       __module_get(THIS_MODULE);
+       /* Must be done after register_netdev() */
+       strlcpy(session->ifname, dev->name, IFNAMSIZ);
++      l2tp_session_dec_refcount(session);
+       dev_hold(dev);
+@@ -308,6 +316,7 @@ out_del_dev:
+       spriv->dev = NULL;
+ out_del_session:
+       l2tp_session_delete(session);
++      l2tp_session_dec_refcount(session);
+ out:
+       return rc;
+ }
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -722,6 +722,14 @@ static int pppol2tp_connect(struct socke
+                       error = PTR_ERR(session);
+                       goto end;
+               }
++
++              l2tp_session_inc_refcount(session);
++              error = l2tp_session_register(session, tunnel);
++              if (error < 0) {
++                      kfree(session);
++                      goto end;
++              }
++              drop_refcnt = true;
+       }
+       /* Associate session with its PPPoL2TP socket */
+@@ -807,7 +815,7 @@ static int pppol2tp_session_create(struc
+       /* Error if tunnel socket is not prepped */
+       if (!tunnel->sock) {
+               error = -ENOENT;
+-              goto out;
++              goto err;
+       }
+       /* Default MTU values. */
+@@ -822,18 +830,21 @@ static int pppol2tp_session_create(struc
+                                     peer_session_id, cfg);
+       if (IS_ERR(session)) {
+               error = PTR_ERR(session);
+-              goto out;
++              goto err;
+       }
+       ps = l2tp_session_priv(session);
+       ps->tunnel_sock = tunnel->sock;
+-      l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
+-                session->name);
+-
+-      error = 0;
+-
+-out:
++      error = l2tp_session_register(session, tunnel);
++      if (error < 0)
++              goto err_sess;
++
++      return 0;
++
++err_sess:
++      kfree(session);
++err:
+       return error;
+ }
diff --git a/queue-4.9/l2tp-fix-l2tp_eth-module-loading.patch b/queue-4.9/l2tp-fix-l2tp_eth-module-loading.patch
new file mode 100644 (file)
index 0000000..fdb7df8
--- /dev/null
@@ -0,0 +1,148 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:33 +0100
+Subject: l2tp: fix l2tp_eth module loading
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-19-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 9f775ead5e570e7e19015b9e4e2f3dd6e71a5935 upstream.
+
+The l2tp_eth module crashes if its netlink callbacks are run when the
+pernet data aren't initialised.
+
+We should normally register_pernet_device() before the genl callbacks.
+However, the pernet data only maintain a list of l2tpeth interfaces,
+and this list is never used. So let's just drop pernet handling
+instead.
+
+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>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_eth.c |   51 ++-------------------------------------------------
+ 1 file changed, 2 insertions(+), 49 deletions(-)
+
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -44,7 +44,6 @@ struct l2tp_eth {
+       struct net_device       *dev;
+       struct sock             *tunnel_sock;
+       struct l2tp_session     *session;
+-      struct list_head        list;
+       atomic_long_t           tx_bytes;
+       atomic_long_t           tx_packets;
+       atomic_long_t           tx_dropped;
+@@ -58,17 +57,6 @@ struct l2tp_eth_sess {
+       struct net_device       *dev;
+ };
+-/* per-net private data for this module */
+-static unsigned int l2tp_eth_net_id;
+-struct l2tp_eth_net {
+-      struct list_head l2tp_eth_dev_list;
+-      spinlock_t l2tp_eth_lock;
+-};
+-
+-static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net)
+-{
+-      return net_generic(net, l2tp_eth_net_id);
+-}
+ static int l2tp_eth_dev_init(struct net_device *dev)
+ {
+@@ -84,12 +72,6 @@ static int l2tp_eth_dev_init(struct net_
+ static void l2tp_eth_dev_uninit(struct net_device *dev)
+ {
+-      struct l2tp_eth *priv = netdev_priv(dev);
+-      struct l2tp_eth_net *pn = l2tp_eth_pernet(dev_net(dev));
+-
+-      spin_lock(&pn->l2tp_eth_lock);
+-      list_del_init(&priv->list);
+-      spin_unlock(&pn->l2tp_eth_lock);
+       dev_put(dev);
+ }
+@@ -266,7 +248,6 @@ static int l2tp_eth_create(struct net *n
+       struct l2tp_eth *priv;
+       struct l2tp_eth_sess *spriv;
+       int rc;
+-      struct l2tp_eth_net *pn;
+       if (cfg->ifname) {
+               dev = dev_get_by_name(net, cfg->ifname);
+@@ -299,7 +280,6 @@ static int l2tp_eth_create(struct net *n
+       priv = netdev_priv(dev);
+       priv->dev = dev;
+       priv->session = session;
+-      INIT_LIST_HEAD(&priv->list);
+       priv->tunnel_sock = tunnel->sock;
+       session->recv_skb = l2tp_eth_dev_recv;
+@@ -320,10 +300,6 @@ static int l2tp_eth_create(struct net *n
+       strlcpy(session->ifname, dev->name, IFNAMSIZ);
+       dev_hold(dev);
+-      pn = l2tp_eth_pernet(dev_net(dev));
+-      spin_lock(&pn->l2tp_eth_lock);
+-      list_add(&priv->list, &pn->l2tp_eth_dev_list);
+-      spin_unlock(&pn->l2tp_eth_lock);
+       return 0;
+@@ -336,22 +312,6 @@ out:
+       return rc;
+ }
+-static __net_init int l2tp_eth_init_net(struct net *net)
+-{
+-      struct l2tp_eth_net *pn = net_generic(net, l2tp_eth_net_id);
+-
+-      INIT_LIST_HEAD(&pn->l2tp_eth_dev_list);
+-      spin_lock_init(&pn->l2tp_eth_lock);
+-
+-      return 0;
+-}
+-
+-static struct pernet_operations l2tp_eth_net_ops = {
+-      .init = l2tp_eth_init_net,
+-      .id   = &l2tp_eth_net_id,
+-      .size = sizeof(struct l2tp_eth_net),
+-};
+-
+ static const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = {
+       .session_create = l2tp_eth_create,
+@@ -365,25 +325,18 @@ static int __init l2tp_eth_init(void)
+       err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops);
+       if (err)
+-              goto out;
+-
+-      err = register_pernet_device(&l2tp_eth_net_ops);
+-      if (err)
+-              goto out_unreg;
++              goto err;
+       pr_info("L2TP ethernet pseudowire support (L2TPv3)\n");
+       return 0;
+-out_unreg:
+-      l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
+-out:
++err:
+       return err;
+ }
+ static void __exit l2tp_eth_exit(void)
+ {
+-      unregister_pernet_device(&l2tp_eth_net_ops);
+       l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
+ }
diff --git a/queue-4.9/l2tp-hold-tunnel-used-while-creating-sessions-with-netlink.patch b/queue-4.9/l2tp-hold-tunnel-used-while-creating-sessions-with-netlink.patch
new file mode 100644 (file)
index 0000000..e3f2fb6
--- /dev/null
@@ -0,0 +1,112 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:30 +0100
+Subject: l2tp: hold tunnel used while creating sessions with netlink
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-16-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit e702c1204eb57788ef189c839c8c779368267d70 upstream.
+
+Use l2tp_tunnel_get() to retrieve tunnel, so that it can't go away on
+us. Otherwise l2tp_tunnel_destruct() might release the last reference
+count concurrently, thus freeing the tunnel while we're using it.
+
+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: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_netlink.c |   21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -510,8 +510,9 @@ static int l2tp_nl_cmd_session_create(st
+               ret = -EINVAL;
+               goto out;
+       }
++
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+-      tunnel = l2tp_tunnel_find(net, tunnel_id);
++      tunnel = l2tp_tunnel_get(net, tunnel_id);
+       if (!tunnel) {
+               ret = -ENODEV;
+               goto out;
+@@ -519,24 +520,24 @@ static int l2tp_nl_cmd_session_create(st
+       if (!info->attrs[L2TP_ATTR_SESSION_ID]) {
+               ret = -EINVAL;
+-              goto out;
++              goto out_tunnel;
+       }
+       session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
+       if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) {
+               ret = -EINVAL;
+-              goto out;
++              goto out_tunnel;
+       }
+       peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]);
+       if (!info->attrs[L2TP_ATTR_PW_TYPE]) {
+               ret = -EINVAL;
+-              goto out;
++              goto out_tunnel;
+       }
+       cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]);
+       if (cfg.pw_type >= __L2TP_PWTYPE_MAX) {
+               ret = -EINVAL;
+-              goto out;
++              goto out_tunnel;
+       }
+       if (tunnel->version > 2) {
+@@ -555,7 +556,7 @@ static int l2tp_nl_cmd_session_create(st
+                       u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]);
+                       if (len > 8) {
+                               ret = -EINVAL;
+-                              goto out;
++                              goto out_tunnel;
+                       }
+                       cfg.cookie_len = len;
+                       memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len);
+@@ -564,7 +565,7 @@ static int l2tp_nl_cmd_session_create(st
+                       u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]);
+                       if (len > 8) {
+                               ret = -EINVAL;
+-                              goto out;
++                              goto out_tunnel;
+                       }
+                       cfg.peer_cookie_len = len;
+                       memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len);
+@@ -607,7 +608,7 @@ static int l2tp_nl_cmd_session_create(st
+       if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) ||
+           (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) {
+               ret = -EPROTONOSUPPORT;
+-              goto out;
++              goto out_tunnel;
+       }
+       /* Check that pseudowire-specific params are present */
+@@ -617,7 +618,7 @@ static int l2tp_nl_cmd_session_create(st
+       case L2TP_PWTYPE_ETH_VLAN:
+               if (!info->attrs[L2TP_ATTR_VLAN_ID]) {
+                       ret = -EINVAL;
+-                      goto out;
++                      goto out_tunnel;
+               }
+               break;
+       case L2TP_PWTYPE_ETH:
+@@ -645,6 +646,8 @@ static int l2tp_nl_cmd_session_create(st
+               }
+       }
++out_tunnel:
++      l2tp_tunnel_dec_refcount(tunnel);
+ out:
+       return ret;
+ }
diff --git a/queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel-updates.patch b/queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel-updates.patch
new file mode 100644 (file)
index 0000000..6368a58
--- /dev/null
@@ -0,0 +1,46 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:28 +0100
+Subject: l2tp: hold tunnel while handling genl tunnel updates
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-14-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 8c0e421525c9eb50d68e8f633f703ca31680b746 upstream.
+
+We need to make sure the tunnel is not going to be destroyed by
+l2tp_tunnel_destruct() concurrently.
+
+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: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_netlink.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -310,8 +310,8 @@ static int l2tp_nl_cmd_tunnel_modify(str
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+-      tunnel = l2tp_tunnel_find(net, tunnel_id);
+-      if (tunnel == NULL) {
++      tunnel = l2tp_tunnel_get(net, tunnel_id);
++      if (!tunnel) {
+               ret = -ENODEV;
+               goto out;
+       }
+@@ -322,6 +322,8 @@ static int l2tp_nl_cmd_tunnel_modify(str
+       ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
+                                tunnel, L2TP_CMD_TUNNEL_MODIFY);
++      l2tp_tunnel_dec_refcount(tunnel);
++
+ out:
+       return ret;
+ }
diff --git a/queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel_get-commands.patch b/queue-4.9/l2tp-hold-tunnel-while-handling-genl-tunnel_get-commands.patch
new file mode 100644 (file)
index 0000000..6da4c08
--- /dev/null
@@ -0,0 +1,80 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:29 +0100
+Subject: l2tp: hold tunnel while handling genl TUNNEL_GET commands
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>, "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-15-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 4e4b21da3acc68a7ea55f850cacc13706b7480e9 upstream.
+
+Use l2tp_tunnel_get() instead of l2tp_tunnel_find() so that we get
+a reference on the tunnel, preventing l2tp_tunnel_destruct() from
+freeing it from under us.
+
+Also move l2tp_tunnel_get() below nlmsg_new() so that we only take
+the reference when needed.
+
+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: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_netlink.c |   27 +++++++++++++++------------
+ 1 file changed, 15 insertions(+), 12 deletions(-)
+
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -436,34 +436,37 @@ static int l2tp_nl_cmd_tunnel_get(struct
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+-              goto out;
++              goto err;
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+-      tunnel = l2tp_tunnel_find(net, tunnel_id);
+-      if (tunnel == NULL) {
+-              ret = -ENODEV;
+-              goto out;
+-      }
+-
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg) {
+               ret = -ENOMEM;
+-              goto out;
++              goto err;
++      }
++
++      tunnel = l2tp_tunnel_get(net, tunnel_id);
++      if (!tunnel) {
++              ret = -ENODEV;
++              goto err_nlmsg;
+       }
+       ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
+                                 NLM_F_ACK, tunnel, L2TP_CMD_TUNNEL_GET);
+       if (ret < 0)
+-              goto err_out;
++              goto err_nlmsg_tunnel;
++
++      l2tp_tunnel_dec_refcount(tunnel);
+       return genlmsg_unicast(net, msg, info->snd_portid);
+-err_out:
++err_nlmsg_tunnel:
++      l2tp_tunnel_dec_refcount(tunnel);
++err_nlmsg:
+       nlmsg_free(msg);
+-
+-out:
++err:
+       return ret;
+ }
diff --git a/queue-4.9/l2tp-hold-tunnel-while-looking-up-sessions-in-l2tp_netlink.patch b/queue-4.9/l2tp-hold-tunnel-while-looking-up-sessions-in-l2tp_netlink.patch
new file mode 100644 (file)
index 0000000..fc799e9
--- /dev/null
@@ -0,0 +1,194 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:26 +0100
+Subject: l2tp: hold tunnel while looking up sessions in l2tp_netlink
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-12-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 54652eb12c1b72e9602d09cb2821d5760939190f upstream.
+
+l2tp_tunnel_find() doesn't take a reference on the returned tunnel.
+Therefore, it's unsafe to use it because the returned tunnel can go
+away on us anytime.
+
+Fix this by defining l2tp_tunnel_get(), which works like
+l2tp_tunnel_find(), but takes a reference on the returned tunnel.
+Caller then has to drop this reference using l2tp_tunnel_dec_refcount().
+
+As l2tp_tunnel_dec_refcount() needs to be moved to l2tp_core.h, let's
+simplify the patch and not move the L2TP_REFCNT_DEBUG part. This code
+has been broken (not even compiling) in May 2012 by
+commit a4ca44fa578c ("net: l2tp: Standardize logging styles")
+and fixed more than two years later by
+commit 29abe2fda54f ("l2tp: fix missing line continuation"). So it
+doesn't appear to be used by anyone.
+
+Same thing for l2tp_tunnel_free(); instead of moving it to l2tp_core.h,
+let's just simplify things and call kfree_rcu() directly in
+l2tp_tunnel_dec_refcount(). Extra assertions and debugging code
+provided by l2tp_tunnel_free() didn't help catching any of the
+reference counting and socket handling issues found while working on
+this series.
+
+Backporting Notes
+
+l2tp_core.c: This patch deletes some code / moves some code to
+l2tp_core.h and follows the patch (not including in this series) that
+switched from atomic to refcount_t. Moved code changed back to atomic.
+
+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: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c    |   66 +++++++++++++++---------------------------------
+ net/l2tp/l2tp_core.h    |   13 +++++++++
+ net/l2tp/l2tp_netlink.c |    6 ++--
+ 3 files changed, 38 insertions(+), 47 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -112,7 +112,6 @@ struct l2tp_net {
+       spinlock_t l2tp_session_hlist_lock;
+ };
+-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
+ static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
+ {
+@@ -126,39 +125,6 @@ static inline struct l2tp_net *l2tp_pern
+       return net_generic(net, l2tp_net_id);
+ }
+-/* Tunnel reference counts. Incremented per session that is added to
+- * the tunnel.
+- */
+-static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
+-{
+-      atomic_inc(&tunnel->ref_count);
+-}
+-
+-static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
+-{
+-      if (atomic_dec_and_test(&tunnel->ref_count))
+-              l2tp_tunnel_free(tunnel);
+-}
+-#ifdef L2TP_REFCNT_DEBUG
+-#define l2tp_tunnel_inc_refcount(_t)                                  \
+-do {                                                                  \
+-      pr_debug("l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n",        \
+-               __func__, __LINE__, (_t)->name,                        \
+-               atomic_read(&_t->ref_count));                          \
+-      l2tp_tunnel_inc_refcount_1(_t);                                 \
+-} while (0)
+-#define l2tp_tunnel_dec_refcount(_t)                                  \
+-do {                                                                  \
+-      pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n",        \
+-               __func__, __LINE__, (_t)->name,                        \
+-               atomic_read(&_t->ref_count));                          \
+-      l2tp_tunnel_dec_refcount_1(_t);                                 \
+-} while (0)
+-#else
+-#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
+-#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
+-#endif
+-
+ /* Session hash global list for L2TPv3.
+  * The session_id SHOULD be random according to RFC3931, but several
+  * L2TP implementations use incrementing session_ids.  So we do a real
+@@ -228,6 +194,27 @@ l2tp_session_id_hash(struct l2tp_tunnel
+       return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
+ }
++/* Lookup a tunnel. A new reference is held on the returned tunnel. */
++struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
++{
++      const struct l2tp_net *pn = l2tp_pernet(net);
++      struct l2tp_tunnel *tunnel;
++
++      rcu_read_lock_bh();
++      list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
++              if (tunnel->tunnel_id == tunnel_id) {
++                      l2tp_tunnel_inc_refcount(tunnel);
++                      rcu_read_unlock_bh();
++
++                      return tunnel;
++              }
++      }
++      rcu_read_unlock_bh();
++
++      return NULL;
++}
++EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
++
+ /* Lookup a session. A new reference is held on the returned session.
+  * Optionally calls session->ref() too if do_ref is true.
+  */
+@@ -1346,17 +1333,6 @@ static void l2tp_udp_encap_destroy(struc
+       }
+ }
+-/* Really kill the tunnel.
+- * Come here only when all sessions have been cleared from the tunnel.
+- */
+-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
+-{
+-      BUG_ON(atomic_read(&tunnel->ref_count) != 0);
+-      BUG_ON(tunnel->sock != NULL);
+-      l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: free...\n", tunnel->name);
+-      kfree_rcu(tunnel, rcu);
+-}
+-
+ /* Workqueue tunnel deletion function */
+ static void l2tp_tunnel_del_work(struct work_struct *work)
+ {
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -231,6 +231,8 @@ out:
+       return tunnel;
+ }
++struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
++
+ struct l2tp_session *l2tp_session_get(const struct net *net,
+                                     struct l2tp_tunnel *tunnel,
+                                     u32 session_id, bool do_ref);
+@@ -269,6 +271,17 @@ int l2tp_nl_register_ops(enum l2tp_pwtyp
+ void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
+ int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
++static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
++{
++      atomic_inc(&tunnel->ref_count);
++}
++
++static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel)
++{
++      if (atomic_dec_and_test(&tunnel->ref_count))
++              kfree_rcu(tunnel, rcu);
++}
++
+ /* Session reference counts. Incremented when code obtains a reference
+  * to a session.
+  */
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -72,10 +72,12 @@ static struct l2tp_session *l2tp_nl_sess
+                  (info->attrs[L2TP_ATTR_CONN_ID])) {
+               tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+               session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
+-              tunnel = l2tp_tunnel_find(net, tunnel_id);
+-              if (tunnel)
++              tunnel = l2tp_tunnel_get(net, tunnel_id);
++              if (tunnel) {
+                       session = l2tp_session_get(net, tunnel, session_id,
+                                                  do_ref);
++                      l2tp_tunnel_dec_refcount(tunnel);
++              }
+       }
+       return session;
diff --git a/queue-4.9/l2tp-hold-tunnel-while-processing-genl-delete-command.patch b/queue-4.9/l2tp-hold-tunnel-while-processing-genl-delete-command.patch
new file mode 100644 (file)
index 0000000..fadb80a
--- /dev/null
@@ -0,0 +1,46 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:27 +0100
+Subject: l2tp: hold tunnel while processing genl delete command
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-13-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit bb0a32ce4389e17e47e198d2cddaf141561581ad upstream.
+
+l2tp_nl_cmd_tunnel_delete() needs to take a reference on the tunnel, to
+prevent it from being concurrently freed by l2tp_tunnel_destruct().
+
+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: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_netlink.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -280,8 +280,8 @@ static int l2tp_nl_cmd_tunnel_delete(str
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+-      tunnel = l2tp_tunnel_find(net, tunnel_id);
+-      if (tunnel == NULL) {
++      tunnel = l2tp_tunnel_get(net, tunnel_id);
++      if (!tunnel) {
+               ret = -ENODEV;
+               goto out;
+       }
+@@ -291,6 +291,8 @@ static int l2tp_nl_cmd_tunnel_delete(str
+       l2tp_tunnel_delete(tunnel);
++      l2tp_tunnel_dec_refcount(tunnel);
++
+ out:
+       return ret;
+ }
diff --git a/queue-4.9/l2tp-initialise-l2tp_eth-sessions-before-registering-them.patch b/queue-4.9/l2tp-initialise-l2tp_eth-sessions-before-registering-them.patch
new file mode 100644 (file)
index 0000000..735c7fe
--- /dev/null
@@ -0,0 +1,246 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:35 +0100
+Subject: l2tp: initialise l2tp_eth sessions before registering them
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-21-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit ee28de6bbd78c2e18111a0aef43ea746f28d2073 upstream.
+
+Sessions must be initialised before being made externally visible by
+l2tp_session_register(). Otherwise the session may be concurrently
+deleted before being initialised, which can confuse the deletion path
+and eventually lead to kernel oops.
+
+Therefore, we need to move l2tp_session_register() down in
+l2tp_eth_create(), but also handle the intermediate step where only the
+session or the netdevice has been registered.
+
+We can't just call l2tp_session_register() in ->ndo_init() because
+we'd have no way to properly undo this operation in ->ndo_uninit().
+Instead, let's register the session and the netdevice in two different
+steps and protect the session's device pointer with RCU.
+
+And now that we allow the session's .dev field to be NULL, we don't
+need to prevent the netdevice from being removed anymore. So we can
+drop the dev_hold() and dev_put() calls in l2tp_eth_create() and
+l2tp_eth_dev_uninit().
+
+Backporting Notes
+
+l2tp_eth.c: In l2tp_eth_create the "out" label was renamed to "err".
+There was one extra occurrence of "goto out" to update.
+
+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>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_eth.c |  108 ++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 76 insertions(+), 32 deletions(-)
+
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -54,7 +54,7 @@ struct l2tp_eth {
+ /* via l2tp_session_priv() */
+ struct l2tp_eth_sess {
+-      struct net_device       *dev;
++      struct net_device __rcu *dev;
+ };
+@@ -72,7 +72,14 @@ static int l2tp_eth_dev_init(struct net_
+ static void l2tp_eth_dev_uninit(struct net_device *dev)
+ {
+-      dev_put(dev);
++      struct l2tp_eth *priv = netdev_priv(dev);
++      struct l2tp_eth_sess *spriv;
++
++      spriv = l2tp_session_priv(priv->session);
++      RCU_INIT_POINTER(spriv->dev, NULL);
++      /* No need for synchronize_net() here. We're called by
++       * unregister_netdev*(), which does the synchronisation for us.
++       */
+ }
+ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -126,8 +133,8 @@ static void l2tp_eth_dev_setup(struct ne
+ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
+ {
+       struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
+-      struct net_device *dev = spriv->dev;
+-      struct l2tp_eth *priv = netdev_priv(dev);
++      struct net_device *dev;
++      struct l2tp_eth *priv;
+       if (session->debug & L2TP_MSG_DATA) {
+               unsigned int length;
+@@ -151,16 +158,25 @@ static void l2tp_eth_dev_recv(struct l2t
+       skb_dst_drop(skb);
+       nf_reset(skb);
++      rcu_read_lock();
++      dev = rcu_dereference(spriv->dev);
++      if (!dev)
++              goto error_rcu;
++
++      priv = netdev_priv(dev);
+       if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) {
+               atomic_long_inc(&priv->rx_packets);
+               atomic_long_add(data_len, &priv->rx_bytes);
+       } else {
+               atomic_long_inc(&priv->rx_errors);
+       }
++      rcu_read_unlock();
++
+       return;
++error_rcu:
++      rcu_read_unlock();
+ error:
+-      atomic_long_inc(&priv->rx_errors);
+       kfree_skb(skb);
+ }
+@@ -171,11 +187,15 @@ static void l2tp_eth_delete(struct l2tp_
+       if (session) {
+               spriv = l2tp_session_priv(session);
+-              dev = spriv->dev;
++
++              rtnl_lock();
++              dev = rtnl_dereference(spriv->dev);
+               if (dev) {
+-                      unregister_netdev(dev);
+-                      spriv->dev = NULL;
++                      unregister_netdevice(dev);
++                      rtnl_unlock();
+                       module_put(THIS_MODULE);
++              } else {
++                      rtnl_unlock();
+               }
+       }
+ }
+@@ -185,9 +205,20 @@ static void l2tp_eth_show(struct seq_fil
+ {
+       struct l2tp_session *session = arg;
+       struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
+-      struct net_device *dev = spriv->dev;
++      struct net_device *dev;
++
++      rcu_read_lock();
++      dev = rcu_dereference(spriv->dev);
++      if (!dev) {
++              rcu_read_unlock();
++              return;
++      }
++      dev_hold(dev);
++      rcu_read_unlock();
+       seq_printf(m, "   interface %s\n", dev->name);
++
++      dev_put(dev);
+ }
+ #endif
+@@ -254,7 +285,7 @@ static int l2tp_eth_create(struct net *n
+               if (dev) {
+                       dev_put(dev);
+                       rc = -EEXIST;
+-                      goto out;
++                      goto err;
+               }
+               strlcpy(name, cfg->ifname, IFNAMSIZ);
+       } else
+@@ -264,21 +295,14 @@ static int l2tp_eth_create(struct net *n
+                                     peer_session_id, cfg);
+       if (IS_ERR(session)) {
+               rc = PTR_ERR(session);
+-              goto out;
+-      }
+-
+-      l2tp_session_inc_refcount(session);
+-      rc = l2tp_session_register(session, tunnel);
+-      if (rc < 0) {
+-              kfree(session);
+-              goto out;
++              goto err;
+       }
+       dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN,
+                          l2tp_eth_dev_setup);
+       if (!dev) {
+               rc = -ENOMEM;
+-              goto out_del_session;
++              goto err_sess;
+       }
+       dev_net_set(dev, net);
+@@ -296,28 +320,48 @@ static int l2tp_eth_create(struct net *n
+ #endif
+       spriv = l2tp_session_priv(session);
+-      spriv->dev = dev;
+-      rc = register_netdev(dev);
+-      if (rc < 0)
+-              goto out_del_dev;
++      l2tp_session_inc_refcount(session);
++
++      rtnl_lock();
++
++      /* Register both device and session while holding the rtnl lock. This
++       * ensures that l2tp_eth_delete() will see that there's a device to
++       * unregister, even if it happened to run before we assign spriv->dev.
++       */
++      rc = l2tp_session_register(session, tunnel);
++      if (rc < 0) {
++              rtnl_unlock();
++              goto err_sess_dev;
++      }
++
++      rc = register_netdevice(dev);
++      if (rc < 0) {
++              rtnl_unlock();
++              l2tp_session_delete(session);
++              l2tp_session_dec_refcount(session);
++              free_netdev(dev);
++
++              return rc;
++      }
+-      __module_get(THIS_MODULE);
+-      /* Must be done after register_netdev() */
+       strlcpy(session->ifname, dev->name, IFNAMSIZ);
++      rcu_assign_pointer(spriv->dev, dev);
++
++      rtnl_unlock();
++
+       l2tp_session_dec_refcount(session);
+-      dev_hold(dev);
++      __module_get(THIS_MODULE);
+       return 0;
+-out_del_dev:
+-      free_netdev(dev);
+-      spriv->dev = NULL;
+-out_del_session:
+-      l2tp_session_delete(session);
++err_sess_dev:
+       l2tp_session_dec_refcount(session);
+-out:
++      free_netdev(dev);
++err_sess:
++      kfree(session);
++err:
+       return rc;
+ }
diff --git a/queue-4.9/l2tp-initialise-ppp-sessions-before-registering-them.patch b/queue-4.9/l2tp-initialise-ppp-sessions-before-registering-them.patch
new file mode 100644 (file)
index 0000000..5917035
--- /dev/null
@@ -0,0 +1,193 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:37 +0100
+Subject: l2tp: initialise PPP sessions before registering them
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-23-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit f98be6c6359e7e4a61aaefb9964c1db31cb9ec0c upstream.
+
+pppol2tp_connect() initialises L2TP sessions after they've been exposed
+to the rest of the system by l2tp_session_register(). This puts
+sessions into transient states that are the source of several races, in
+particular with session's deletion path.
+
+This patch centralises the initialisation code into
+pppol2tp_session_init(), which is called before the registration phase.
+The only field that can't be set before session registration is the
+pppol2tp socket pointer, which has already been converted to RCU. So
+pppol2tp_connect() should now be race-free.
+
+The session's .session_close() callback is now set before registration.
+Therefore, it's always called when l2tp_core deletes the session, even
+if it was created by pppol2tp_session_create() and hasn't been plugged
+to a pppol2tp socket yet. That'd prevent session free because the extra
+reference taken by pppol2tp_session_close() wouldn't be dropped by the
+socket's ->sk_destruct() callback (pppol2tp_session_destruct()).
+We could set .session_close() only while connecting a session to its
+pppol2tp socket, or teach pppol2tp_session_close() to avoid grabbing a
+reference when the session isn't connected, but that'd require adding
+some form of synchronisation to be race free.
+
+Instead of that, we can just let the pppol2tp socket hold a reference
+on the session as soon as it starts depending on it (that is, in
+pppol2tp_connect()). Then we don't need to utilise
+pppol2tp_session_close() to hold a reference at the last moment to
+prevent l2tp_core from dropping it.
+
+When releasing the socket, pppol2tp_release() now deletes the session
+using the standard l2tp_session_delete() function, instead of merely
+removing it from hash tables. l2tp_session_delete() drops the reference
+the sessions holds on itself, but also makes sure it doesn't remove a
+session twice. So it can safely be called, even if l2tp_core already
+tried, or is concurrently trying, to remove the session.
+Finally, pppol2tp_session_destruct() drops the reference held by the
+socket.
+
+Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c |   69 ++++++++++++++++++++++++++++------------------------
+ 1 file changed, 38 insertions(+), 31 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -449,9 +449,6 @@ static void pppol2tp_session_close(struc
+                       inet_shutdown(sk->sk_socket, SEND_SHUTDOWN);
+               sock_put(sk);
+       }
+-
+-      /* Don't let the session go away before our socket does */
+-      l2tp_session_inc_refcount(session);
+ }
+ /* Really kill the session socket. (Called from sock_put() if
+@@ -507,8 +504,7 @@ static int pppol2tp_release(struct socke
+       if (session != NULL) {
+               struct pppol2tp_session *ps;
+-              __l2tp_session_unhash(session);
+-              l2tp_session_queue_purge(session);
++              l2tp_session_delete(session);
+               ps = l2tp_session_priv(session);
+               mutex_lock(&ps->sk_lock);
+@@ -600,6 +596,35 @@ static void pppol2tp_show(struct seq_fil
+ }
+ #endif
++static void pppol2tp_session_init(struct l2tp_session *session)
++{
++      struct pppol2tp_session *ps;
++      struct dst_entry *dst;
++
++      session->recv_skb = pppol2tp_recv;
++      session->session_close = pppol2tp_session_close;
++#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
++      session->show = pppol2tp_show;
++#endif
++
++      ps = l2tp_session_priv(session);
++      mutex_init(&ps->sk_lock);
++      ps->tunnel_sock = session->tunnel->sock;
++      ps->owner = current->pid;
++
++      /* If PMTU discovery was enabled, use the MTU that was discovered */
++      dst = sk_dst_get(session->tunnel->sock);
++      if (dst) {
++              u32 pmtu = dst_mtu(dst);
++
++              if (pmtu) {
++                      session->mtu = pmtu - PPPOL2TP_HEADER_OVERHEAD;
++                      session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD;
++              }
++              dst_release(dst);
++      }
++}
++
+ /* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
+  */
+ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
+@@ -611,7 +636,6 @@ static int pppol2tp_connect(struct socke
+       struct l2tp_session *session = NULL;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+-      struct dst_entry *dst;
+       struct l2tp_session_cfg cfg = { 0, };
+       int error = 0;
+       u32 tunnel_id, peer_tunnel_id;
+@@ -760,8 +784,8 @@ static int pppol2tp_connect(struct socke
+                       goto end;
+               }
++              pppol2tp_session_init(session);
+               ps = l2tp_session_priv(session);
+-              mutex_init(&ps->sk_lock);
+               l2tp_session_inc_refcount(session);
+               mutex_lock(&ps->sk_lock);
+@@ -774,26 +798,6 @@ static int pppol2tp_connect(struct socke
+               drop_refcnt = true;
+       }
+-      ps->owner            = current->pid;
+-      ps->tunnel_sock = tunnel->sock;
+-
+-      session->recv_skb       = pppol2tp_recv;
+-      session->session_close  = pppol2tp_session_close;
+-#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
+-      session->show           = pppol2tp_show;
+-#endif
+-
+-      /* If PMTU discovery was enabled, use the MTU that was discovered */
+-      dst = sk_dst_get(tunnel->sock);
+-      if (dst != NULL) {
+-              u32 pmtu = dst_mtu(dst);
+-
+-              if (pmtu != 0)
+-                      session->mtu = session->mru = pmtu -
+-                              PPPOL2TP_HEADER_OVERHEAD;
+-              dst_release(dst);
+-      }
+-
+       /* Special case: if source & dest session_id == 0x0000, this
+        * socket is being created to manage the tunnel. Just set up
+        * the internal context for use by ioctl() and sockopt()
+@@ -827,6 +831,12 @@ out_no_ppp:
+       rcu_assign_pointer(ps->sk, sk);
+       mutex_unlock(&ps->sk_lock);
++      /* Keep the reference we've grabbed on the session: sk doesn't expect
++       * the session to disappear. pppol2tp_session_destruct() is responsible
++       * for dropping it.
++       */
++      drop_refcnt = false;
++
+       sk->sk_state = PPPOX_CONNECTED;
+       l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
+                 session->name);
+@@ -848,7 +858,6 @@ static int pppol2tp_session_create(struc
+ {
+       int error;
+       struct l2tp_session *session;
+-      struct pppol2tp_session *ps;
+       /* Error if tunnel socket is not prepped */
+       if (!tunnel->sock) {
+@@ -871,9 +880,7 @@ static int pppol2tp_session_create(struc
+               goto err;
+       }
+-      ps = l2tp_session_priv(session);
+-      mutex_init(&ps->sk_lock);
+-      ps->tunnel_sock = tunnel->sock;
++      pppol2tp_session_init(session);
+       error = l2tp_session_register(session, tunnel);
+       if (error < 0)
diff --git a/queue-4.9/l2tp-initialise-session-s-refcount-before-making-it-reachable.patch b/queue-4.9/l2tp-initialise-session-s-refcount-before-making-it-reachable.patch
new file mode 100644 (file)
index 0000000..8faa793
--- /dev/null
@@ -0,0 +1,53 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:25 +0100
+Subject: l2tp: initialise session's refcount before making it reachable
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-11-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 9ee369a405c57613d7c83a3967780c3e30c52ecc upstream.
+
+Sessions must be fully initialised before calling
+l2tp_session_add_to_tunnel(). Otherwise, there's a short time frame
+where partially initialised sessions can be accessed by external users.
+
+Backporting Notes
+
+l2tp_core.c: moving code that had been converted from atomic to
+refcount_t by an earlier change (which isn't being included in this
+patch series).
+
+Fixes: dbdbc73b4478 ("l2tp: fix duplicate session creation")
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -1847,6 +1847,8 @@ struct l2tp_session *l2tp_session_create
+               l2tp_session_set_header_len(session, tunnel->version);
++              l2tp_session_inc_refcount(session);
++
+               err = l2tp_session_add_to_tunnel(tunnel, session);
+               if (err) {
+                       kfree(session);
+@@ -1854,10 +1856,6 @@ struct l2tp_session *l2tp_session_create
+                       return ERR_PTR(err);
+               }
+-              /* Bump the reference count. The session context is deleted
+-               * only when this drops to zero.
+-               */
+-              l2tp_session_inc_refcount(session);
+               l2tp_tunnel_inc_refcount(tunnel);
+               /* Ensure tunnel socket isn't deleted */
diff --git a/queue-4.9/l2tp-pass-tunnel-pointer-to-session_create.patch b/queue-4.9/l2tp-pass-tunnel-pointer-to-session_create.patch
new file mode 100644 (file)
index 0000000..c60315c
--- /dev/null
@@ -0,0 +1,144 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:32 +0100
+Subject: l2tp: pass tunnel pointer to ->session_create()
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-18-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit f026bc29a8e093edfbb2a77700454b285c97e8ad upstream.
+
+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>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.h    |    4 +++-
+ net/l2tp/l2tp_eth.c     |   11 +++--------
+ net/l2tp/l2tp_netlink.c |    8 ++++----
+ net/l2tp/l2tp_ppp.c     |   19 +++++++------------
+ 4 files changed, 17 insertions(+), 25 deletions(-)
+
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -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);
+ };
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -256,23 +256,18 @@ static void l2tp_eth_adjust_mtu(struct l
+       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)
+ {
+       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) {
+               dev = dev_get_by_name(net, cfg->ifname);
+               if (dev) {
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -632,10 +632,10 @@ static int l2tp_nl_cmd_session_create(st
+               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);
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -795,25 +795,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)
diff --git a/queue-4.9/l2tp-prevent-creation-of-sessions-on-terminated-tunnels.patch b/queue-4.9/l2tp-prevent-creation-of-sessions-on-terminated-tunnels.patch
new file mode 100644 (file)
index 0000000..0f0d88e
--- /dev/null
@@ -0,0 +1,168 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:31 +0100
+Subject: l2tp: prevent creation of sessions on terminated tunnels
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-17-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit f3c66d4e144a0904ea9b95d23ed9f8eb38c11bfb upstream.
+
+l2tp_tunnel_destruct() sets tunnel->sock to NULL, then removes the
+tunnel from the pernet list and finally closes all its sessions.
+Therefore, it's possible to add a session to a tunnel that is still
+reachable, but for which tunnel->sock has already been reset. This can
+make l2tp_session_create() dereference a NULL pointer when calling
+sock_hold(tunnel->sock).
+
+This patch adds the .acpt_newsess field to struct l2tp_tunnel, which is
+used by l2tp_tunnel_closeall() to prevent addition of new sessions to
+tunnels. Resetting tunnel->sock is done after l2tp_tunnel_closeall()
+returned, so that l2tp_session_add_to_tunnel() can safely take a
+reference on it when .acpt_newsess is true.
+
+The .acpt_newsess field is modified in l2tp_tunnel_closeall(), rather
+than in l2tp_tunnel_destruct(), so that it benefits all tunnel removal
+mechanisms. E.g. on UDP tunnels, a session could be added to a tunnel
+after l2tp_udp_encap_destroy() proceeded. This would prevent the tunnel
+from being removed because of the references held by this new session
+on the tunnel and its socket. Even though the session could be removed
+manually later on, this defeats the purpose of
+commit 9980d001cec8 ("l2tp: add udp encap socket destroy handler").
+
+Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |   41 ++++++++++++++++++++++++++++-------------
+ net/l2tp/l2tp_core.h |    4 ++++
+ 2 files changed, 32 insertions(+), 13 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -328,13 +328,21 @@ static int l2tp_session_add_to_tunnel(st
+       struct hlist_head *g_head;
+       struct hlist_head *head;
+       struct l2tp_net *pn;
++      int err;
+       head = l2tp_session_id_hash(tunnel, session->session_id);
+       write_lock_bh(&tunnel->hlist_lock);
++      if (!tunnel->acpt_newsess) {
++              err = -ENODEV;
++              goto err_tlock;
++      }
++
+       hlist_for_each_entry(session_walk, head, hlist)
+-              if (session_walk->session_id == session->session_id)
+-                      goto exist;
++              if (session_walk->session_id == session->session_id) {
++                      err = -EEXIST;
++                      goto err_tlock;
++              }
+       if (tunnel->version == L2TP_HDR_VER_3) {
+               pn = l2tp_pernet(tunnel->l2tp_net);
+@@ -342,12 +350,21 @@ static int l2tp_session_add_to_tunnel(st
+                                               session->session_id);
+               spin_lock_bh(&pn->l2tp_session_hlist_lock);
++
+               hlist_for_each_entry(session_walk, g_head, global_hlist)
+-                      if (session_walk->session_id == session->session_id)
+-                              goto exist_glob;
++                      if (session_walk->session_id == session->session_id) {
++                              err = -EEXIST;
++                              goto err_tlock_pnlock;
++                      }
++              l2tp_tunnel_inc_refcount(tunnel);
++              sock_hold(tunnel->sock);
+               hlist_add_head_rcu(&session->global_hlist, g_head);
++
+               spin_unlock_bh(&pn->l2tp_session_hlist_lock);
++      } else {
++              l2tp_tunnel_inc_refcount(tunnel);
++              sock_hold(tunnel->sock);
+       }
+       hlist_add_head(&session->hlist, head);
+@@ -355,12 +372,12 @@ static int l2tp_session_add_to_tunnel(st
+       return 0;
+-exist_glob:
++err_tlock_pnlock:
+       spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+-exist:
++err_tlock:
+       write_unlock_bh(&tunnel->hlist_lock);
+-      return -EEXIST;
++      return err;
+ }
+ /* Lookup a tunnel by id
+@@ -1246,7 +1263,6 @@ static void l2tp_tunnel_destruct(struct
+       /* Remove hooks into tunnel socket */
+       sk->sk_destruct = tunnel->old_sk_destruct;
+       sk->sk_user_data = NULL;
+-      tunnel->sock = NULL;
+       /* Remove the tunnel struct from the tunnel list */
+       pn = l2tp_pernet(tunnel->l2tp_net);
+@@ -1256,6 +1272,8 @@ static void l2tp_tunnel_destruct(struct
+       atomic_dec(&l2tp_tunnel_count);
+       l2tp_tunnel_closeall(tunnel);
++
++      tunnel->sock = NULL;
+       l2tp_tunnel_dec_refcount(tunnel);
+       /* Call the original destructor */
+@@ -1280,6 +1298,7 @@ void l2tp_tunnel_closeall(struct l2tp_tu
+                 tunnel->name);
+       write_lock_bh(&tunnel->hlist_lock);
++      tunnel->acpt_newsess = false;
+       for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
+ again:
+               hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+@@ -1583,6 +1602,7 @@ int l2tp_tunnel_create(struct net *net,
+       tunnel->magic = L2TP_TUNNEL_MAGIC;
+       sprintf(&tunnel->name[0], "tunl %u", tunnel_id);
+       rwlock_init(&tunnel->hlist_lock);
++      tunnel->acpt_newsess = true;
+       /* The net we belong to */
+       tunnel->l2tp_net = net;
+@@ -1832,11 +1852,6 @@ struct l2tp_session *l2tp_session_create
+                       return ERR_PTR(err);
+               }
+-              l2tp_tunnel_inc_refcount(tunnel);
+-
+-              /* Ensure tunnel socket isn't deleted */
+-              sock_hold(tunnel->sock);
+-
+               /* Ignore management session in session count value */
+               if (session->session_id != 0)
+                       atomic_inc(&l2tp_session_count);
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -162,6 +162,10 @@ struct l2tp_tunnel {
+       struct rcu_head rcu;
+       rwlock_t                hlist_lock;     /* protect session_hlist */
++      bool                    acpt_newsess;   /* Indicates whether this
++                                               * tunnel accepts new sessions.
++                                               * Protected by hlist_lock.
++                                               */
+       struct hlist_head       session_hlist[L2TP_HASH_SIZE];
+                                               /* hashed list of sessions,
+                                                * hashed by id */
diff --git a/queue-4.9/l2tp-protect-sock-pointer-of-struct-pppol2tp_session-with-rcu.patch b/queue-4.9/l2tp-protect-sock-pointer-of-struct-pppol2tp_session-with-rcu.patch
new file mode 100644 (file)
index 0000000..1485947
--- /dev/null
@@ -0,0 +1,390 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:36 +0100
+Subject: l2tp: protect sock pointer of struct pppol2tp_session with RCU
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-22-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit ee40fb2e1eb5bc0ddd3f2f83c6e39a454ef5a741 upstream.
+
+pppol2tp_session_create() registers sessions that can't have their
+corresponding socket initialised. This socket has to be created by
+userspace, then connected to the session by pppol2tp_connect().
+Therefore, we need to protect the pppol2tp socket pointer of L2TP
+sessions, so that it can safely be updated when userspace is connecting
+or closing the socket. This will eventually allow pppol2tp_connect()
+to avoid generating transient states while initialising its parts of the
+session.
+
+To this end, this patch protects the pppol2tp socket pointer using RCU.
+
+The pppol2tp socket pointer is still set in pppol2tp_connect(), but
+only once we know the function isn't going to fail. It's eventually
+reset by pppol2tp_release(), which now has to wait for a grace period
+to elapse before it can drop the last reference on the socket. This
+ensures that pppol2tp_session_get_sock() can safely grab a reference
+on the socket, even after ps->sk is reset to NULL but before this
+operation actually gets visible from pppol2tp_session_get_sock().
+
+The rest is standard RCU conversion: pppol2tp_recv(), which already
+runs in atomic context, is simply enclosed by rcu_read_lock() and
+rcu_read_unlock(), while other functions are converted to use
+pppol2tp_session_get_sock() followed by sock_put().
+pppol2tp_session_setsockopt() is a special case. It used to retrieve
+the pppol2tp socket from the L2TP session, which itself was retrieved
+from the pppol2tp socket. Therefore we can just avoid dereferencing
+ps->sk and directly use the original socket pointer instead.
+
+With all users of ps->sk now handling NULL and concurrent updates, the
+L2TP ->ref() and ->deref() callbacks aren't needed anymore. Therefore,
+rather than converting pppol2tp_session_sock_hold() and
+pppol2tp_session_sock_put(), we can just drop them.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c |  154 ++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 101 insertions(+), 53 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -122,8 +122,11 @@
+ struct pppol2tp_session {
+       int                     owner;          /* pid that opened the socket */
+-      struct sock             *sock;          /* Pointer to the session
++      struct mutex            sk_lock;        /* Protects .sk */
++      struct sock __rcu       *sk;            /* Pointer to the session
+                                                * PPPoX socket */
++      struct sock             *__sk;          /* Copy of .sk, for cleanup */
++      struct rcu_head         rcu;            /* For asynchronous release */
+       struct sock             *tunnel_sock;   /* Pointer to the tunnel UDP
+                                                * socket */
+       int                     flags;          /* accessed by PPPIOCGFLAGS.
+@@ -138,6 +141,24 @@ static const struct ppp_channel_ops pppo
+ static const struct proto_ops pppol2tp_ops;
++/* Retrieves the pppol2tp socket associated to a session.
++ * A reference is held on the returned socket, so this function must be paired
++ * with sock_put().
++ */
++static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session)
++{
++      struct pppol2tp_session *ps = l2tp_session_priv(session);
++      struct sock *sk;
++
++      rcu_read_lock();
++      sk = rcu_dereference(ps->sk);
++      if (sk)
++              sock_hold(sk);
++      rcu_read_unlock();
++
++      return sk;
++}
++
+ /* Helpers to obtain tunnel/session contexts from sockets.
+  */
+ static inline struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk)
+@@ -224,7 +245,8 @@ static void pppol2tp_recv(struct l2tp_se
+       /* If the socket is bound, send it in to PPP's input queue. Otherwise
+        * queue it on the session socket.
+        */
+-      sk = ps->sock;
++      rcu_read_lock();
++      sk = rcu_dereference(ps->sk);
+       if (sk == NULL)
+               goto no_sock;
+@@ -247,30 +269,16 @@ static void pppol2tp_recv(struct l2tp_se
+                       kfree_skb(skb);
+               }
+       }
++      rcu_read_unlock();
+       return;
+ no_sock:
++      rcu_read_unlock();
+       l2tp_info(session, L2TP_MSG_DATA, "%s: no socket\n", session->name);
+       kfree_skb(skb);
+ }
+-static void pppol2tp_session_sock_hold(struct l2tp_session *session)
+-{
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
+-
+-      if (ps->sock)
+-              sock_hold(ps->sock);
+-}
+-
+-static void pppol2tp_session_sock_put(struct l2tp_session *session)
+-{
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
+-
+-      if (ps->sock)
+-              sock_put(ps->sock);
+-}
+-
+ /************************************************************************
+  * Transmit handling
+  ***********************************************************************/
+@@ -431,14 +439,16 @@ abort:
+  */
+ static void pppol2tp_session_close(struct l2tp_session *session)
+ {
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
+-      struct sock *sk = ps->sock;
+-      struct socket *sock = sk->sk_socket;
++      struct sock *sk;
+       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+-      if (sock)
+-              inet_shutdown(sock, SEND_SHUTDOWN);
++      sk = pppol2tp_session_get_sock(session);
++      if (sk) {
++              if (sk->sk_socket)
++                      inet_shutdown(sk->sk_socket, SEND_SHUTDOWN);
++              sock_put(sk);
++      }
+       /* Don't let the session go away before our socket does */
+       l2tp_session_inc_refcount(session);
+@@ -461,6 +471,14 @@ static void pppol2tp_session_destruct(st
+       }
+ }
++static void pppol2tp_put_sk(struct rcu_head *head)
++{
++      struct pppol2tp_session *ps;
++
++      ps = container_of(head, typeof(*ps), rcu);
++      sock_put(ps->__sk);
++}
++
+ /* Called when the PPPoX socket (session) is closed.
+  */
+ static int pppol2tp_release(struct socket *sock)
+@@ -486,11 +504,24 @@ static int pppol2tp_release(struct socke
+       session = pppol2tp_sock_to_session(sk);
+-      /* Purge any queued data */
+       if (session != NULL) {
++              struct pppol2tp_session *ps;
++
+               __l2tp_session_unhash(session);
+               l2tp_session_queue_purge(session);
+-              sock_put(sk);
++
++              ps = l2tp_session_priv(session);
++              mutex_lock(&ps->sk_lock);
++              ps->__sk = rcu_dereference_protected(ps->sk,
++                                                   lockdep_is_held(&ps->sk_lock));
++              RCU_INIT_POINTER(ps->sk, NULL);
++              mutex_unlock(&ps->sk_lock);
++              call_rcu(&ps->rcu, pppol2tp_put_sk);
++
++              /* Rely on the sock_put() call at the end of the function for
++               * dropping the reference held by pppol2tp_sock_to_session().
++               * The last reference will be dropped by pppol2tp_put_sk().
++               */
+       }
+       release_sock(sk);
+@@ -557,12 +588,14 @@ out:
+ static void pppol2tp_show(struct seq_file *m, void *arg)
+ {
+       struct l2tp_session *session = arg;
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
++      struct sock *sk;
++
++      sk = pppol2tp_session_get_sock(session);
++      if (sk) {
++              struct pppox_sock *po = pppox_sk(sk);
+-      if (ps) {
+-              struct pppox_sock *po = pppox_sk(ps->sock);
+-              if (po)
+-                      seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
++              seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
++              sock_put(sk);
+       }
+ }
+ #endif
+@@ -700,13 +733,17 @@ static int pppol2tp_connect(struct socke
+               /* Using a pre-existing session is fine as long as it hasn't
+                * been connected yet.
+                */
+-              if (ps->sock) {
++              mutex_lock(&ps->sk_lock);
++              if (rcu_dereference_protected(ps->sk,
++                                            lockdep_is_held(&ps->sk_lock))) {
++                      mutex_unlock(&ps->sk_lock);
+                       error = -EEXIST;
+                       goto end;
+               }
+               /* consistency checks */
+               if (ps->tunnel_sock != tunnel->sock) {
++                      mutex_unlock(&ps->sk_lock);
+                       error = -EEXIST;
+                       goto end;
+               }
+@@ -723,19 +760,21 @@ static int pppol2tp_connect(struct socke
+                       goto end;
+               }
++              ps = l2tp_session_priv(session);
++              mutex_init(&ps->sk_lock);
+               l2tp_session_inc_refcount(session);
++
++              mutex_lock(&ps->sk_lock);
+               error = l2tp_session_register(session, tunnel);
+               if (error < 0) {
++                      mutex_unlock(&ps->sk_lock);
+                       kfree(session);
+                       goto end;
+               }
+               drop_refcnt = true;
+       }
+-      /* Associate session with its PPPoL2TP socket */
+-      ps = l2tp_session_priv(session);
+       ps->owner            = current->pid;
+-      ps->sock             = sk;
+       ps->tunnel_sock = tunnel->sock;
+       session->recv_skb       = pppol2tp_recv;
+@@ -744,12 +783,6 @@ static int pppol2tp_connect(struct socke
+       session->show           = pppol2tp_show;
+ #endif
+-      /* We need to know each time a skb is dropped from the reorder
+-       * queue.
+-       */
+-      session->ref = pppol2tp_session_sock_hold;
+-      session->deref = pppol2tp_session_sock_put;
+-
+       /* If PMTU discovery was enabled, use the MTU that was discovered */
+       dst = sk_dst_get(tunnel->sock);
+       if (dst != NULL) {
+@@ -783,12 +816,17 @@ static int pppol2tp_connect(struct socke
+       po->chan.mtu     = session->mtu;
+       error = ppp_register_net_channel(sock_net(sk), &po->chan);
+-      if (error)
++      if (error) {
++              mutex_unlock(&ps->sk_lock);
+               goto end;
++      }
+ out_no_ppp:
+       /* This is how we get the session context from the socket. */
+       sk->sk_user_data = session;
++      rcu_assign_pointer(ps->sk, sk);
++      mutex_unlock(&ps->sk_lock);
++
+       sk->sk_state = PPPOX_CONNECTED;
+       l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
+                 session->name);
+@@ -834,6 +872,7 @@ static int pppol2tp_session_create(struc
+       }
+       ps = l2tp_session_priv(session);
++      mutex_init(&ps->sk_lock);
+       ps->tunnel_sock = tunnel->sock;
+       error = l2tp_session_register(session, tunnel);
+@@ -1005,12 +1044,10 @@ static int pppol2tp_session_ioctl(struct
+                "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
+                session->name, cmd, arg);
+-      sk = ps->sock;
++      sk = pppol2tp_session_get_sock(session);
+       if (!sk)
+               return -EBADR;
+-      sock_hold(sk);
+-
+       switch (cmd) {
+       case SIOCGIFMTU:
+               err = -ENXIO;
+@@ -1286,7 +1323,6 @@ static int pppol2tp_session_setsockopt(s
+                                      int optname, int val)
+ {
+       int err = 0;
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
+       switch (optname) {
+       case PPPOL2TP_SO_RECVSEQ:
+@@ -1307,8 +1343,8 @@ static int pppol2tp_session_setsockopt(s
+               }
+               session->send_seq = val ? -1 : 0;
+               {
+-                      struct sock *ssk      = ps->sock;
+-                      struct pppox_sock *po = pppox_sk(ssk);
++                      struct pppox_sock *po = pppox_sk(sk);
++
+                       po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
+                               PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+               }
+@@ -1644,8 +1680,9 @@ static void pppol2tp_seq_session_show(st
+ {
+       struct l2tp_session *session = v;
+       struct l2tp_tunnel *tunnel = session->tunnel;
+-      struct pppol2tp_session *ps = l2tp_session_priv(session);
+-      struct pppox_sock *po = pppox_sk(ps->sock);
++      unsigned char state;
++      char user_data_ok;
++      struct sock *sk;
+       u32 ip = 0;
+       u16 port = 0;
+@@ -1655,6 +1692,15 @@ static void pppol2tp_seq_session_show(st
+               port = ntohs(inet->inet_sport);
+       }
++      sk = pppol2tp_session_get_sock(session);
++      if (sk) {
++              state = sk->sk_state;
++              user_data_ok = (session == sk->sk_user_data) ? 'Y' : 'N';
++      } else {
++              state = 0;
++              user_data_ok = 'N';
++      }
++
+       seq_printf(m, "  SESSION '%s' %08X/%d %04X/%04X -> "
+                  "%04X/%04X %d %c\n",
+                  session->name, ip, port,
+@@ -1662,9 +1708,7 @@ static void pppol2tp_seq_session_show(st
+                  session->session_id,
+                  tunnel->peer_tunnel_id,
+                  session->peer_session_id,
+-                 ps->sock->sk_state,
+-                 (session == ps->sock->sk_user_data) ?
+-                 'Y' : 'N');
++                 state, user_data_ok);
+       seq_printf(m, "   %d/%d/%c/%c/%s %08x %u\n",
+                  session->mtu, session->mru,
+                  session->recv_seq ? 'R' : '-',
+@@ -1681,8 +1725,12 @@ static void pppol2tp_seq_session_show(st
+                  atomic_long_read(&session->stats.rx_bytes),
+                  atomic_long_read(&session->stats.rx_errors));
+-      if (po)
++      if (sk) {
++              struct pppox_sock *po = pppox_sk(sk);
++
+               seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
++              sock_put(sk);
++      }
+ }
+ static int pppol2tp_seq_show(struct seq_file *m, void *v)
diff --git a/queue-4.9/l2tp-remove-l2tp_session_find.patch b/queue-4.9/l2tp-remove-l2tp_session_find.patch
new file mode 100644 (file)
index 0000000..58eed72
--- /dev/null
@@ -0,0 +1,102 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:22 +0100
+Subject: l2tp: remove l2tp_session_find()
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-8-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 55a3ce3b9d98f752df9e2cfb1cba7e715522428a upstream.
+
+This function isn't used anymore.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c |   51 +--------------------------------------------------
+ net/l2tp/l2tp_core.h |    3 ---
+ 2 files changed, 1 insertion(+), 53 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -216,27 +216,6 @@ static void l2tp_tunnel_sock_put(struct
+       sock_put(sk);
+ }
+-/* Lookup a session by id in the global session list
+- */
+-static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)
+-{
+-      struct l2tp_net *pn = l2tp_pernet(net);
+-      struct hlist_head *session_list =
+-              l2tp_session_id_hash_2(pn, session_id);
+-      struct l2tp_session *session;
+-
+-      rcu_read_lock_bh();
+-      hlist_for_each_entry_rcu(session, session_list, global_hlist) {
+-              if (session->session_id == session_id) {
+-                      rcu_read_unlock_bh();
+-                      return session;
+-              }
+-      }
+-      rcu_read_unlock_bh();
+-
+-      return NULL;
+-}
+-
+ /* Session hash list.
+  * The session_id SHOULD be random according to RFC2661, but several
+  * L2TP implementations (Cisco and Microsoft) use incrementing
+@@ -249,35 +228,7 @@ l2tp_session_id_hash(struct l2tp_tunnel
+       return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
+ }
+-/* Lookup a session by id
+- */
+-struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id)
+-{
+-      struct hlist_head *session_list;
+-      struct l2tp_session *session;
+-
+-      /* In L2TPv3, session_ids are unique over all tunnels and we
+-       * sometimes need to look them up before we know the
+-       * tunnel.
+-       */
+-      if (tunnel == NULL)
+-              return l2tp_session_find_2(net, session_id);
+-
+-      session_list = l2tp_session_id_hash(tunnel, session_id);
+-      read_lock_bh(&tunnel->hlist_lock);
+-      hlist_for_each_entry(session, session_list, hlist) {
+-              if (session->session_id == session_id) {
+-                      read_unlock_bh(&tunnel->hlist_lock);
+-                      return session;
+-              }
+-      }
+-      read_unlock_bh(&tunnel->hlist_lock);
+-
+-      return NULL;
+-}
+-EXPORT_SYMBOL_GPL(l2tp_session_find);
+-
+-/* Like l2tp_session_find() but takes a reference on the returned session.
++/* Lookup a session. A new reference is held on the returned session.
+  * Optionally calls session->ref() too if do_ref is true.
+  */
+ struct l2tp_session *l2tp_session_get(struct net *net,
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -234,9 +234,6 @@ out:
+ struct l2tp_session *l2tp_session_get(struct net *net,
+                                     struct l2tp_tunnel *tunnel,
+                                     u32 session_id, bool do_ref);
+-struct l2tp_session *l2tp_session_find(struct net *net,
+-                                     struct l2tp_tunnel *tunnel,
+-                                     u32 session_id);
+ struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
+                                         bool do_ref);
+ struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
diff --git a/queue-4.9/l2tp-remove-useless-duplicate-session-detection-in-l2tp_netlink.patch b/queue-4.9/l2tp-remove-useless-duplicate-session-detection-in-l2tp_netlink.patch
new file mode 100644 (file)
index 0000000..6b0f0cd
--- /dev/null
@@ -0,0 +1,42 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:21 +0100
+Subject: l2tp: remove useless duplicate session detection in l2tp_netlink
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, Guillaume Nault <g.nault@alphalink.fr>,  "David S . Miller" <davem@davemloft.net>, Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-7-gprocida@google.com>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit af87ae465abdc070de0dc35d6c6a9e7a8cd82987 upstream.
+
+There's no point in checking for duplicate sessions at the beginning of
+l2tp_nl_cmd_session_create(); the ->session_create() callbacks already
+return -EEXIST when the session already exists.
+
+Furthermore, even if l2tp_session_find() returns NULL, a new session
+might be created right after the test. So relying on ->session_create()
+to avoid duplicate session is the only sane behaviour.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_netlink.c |    5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/net/l2tp/l2tp_netlink.c
++++ b/net/l2tp/l2tp_netlink.c
+@@ -513,11 +513,6 @@ static int l2tp_nl_cmd_session_create(st
+               goto out;
+       }
+       session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
+-      session = l2tp_session_find(net, tunnel, session_id);
+-      if (session) {
+-              ret = -EEXIST;
+-              goto out;
+-      }
+       if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) {
+               ret = -EINVAL;
diff --git a/queue-4.9/net-l2tp-deprecate-pppol2tp_msg_-in-favour-of-l2tp_msg_.patch b/queue-4.9/net-l2tp-deprecate-pppol2tp_msg_-in-favour-of-l2tp_msg_.patch
new file mode 100644 (file)
index 0000000..fae773f
--- /dev/null
@@ -0,0 +1,72 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:17 +0100
+Subject: net: l2tp: deprecate PPPOL2TP_MSG_* in favour of L2TP_MSG_*
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, "Asbjørn Sloth Tønnesen" <asbjorn@asbjorn.st>, "David S . Miller" <davem@davemloft.net>, "Giuliano Procida" <gprocida@google.com>
+Message-ID: <20200521233937.175182-3-gprocida@google.com>
+
+From: Asbjørn Sloth Tønnesen <asbjorn@asbjorn.st>
+
+commit 47c3e7783be4e142b861d34b5c2e223330b05d8a upstream.
+
+PPPOL2TP_MSG_* and L2TP_MSG_* are duplicates, and are being used
+interchangeably in the kernel, so let's standardize on L2TP_MSG_*
+internally, and keep PPPOL2TP_MSG_* defined in UAPI for compatibility.
+
+Signed-off-by: Asbjoern Sloth Toennesen <asbjorn@asbjorn.st>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/networking/l2tp.txt |    8 ++++----
+ include/uapi/linux/if_pppol2tp.h  |   13 ++++++-------
+ 2 files changed, 10 insertions(+), 11 deletions(-)
+
+--- a/Documentation/networking/l2tp.txt
++++ b/Documentation/networking/l2tp.txt
+@@ -177,10 +177,10 @@ setsockopt on the PPPoX socket to set a
+ The following debug mask bits are available:
+-PPPOL2TP_MSG_DEBUG    verbose debug (if compiled in)
+-PPPOL2TP_MSG_CONTROL  userspace - kernel interface
+-PPPOL2TP_MSG_SEQ      sequence numbers handling
+-PPPOL2TP_MSG_DATA     data packets
++L2TP_MSG_DEBUG    verbose debug (if compiled in)
++L2TP_MSG_CONTROL  userspace - kernel interface
++L2TP_MSG_SEQ      sequence numbers handling
++L2TP_MSG_DATA     data packets
+ If enabled, files under a l2tp debugfs directory can be used to dump
+ kernel state about L2TP tunnels and sessions. To access it, the
+--- a/include/uapi/linux/if_pppol2tp.h
++++ b/include/uapi/linux/if_pppol2tp.h
+@@ -18,6 +18,7 @@
+ #include <linux/types.h>
+ #include <linux/in.h>
+ #include <linux/in6.h>
++#include <linux/l2tp.h>
+ /* Structure used to connect() the socket to a particular tunnel UDP
+  * socket over IPv4.
+@@ -90,14 +91,12 @@ enum {
+       PPPOL2TP_SO_REORDERTO   = 5,
+ };
+-/* Debug message categories for the DEBUG socket option */
++/* Debug message categories for the DEBUG socket option (deprecated) */
+ enum {
+-      PPPOL2TP_MSG_DEBUG      = (1 << 0),     /* verbose debug (if
+-                                               * compiled in) */
+-      PPPOL2TP_MSG_CONTROL    = (1 << 1),     /* userspace - kernel
+-                                               * interface */
+-      PPPOL2TP_MSG_SEQ        = (1 << 2),     /* sequence numbers */
+-      PPPOL2TP_MSG_DATA       = (1 << 3),     /* data packets */
++      PPPOL2TP_MSG_DEBUG      = L2TP_MSG_DEBUG,
++      PPPOL2TP_MSG_CONTROL    = L2TP_MSG_CONTROL,
++      PPPOL2TP_MSG_SEQ        = L2TP_MSG_SEQ,
++      PPPOL2TP_MSG_DATA       = L2TP_MSG_DATA,
+ };
diff --git a/queue-4.9/net-l2tp-export-debug-flags-to-uapi.patch b/queue-4.9/net-l2tp-export-debug-flags-to-uapi.patch
new file mode 100644 (file)
index 0000000..28d2756
--- /dev/null
@@ -0,0 +1,76 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:16 +0100
+Subject: net: l2tp: export debug flags to UAPI
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, "Asbjørn Sloth Tønnesen" <asbjorn@asbjorn.st>, "David S . Miller" <davem@davemloft.net>, "Giuliano Procida" <gprocida@google.com>
+Message-ID: <20200521233937.175182-2-gprocida@google.com>
+
+From: Asbjørn Sloth Tønnesen <asbjorn@asbjorn.st>
+
+commit 41c43fbee68f4f9a2a9675d83bca91c77862d7f0 upstream.
+
+Move the L2TP_MSG_* definitions to UAPI, as it is part of
+the netlink API.
+
+Signed-off-by: Asbjoern Sloth Toennesen <asbjorn@asbjorn.st>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/uapi/linux/l2tp.h |   17 ++++++++++++++++-
+ net/l2tp/l2tp_core.h      |   10 ----------
+ 2 files changed, 16 insertions(+), 11 deletions(-)
+
+--- a/include/uapi/linux/l2tp.h
++++ b/include/uapi/linux/l2tp.h
+@@ -108,7 +108,7 @@ enum {
+       L2TP_ATTR_VLAN_ID,              /* u16 */
+       L2TP_ATTR_COOKIE,               /* 0, 4 or 8 bytes */
+       L2TP_ATTR_PEER_COOKIE,          /* 0, 4 or 8 bytes */
+-      L2TP_ATTR_DEBUG,                /* u32 */
++      L2TP_ATTR_DEBUG,                /* u32, enum l2tp_debug_flags */
+       L2TP_ATTR_RECV_SEQ,             /* u8 */
+       L2TP_ATTR_SEND_SEQ,             /* u8 */
+       L2TP_ATTR_LNS_MODE,             /* u8 */
+@@ -175,6 +175,21 @@ enum l2tp_seqmode {
+       L2TP_SEQ_ALL = 2,
+ };
++/**
++ * enum l2tp_debug_flags - debug message categories for L2TP tunnels/sessions
++ *
++ * @L2TP_MSG_DEBUG: verbose debug (if compiled in)
++ * @L2TP_MSG_CONTROL: userspace - kernel interface
++ * @L2TP_MSG_SEQ: sequence numbers
++ * @L2TP_MSG_DATA: data packets
++ */
++enum l2tp_debug_flags {
++      L2TP_MSG_DEBUG          = (1 << 0),
++      L2TP_MSG_CONTROL        = (1 << 1),
++      L2TP_MSG_SEQ            = (1 << 2),
++      L2TP_MSG_DATA           = (1 << 3),
++};
++
+ /*
+  * NETLINK_GENERIC related info
+  */
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -23,16 +23,6 @@
+ #define L2TP_HASH_BITS_2      8
+ #define L2TP_HASH_SIZE_2      (1 << L2TP_HASH_BITS_2)
+-/* Debug message categories for the DEBUG socket option */
+-enum {
+-      L2TP_MSG_DEBUG          = (1 << 0),     /* verbose debug (if
+-                                               * compiled in) */
+-      L2TP_MSG_CONTROL        = (1 << 1),     /* userspace - kernel
+-                                               * interface */
+-      L2TP_MSG_SEQ            = (1 << 2),     /* sequence numbers */
+-      L2TP_MSG_DATA           = (1 << 3),     /* data packets */
+-};
+-
+ struct sk_buff;
+ struct l2tp_stats {
diff --git a/queue-4.9/net-l2tp-ppp-change-pppol2tp_msg_-l2tp_msg_.patch b/queue-4.9/net-l2tp-ppp-change-pppol2tp_msg_-l2tp_msg_.patch
new file mode 100644 (file)
index 0000000..19ee515
--- /dev/null
@@ -0,0 +1,253 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:18 +0100
+Subject: net: l2tp: ppp: change PPPOL2TP_MSG_* => L2TP_MSG_*
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, "Asbjørn Sloth Tønnesen" <asbjorn@asbjorn.st>, "David S . Miller" <davem@davemloft.net>, "Giuliano Procida" <gprocida@google.com>
+Message-ID: <20200521233937.175182-4-gprocida@google.com>
+
+From: Asbjørn Sloth Tønnesen <asbjorn@asbjorn.st>
+
+commit fba40c632c6473fa89660e870a6042c0fe733f8c upstream.
+
+Signed-off-by: Asbjoern Sloth Toennesen <asbjorn@asbjorn.st>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c |   54 ++++++++++++++++++++++++++--------------------------
+ 1 file changed, 27 insertions(+), 27 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -231,14 +231,14 @@ static void pppol2tp_recv(struct l2tp_se
+       if (sk->sk_state & PPPOX_BOUND) {
+               struct pppox_sock *po;
+-              l2tp_dbg(session, PPPOL2TP_MSG_DATA,
++              l2tp_dbg(session, L2TP_MSG_DATA,
+                        "%s: recv %d byte data frame, passing to ppp\n",
+                        session->name, data_len);
+               po = pppox_sk(sk);
+               ppp_input(&po->chan, skb);
+       } else {
+-              l2tp_dbg(session, PPPOL2TP_MSG_DATA,
++              l2tp_dbg(session, L2TP_MSG_DATA,
+                        "%s: recv %d byte data frame, passing to L2TP socket\n",
+                        session->name, data_len);
+@@ -251,7 +251,7 @@ static void pppol2tp_recv(struct l2tp_se
+       return;
+ no_sock:
+-      l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: no socket\n", session->name);
++      l2tp_info(session, L2TP_MSG_DATA, "%s: no socket\n", session->name);
+       kfree_skb(skb);
+ }
+@@ -782,7 +782,7 @@ out_no_ppp:
+       /* This is how we get the session context from the socket. */
+       sk->sk_user_data = session;
+       sk->sk_state = PPPOX_CONNECTED;
+-      l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: created\n",
++      l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
+                 session->name);
+ end:
+@@ -833,7 +833,7 @@ static int pppol2tp_session_create(struc
+       ps = l2tp_session_priv(session);
+       ps->tunnel_sock = tunnel->sock;
+-      l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: created\n",
++      l2tp_info(session, L2TP_MSG_CONTROL, "%s: created\n",
+                 session->name);
+       error = 0;
+@@ -995,7 +995,7 @@ static int pppol2tp_session_ioctl(struct
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       struct pppol2tp_ioc_stats stats;
+-      l2tp_dbg(session, PPPOL2TP_MSG_CONTROL,
++      l2tp_dbg(session, L2TP_MSG_CONTROL,
+                "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
+                session->name, cmd, arg);
+@@ -1018,7 +1018,7 @@ static int pppol2tp_session_ioctl(struct
+               if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq)))
+                       break;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get mtu=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: get mtu=%d\n",
+                         session->name, session->mtu);
+               err = 0;
+               break;
+@@ -1034,7 +1034,7 @@ static int pppol2tp_session_ioctl(struct
+               session->mtu = ifr.ifr_mtu;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set mtu=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: set mtu=%d\n",
+                         session->name, session->mtu);
+               err = 0;
+               break;
+@@ -1048,7 +1048,7 @@ static int pppol2tp_session_ioctl(struct
+               if (put_user(session->mru, (int __user *) arg))
+                       break;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get mru=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: get mru=%d\n",
+                         session->name, session->mru);
+               err = 0;
+               break;
+@@ -1063,7 +1063,7 @@ static int pppol2tp_session_ioctl(struct
+                       break;
+               session->mru = val;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set mru=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: set mru=%d\n",
+                         session->name, session->mru);
+               err = 0;
+               break;
+@@ -1073,7 +1073,7 @@ static int pppol2tp_session_ioctl(struct
+               if (put_user(ps->flags, (int __user *) arg))
+                       break;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get flags=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: get flags=%d\n",
+                         session->name, ps->flags);
+               err = 0;
+               break;
+@@ -1083,7 +1083,7 @@ static int pppol2tp_session_ioctl(struct
+               if (get_user(val, (int __user *) arg))
+                       break;
+               ps->flags = val;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set flags=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: set flags=%d\n",
+                         session->name, ps->flags);
+               err = 0;
+               break;
+@@ -1100,7 +1100,7 @@ static int pppol2tp_session_ioctl(struct
+               if (copy_to_user((void __user *) arg, &stats,
+                                sizeof(stats)))
+                       break;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get L2TP stats\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: get L2TP stats\n",
+                         session->name);
+               err = 0;
+               break;
+@@ -1128,7 +1128,7 @@ static int pppol2tp_tunnel_ioctl(struct
+       struct sock *sk;
+       struct pppol2tp_ioc_stats stats;
+-      l2tp_dbg(tunnel, PPPOL2TP_MSG_CONTROL,
++      l2tp_dbg(tunnel, L2TP_MSG_CONTROL,
+                "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n",
+                tunnel->name, cmd, arg);
+@@ -1171,7 +1171,7 @@ static int pppol2tp_tunnel_ioctl(struct
+                       err = -EFAULT;
+                       break;
+               }
+-              l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: get L2TP stats\n",
++              l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: get L2TP stats\n",
+                         tunnel->name);
+               err = 0;
+               break;
+@@ -1261,7 +1261,7 @@ static int pppol2tp_tunnel_setsockopt(st
+       switch (optname) {
+       case PPPOL2TP_SO_DEBUG:
+               tunnel->debug = val;
+-              l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: set debug=%x\n",
++              l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: set debug=%x\n",
+                         tunnel->name, tunnel->debug);
+               break;
+@@ -1289,7 +1289,7 @@ static int pppol2tp_session_setsockopt(s
+                       break;
+               }
+               session->recv_seq = val ? -1 : 0;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: set recv_seq=%d\n",
+                         session->name, session->recv_seq);
+               break;
+@@ -1307,7 +1307,7 @@ static int pppol2tp_session_setsockopt(s
+                               PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+               }
+               l2tp_session_set_header_len(session, session->tunnel->version);
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: set send_seq=%d\n",
+                         session->name, session->send_seq);
+               break;
+@@ -1318,20 +1318,20 @@ static int pppol2tp_session_setsockopt(s
+                       break;
+               }
+               session->lns_mode = val ? -1 : 0;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: set lns_mode=%d\n",
+                         session->name, session->lns_mode);
+               break;
+       case PPPOL2TP_SO_DEBUG:
+               session->debug = val;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set debug=%x\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: set debug=%x\n",
+                         session->name, session->debug);
+               break;
+       case PPPOL2TP_SO_REORDERTO:
+               session->reorder_timeout = msecs_to_jiffies(val);
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: set reorder_timeout=%d\n",
+                         session->name, session->reorder_timeout);
+               break;
+@@ -1412,7 +1412,7 @@ static int pppol2tp_tunnel_getsockopt(st
+       switch (optname) {
+       case PPPOL2TP_SO_DEBUG:
+               *val = tunnel->debug;
+-              l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: get debug=%x\n",
++              l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: get debug=%x\n",
+                         tunnel->name, tunnel->debug);
+               break;
+@@ -1435,31 +1435,31 @@ static int pppol2tp_session_getsockopt(s
+       switch (optname) {
+       case PPPOL2TP_SO_RECVSEQ:
+               *val = session->recv_seq;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: get recv_seq=%d\n", session->name, *val);
+               break;
+       case PPPOL2TP_SO_SENDSEQ:
+               *val = session->send_seq;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: get send_seq=%d\n", session->name, *val);
+               break;
+       case PPPOL2TP_SO_LNSMODE:
+               *val = session->lns_mode;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: get lns_mode=%d\n", session->name, *val);
+               break;
+       case PPPOL2TP_SO_DEBUG:
+               *val = session->debug;
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get debug=%d\n",
++              l2tp_info(session, L2TP_MSG_CONTROL, "%s: get debug=%d\n",
+                         session->name, *val);
+               break;
+       case PPPOL2TP_SO_REORDERTO:
+               *val = (int) jiffies_to_msecs(session->reorder_timeout);
+-              l2tp_info(session, PPPOL2TP_MSG_CONTROL,
++              l2tp_info(session, L2TP_MSG_CONTROL,
+                         "%s: get reorder_timeout=%d\n", session->name, *val);
+               break;
diff --git a/queue-4.9/new-kernel-function-to-get-ip-overhead-on-a-socket.patch b/queue-4.9/new-kernel-function-to-get-ip-overhead-on-a-socket.patch
new file mode 100644 (file)
index 0000000..4805350
--- /dev/null
@@ -0,0 +1,94 @@
+From foo@baz Fri 22 May 2020 02:11:00 PM CEST
+From: Giuliano Procida <gprocida@google.com>
+Date: Fri, 22 May 2020 00:39:19 +0100
+Subject: New kernel function to get IP overhead on a socket.
+To: greg@kroah.com
+Cc: stable@vger.kernel.org, "R. Parameswaran" <parameswaran.r7@gmail.com>,  "R . Parameswaran" <rparames@brocade.com>, "David S . Miller" <davem@davemloft.net>,  Giuliano Procida <gprocida@google.com>
+Message-ID: <20200521233937.175182-5-gprocida@google.com>
+
+From: "R. Parameswaran" <parameswaran.r7@gmail.com>
+
+commit 113c3075931a334f899008f6c753abe70a3a9323 upstream.
+
+A new function, kernel_sock_ip_overhead(), is provided
+to calculate the cumulative overhead imposed by the IP
+Header and IP options, if any, on a socket's payload.
+The new function returns an overhead of zero for sockets
+that do not belong to the IPv4 or IPv6 address families.
+This is used in the L2TP code path to compute the
+total outer IP overhead on the L2TP tunnel socket when
+calculating the default MTU for Ethernet pseudowires.
+
+Signed-off-by: R. Parameswaran <rparames@brocade.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Giuliano Procida <gprocida@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/net.h |    3 +++
+ net/socket.c        |   46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/include/linux/net.h
++++ b/include/linux/net.h
+@@ -298,6 +298,9 @@ int kernel_sendpage(struct socket *sock,
+ int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
+ int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
++/* Following routine returns the IP overhead imposed by a socket.  */
++u32 kernel_sock_ip_overhead(struct sock *sk);
++
+ #define MODULE_ALIAS_NETPROTO(proto) \
+       MODULE_ALIAS("net-pf-" __stringify(proto))
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -3321,3 +3321,49 @@ int kernel_sock_shutdown(struct socket *
+       return sock->ops->shutdown(sock, how);
+ }
+ EXPORT_SYMBOL(kernel_sock_shutdown);
++
++/* This routine returns the IP overhead imposed by a socket i.e.
++ * the length of the underlying IP header, depending on whether
++ * this is an IPv4 or IPv6 socket and the length from IP options turned
++ * on at the socket.
++ */
++u32 kernel_sock_ip_overhead(struct sock *sk)
++{
++      struct inet_sock *inet;
++      struct ip_options_rcu *opt;
++      u32 overhead = 0;
++      bool owned_by_user;
++#if IS_ENABLED(CONFIG_IPV6)
++      struct ipv6_pinfo *np;
++      struct ipv6_txoptions *optv6 = NULL;
++#endif /* IS_ENABLED(CONFIG_IPV6) */
++
++      if (!sk)
++              return overhead;
++
++      owned_by_user = sock_owned_by_user(sk);
++      switch (sk->sk_family) {
++      case AF_INET:
++              inet = inet_sk(sk);
++              overhead += sizeof(struct iphdr);
++              opt = rcu_dereference_protected(inet->inet_opt,
++                                              owned_by_user);
++              if (opt)
++                      overhead += opt->opt.optlen;
++              return overhead;
++#if IS_ENABLED(CONFIG_IPV6)
++      case AF_INET6:
++              np = inet6_sk(sk);
++              overhead += sizeof(struct ipv6hdr);
++              if (np)
++                      optv6 = rcu_dereference_protected(np->opt,
++                                                        owned_by_user);
++              if (optv6)
++                      overhead += (optv6->opt_flen + optv6->opt_nflen);
++              return overhead;
++#endif /* IS_ENABLED(CONFIG_IPV6) */
++      default: /* Returns 0 overhead if the socket is not ipv4 or ipv6 */
++              return overhead;
++      }
++}
++EXPORT_SYMBOL(kernel_sock_ip_overhead);
index 7243a18dd687b7fab7a70e97b6e66b62ea10bcd3..86e9848cf8028c91c240d5f637a91465d4bb4f85 100644 (file)
@@ -24,3 +24,25 @@ padata-initialize-pd-cpu-with-effective-cpumask.patch
 padata-purge-get_cpu-and-reorder_via_wq-from-padata_.patch
 arm64-fix-the-flush_icache_range-arguments-in-machin.patch
 watchdog-fix-the-race-between-the-release-of-watchdog_core_data-and-cdev.patch
+net-l2tp-export-debug-flags-to-uapi.patch
+net-l2tp-deprecate-pppol2tp_msg_-in-favour-of-l2tp_msg_.patch
+net-l2tp-ppp-change-pppol2tp_msg_-l2tp_msg_.patch
+new-kernel-function-to-get-ip-overhead-on-a-socket.patch
+l2tp-adjust-intf-mtu-add-underlay-l3-l2-hdrs.patch
+l2tp-remove-useless-duplicate-session-detection-in-l2tp_netlink.patch
+l2tp-remove-l2tp_session_find.patch
+l2tp-define-parameters-of-l2tp_session_get-as-const.patch
+l2tp-define-parameters-of-l2tp_tunnel_find-as-const.patch
+l2tp-initialise-session-s-refcount-before-making-it-reachable.patch
+l2tp-hold-tunnel-while-looking-up-sessions-in-l2tp_netlink.patch
+l2tp-hold-tunnel-while-processing-genl-delete-command.patch
+l2tp-hold-tunnel-while-handling-genl-tunnel-updates.patch
+l2tp-hold-tunnel-while-handling-genl-tunnel_get-commands.patch
+l2tp-hold-tunnel-used-while-creating-sessions-with-netlink.patch
+l2tp-prevent-creation-of-sessions-on-terminated-tunnels.patch
+l2tp-pass-tunnel-pointer-to-session_create.patch
+l2tp-fix-l2tp_eth-module-loading.patch
+l2tp-don-t-register-sessions-in-l2tp_session_create.patch
+l2tp-initialise-l2tp_eth-sessions-before-registering-them.patch
+l2tp-protect-sock-pointer-of-struct-pppol2tp_session-with-rcu.patch
+l2tp-initialise-ppp-sessions-before-registering-them.patch