--- /dev/null
+From 4ac36a4adaf80013a60013d6f829f5863d5d0e05 Mon Sep 17 00:00:00 2001
+From: "phil.turnbull@oracle.com" <phil.turnbull@oracle.com>
+Date: Tue, 26 Jul 2016 15:14:35 -0400
+Subject: l2tp: Correctly return -EBADF from pppol2tp_getname.
+
+From: phil.turnbull@oracle.com <phil.turnbull@oracle.com>
+
+commit 4ac36a4adaf80013a60013d6f829f5863d5d0e05 upstream.
+
+If 'tunnel' is NULL we should return -EBADF but the 'end_put_sess' path
+unconditionally sets 'error' back to zero. Rework the error path so it
+more closely matches pppol2tp_sendmsg.
+
+Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
+Signed-off-by: Phil Turnbull <phil.turnbull@oracle.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/l2tp/l2tp_ppp.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -889,10 +889,8 @@ static int pppol2tp_getname(struct socke
+
+ pls = l2tp_session_priv(session);
+ tunnel = l2tp_sock_to_tunnel(pls->tunnel_sock);
+- if (tunnel == NULL) {
+- error = -EBADF;
++ if (tunnel == NULL)
+ goto end_put_sess;
+- }
+
+ inet = inet_sk(tunnel->sock);
+ if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) {
+@@ -970,12 +968,11 @@ static int pppol2tp_getname(struct socke
+ }
+
+ *usockaddr_len = len;
++ error = 0;
+
+ sock_put(pls->tunnel_sock);
+ end_put_sess:
+ sock_put(sk);
+- error = 0;
+-
+ end:
+ return error;
+ }
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:46 +0100
+Subject: l2tp: ensure session can't get removed during pppol2tp_session_ioctl()
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-5-will@kernel.org>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 57377d63547861919ee634b845c7caa38de4a452 upstream.
+
+Holding a reference on session is required before calling
+pppol2tp_session_ioctl(). The session could get freed while processing the
+ioctl otherwise. Since pppol2tp_session_ioctl() uses the session's socket,
+we also need to take a reference on it in l2tp_session_get().
+
+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: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -1168,11 +1168,18 @@ static int pppol2tp_tunnel_ioctl(struct
+ if (stats.session_id != 0) {
+ /* resend to session ioctl handler */
+ struct l2tp_session *session =
+- l2tp_session_find(sock_net(sk), tunnel, stats.session_id);
+- if (session != NULL)
+- err = pppol2tp_session_ioctl(session, cmd, arg);
+- else
++ l2tp_session_get(sock_net(sk), tunnel,
++ stats.session_id, true);
++
++ if (session) {
++ err = pppol2tp_session_ioctl(session, cmd,
++ arg);
++ if (session->deref)
++ session->deref(session);
++ l2tp_session_dec_refcount(session);
++ } else {
+ err = -EBADR;
++ }
+ break;
+ }
+ #ifdef CONFIG_XFRM
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:49 +0100
+Subject: l2tp: ensure sessions are freed after their PPPOL2TP socket
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-8-will@kernel.org>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit cdd10c9627496ad25c87ce6394e29752253c69d3 upstream.
+
+If l2tp_tunnel_delete() or l2tp_tunnel_closeall() deletes a session
+right after pppol2tp_release() orphaned its socket, then the 'sock'
+variable of the pppol2tp_session_close() callback is NULL. Yet the
+session is still used by pppol2tp_release().
+
+Therefore we need to take an extra reference in any case, to prevent
+l2tp_tunnel_delete() or l2tp_tunnel_closeall() from freeing the session.
+
+Since the pppol2tp_session_close() callback is only set if the session
+is associated to a PPPOL2TP socket and that both l2tp_tunnel_delete()
+and l2tp_tunnel_closeall() hold the PPPOL2TP socket before calling
+pppol2tp_session_close(), we're sure that pppol2tp_session_close() and
+pppol2tp_session_destruct() are paired and called in the right order.
+So the reference taken by the former will be released by the later.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -452,11 +452,11 @@ static void pppol2tp_session_close(struc
+
+ BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
+- if (sock) {
++ if (sock)
+ inet_shutdown(sock, SEND_SHUTDOWN);
+- /* Don't let the session go away before our socket does */
+- l2tp_session_inc_refcount(session);
+- }
++
++ /* 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
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:47 +0100
+Subject: l2tp: fix duplicate session creation
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-6-will@kernel.org>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit dbdbc73b44782e22b3b4b6e8b51e7a3d245f3086 upstream.
+
+l2tp_session_create() relies on its caller for checking for duplicate
+sessions. This is racy since a session can be concurrently inserted
+after the caller's verification.
+
+Fix this by letting l2tp_session_create() verify sessions uniqueness
+upon insertion. Callers need to be adapted to check for
+l2tp_session_create()'s return code instead of calling
+l2tp_session_find().
+
+pppol2tp_connect() is a bit special because it has to work on existing
+sessions (if they're not connected) or to create a new session if none
+is found. When acting on a preexisting session, a reference must be
+held or it could go away on us. So we have to use l2tp_session_get()
+instead of l2tp_session_find() and drop the reference before exiting.
+
+Fixes: d9e31d17ceba ("l2tp: Add L2TP ethernet pseudowire support")
+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: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c | 70 ++++++++++++++++++++++++++++++++++++++-------------
+ net/l2tp/l2tp_eth.c | 10 +------
+ net/l2tp/l2tp_ppp.c | 60 +++++++++++++++++++++----------------------
+ 3 files changed, 84 insertions(+), 56 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -377,6 +377,48 @@ struct l2tp_session *l2tp_session_find_b
+ }
+ EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname);
+
++static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
++ struct l2tp_session *session)
++{
++ struct l2tp_session *session_walk;
++ struct hlist_head *g_head;
++ struct hlist_head *head;
++ struct l2tp_net *pn;
++
++ head = l2tp_session_id_hash(tunnel, session->session_id);
++
++ write_lock_bh(&tunnel->hlist_lock);
++ hlist_for_each_entry(session_walk, head, hlist)
++ if (session_walk->session_id == session->session_id)
++ goto exist;
++
++ if (tunnel->version == L2TP_HDR_VER_3) {
++ pn = l2tp_pernet(tunnel->l2tp_net);
++ g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net),
++ 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;
++
++ hlist_add_head_rcu(&session->global_hlist, g_head);
++ spin_unlock_bh(&pn->l2tp_session_hlist_lock);
++ }
++
++ hlist_add_head(&session->hlist, head);
++ write_unlock_bh(&tunnel->hlist_lock);
++
++ return 0;
++
++exist_glob:
++ spin_unlock_bh(&pn->l2tp_session_hlist_lock);
++exist:
++ write_unlock_bh(&tunnel->hlist_lock);
++
++ return -EEXIST;
++}
++
+ /* Lookup a tunnel by id
+ */
+ struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
+@@ -1792,6 +1834,7 @@ 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) {
+@@ -1847,6 +1890,13 @@ struct l2tp_session *l2tp_session_create
+
+ l2tp_session_set_header_len(session, tunnel->version);
+
++ err = l2tp_session_add_to_tunnel(tunnel, session);
++ if (err) {
++ kfree(session);
++
++ return ERR_PTR(err);
++ }
++
+ /* Bump the reference count. The session context is deleted
+ * only when this drops to zero.
+ */
+@@ -1856,28 +1906,14 @@ struct l2tp_session *l2tp_session_create
+ /* Ensure tunnel socket isn't deleted */
+ sock_hold(tunnel->sock);
+
+- /* Add session to the tunnel's hash list */
+- write_lock_bh(&tunnel->hlist_lock);
+- hlist_add_head(&session->hlist,
+- l2tp_session_id_hash(tunnel, session_id));
+- write_unlock_bh(&tunnel->hlist_lock);
+-
+- /* And to the global session list if L2TPv3 */
+- if (tunnel->version != L2TP_HDR_VER_2) {
+- struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+-
+- spin_lock_bh(&pn->l2tp_session_hlist_lock);
+- hlist_add_head_rcu(&session->global_hlist,
+- l2tp_session_id_hash_2(pn, session_id));
+- spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+- }
+-
+ /* Ignore management session in session count value */
+ if (session->session_id != 0)
+ atomic_inc(&l2tp_session_count);
++
++ return session;
+ }
+
+- return session;
++ return ERR_PTR(-ENOMEM);
+ }
+ EXPORT_SYMBOL_GPL(l2tp_session_create);
+
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -223,12 +223,6 @@ static int l2tp_eth_create(struct net *n
+ goto out;
+ }
+
+- session = l2tp_session_find(net, tunnel, session_id);
+- if (session) {
+- rc = -EEXIST;
+- goto out;
+- }
+-
+ if (cfg->ifname) {
+ dev = dev_get_by_name(net, cfg->ifname);
+ if (dev) {
+@@ -242,8 +236,8 @@ static int l2tp_eth_create(struct net *n
+
+ session = l2tp_session_create(sizeof(*spriv), tunnel, session_id,
+ peer_session_id, cfg);
+- if (!session) {
+- rc = -ENOMEM;
++ if (IS_ERR(session)) {
++ rc = PTR_ERR(session);
+ goto out;
+ }
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -600,6 +600,7 @@ static int pppol2tp_connect(struct socke
+ int error = 0;
+ u32 tunnel_id, peer_tunnel_id;
+ u32 session_id, peer_session_id;
++ bool drop_refcnt = false;
+ int ver = 2;
+ int fd;
+
+@@ -708,36 +709,36 @@ static int pppol2tp_connect(struct socke
+ if (tunnel->peer_tunnel_id == 0)
+ tunnel->peer_tunnel_id = peer_tunnel_id;
+
+- /* Create session if it doesn't already exist. We handle the
+- * case where a session was previously created by the netlink
+- * interface by checking that the session doesn't already have
+- * a socket and its tunnel socket are what we expect. If any
+- * of those checks fail, return EEXIST to the caller.
+- */
+- session = l2tp_session_find(sock_net(sk), tunnel, session_id);
+- if (session == NULL) {
+- /* Default MTU must allow space for UDP/L2TP/PPP
+- * headers.
++ session = l2tp_session_get(sock_net(sk), tunnel, session_id, false);
++ if (session) {
++ drop_refcnt = true;
++ ps = l2tp_session_priv(session);
++
++ /* Using a pre-existing session is fine as long as it hasn't
++ * been connected yet.
+ */
+- cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
++ if (ps->sock) {
++ error = -EEXIST;
++ goto end;
++ }
+
+- /* Allocate and initialize a new session context. */
+- session = l2tp_session_create(sizeof(struct pppol2tp_session),
+- tunnel, session_id,
+- peer_session_id, &cfg);
+- if (session == NULL) {
+- error = -ENOMEM;
++ /* consistency checks */
++ if (ps->tunnel_sock != tunnel->sock) {
++ error = -EEXIST;
+ goto end;
+ }
+ } else {
+- ps = l2tp_session_priv(session);
+- error = -EEXIST;
+- if (ps->sock != NULL)
+- goto end;
++ /* Default MTU must allow space for UDP/L2TP/PPP headers */
++ cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
++ cfg.mru = cfg.mtu;
+
+- /* consistency checks */
+- if (ps->tunnel_sock != tunnel->sock)
++ session = l2tp_session_create(sizeof(struct pppol2tp_session),
++ tunnel, session_id,
++ peer_session_id, &cfg);
++ if (IS_ERR(session)) {
++ error = PTR_ERR(session);
+ goto end;
++ }
+ }
+
+ /* Associate session with its PPPoL2TP socket */
+@@ -802,6 +803,8 @@ out_no_ppp:
+ session->name);
+
+ end:
++ if (drop_refcnt)
++ l2tp_session_dec_refcount(session);
+ release_sock(sk);
+
+ return error;
+@@ -829,12 +832,6 @@ static int pppol2tp_session_create(struc
+ if (tunnel->sock == NULL)
+ goto out;
+
+- /* Check that this session doesn't already exist */
+- error = -EEXIST;
+- session = l2tp_session_find(net, tunnel, session_id);
+- if (session != NULL)
+- goto out;
+-
+ /* Default MTU values. */
+ if (cfg->mtu == 0)
+ cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+@@ -842,12 +839,13 @@ static int pppol2tp_session_create(struc
+ cfg->mru = cfg->mtu;
+
+ /* Allocate and initialize a new session context. */
+- error = -ENOMEM;
+ session = l2tp_session_create(sizeof(struct pppol2tp_session),
+ tunnel, session_id,
+ peer_session_id, cfg);
+- if (session == NULL)
++ if (IS_ERR(session)) {
++ error = PTR_ERR(session);
+ goto out;
++ }
+
+ ps = l2tp_session_priv(session);
+ ps->tunnel_sock = tunnel->sock;
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:50 +0100
+Subject: l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-9-will@kernel.org>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit b228a94066406b6c456321d69643b0d7ce11cfa6 upstream.
+
+There are several ways to remove L2TP sessions:
+
+ * deleting a session explicitly using the netlink interface (with
+ L2TP_CMD_SESSION_DELETE),
+ * deleting the session's parent tunnel (either by closing the
+ tunnel's file descriptor or using the netlink interface),
+ * closing the PPPOL2TP file descriptor of a PPP pseudo-wire.
+
+In some cases, when these methods are used concurrently on the same
+session, the session can be removed twice, leading to use-after-free
+bugs.
+
+This patch adds a 'dead' flag, used by l2tp_session_delete() and
+l2tp_tunnel_closeall() to prevent them from stepping on each other's
+toes.
+
+The session deletion path used when closing a PPPOL2TP file descriptor
+doesn't need to be adapted. It already has to ensure that a session
+remains valid for the lifetime of its PPPOL2TP file descriptor.
+So it takes an extra reference on the session in the ->session_close()
+callback (pppol2tp_session_close()), which is eventually dropped
+in the ->sk_destruct() callback of the PPPOL2TP socket
+(pppol2tp_session_destruct()).
+Still, __l2tp_session_unhash() and l2tp_session_queue_purge() can be
+called twice and even concurrently for a given session, but thanks to
+proper locking and re-initialisation of list fields, this is not an
+issue.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c | 6 ++++++
+ net/l2tp/l2tp_core.h | 1 +
+ 2 files changed, 7 insertions(+)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -1351,6 +1351,9 @@ again:
+
+ hlist_del_init(&session->hlist);
+
++ if (test_and_set_bit(0, &session->dead))
++ goto again;
++
+ if (session->ref != NULL)
+ (*session->ref)(session);
+
+@@ -1799,6 +1802,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash)
+ */
+ int l2tp_session_delete(struct l2tp_session *session)
+ {
++ if (test_and_set_bit(0, &session->dead))
++ return 0;
++
+ if (session->ref)
+ (*session->ref)(session);
+ __l2tp_session_unhash(session);
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -85,6 +85,7 @@ struct l2tp_session_cfg {
+ struct l2tp_session {
+ int magic; /* should be
+ * L2TP_SESSION_MAGIC */
++ long dead;
+
+ struct l2tp_tunnel *tunnel; /* back pointer to tunnel
+ * context */
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:45 +0100
+Subject: l2tp: fix race in l2tp_recv_common()
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-4-will@kernel.org>
+
+From: Guillaume Nault <g.nault@alphalink.fr>
+
+commit 61b9a047729bb230978178bca6729689d0c50ca2 upstream.
+
+Taking a reference on sessions in l2tp_recv_common() is racy; this
+has to be done by the callers.
+
+To this end, a new function is required (l2tp_session_get()) to
+atomically lookup a session and take a reference on it. Callers then
+have to manually drop this reference.
+
+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: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_core.c | 73 +++++++++++++++++++++++++++++++++++++++++----------
+ net/l2tp/l2tp_core.h | 3 ++
+ net/l2tp/l2tp_ip.c | 17 ++++++++---
+ net/l2tp/l2tp_ip6.c | 18 +++++++++---
+ 4 files changed, 88 insertions(+), 23 deletions(-)
+
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -277,6 +277,55 @@ struct l2tp_session *l2tp_session_find(s
+ }
+ EXPORT_SYMBOL_GPL(l2tp_session_find);
+
++/* Like l2tp_session_find() but takes a reference 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_tunnel *tunnel,
++ u32 session_id, bool do_ref)
++{
++ struct hlist_head *session_list;
++ struct l2tp_session *session;
++
++ if (!tunnel) {
++ struct l2tp_net *pn = l2tp_pernet(net);
++
++ session_list = l2tp_session_id_hash_2(pn, session_id);
++
++ rcu_read_lock_bh();
++ hlist_for_each_entry_rcu(session, session_list, global_hlist) {
++ if (session->session_id == session_id) {
++ l2tp_session_inc_refcount(session);
++ if (do_ref && session->ref)
++ session->ref(session);
++ rcu_read_unlock_bh();
++
++ return session;
++ }
++ }
++ rcu_read_unlock_bh();
++
++ return NULL;
++ }
++
++ 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) {
++ l2tp_session_inc_refcount(session);
++ if (do_ref && session->ref)
++ session->ref(session);
++ read_unlock_bh(&tunnel->hlist_lock);
++
++ return session;
++ }
++ }
++ read_unlock_bh(&tunnel->hlist_lock);
++
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(l2tp_session_get);
++
+ struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
+ bool do_ref)
+ {
+@@ -636,6 +685,9 @@ discard:
+ * a data (not control) frame before coming here. Fields up to the
+ * session-id have already been parsed and ptr points to the data
+ * after the session-id.
++ *
++ * session->ref() must have been called prior to l2tp_recv_common().
++ * session->deref() will be called automatically after skb is processed.
+ */
+ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
+ unsigned char *ptr, unsigned char *optr, u16 hdrflags,
+@@ -645,14 +697,6 @@ void l2tp_recv_common(struct l2tp_sessio
+ int offset;
+ u32 ns, nr;
+
+- /* The ref count is increased since we now hold a pointer to
+- * the session. Take care to decrement the refcnt when exiting
+- * this function from now on...
+- */
+- l2tp_session_inc_refcount(session);
+- if (session->ref)
+- (*session->ref)(session);
+-
+ /* Parse and check optional cookie */
+ if (session->peer_cookie_len > 0) {
+ if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
+@@ -803,8 +847,6 @@ void l2tp_recv_common(struct l2tp_sessio
+ /* Try to dequeue as many skbs from reorder_q as we can. */
+ l2tp_recv_dequeue(session);
+
+- l2tp_session_dec_refcount(session);
+-
+ return;
+
+ discard:
+@@ -813,8 +855,6 @@ discard:
+
+ if (session->deref)
+ (*session->deref)(session);
+-
+- l2tp_session_dec_refcount(session);
+ }
+ EXPORT_SYMBOL(l2tp_recv_common);
+
+@@ -921,8 +961,14 @@ static int l2tp_udp_recv_core(struct l2t
+ }
+
+ /* Find the session context */
+- session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id);
++ session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true);
+ if (!session || !session->recv_skb) {
++ if (session) {
++ if (session->deref)
++ session->deref(session);
++ l2tp_session_dec_refcount(session);
++ }
++
+ /* Not found? Pass to userspace to deal with */
+ l2tp_info(tunnel, L2TP_MSG_DATA,
+ "%s: no session found (%u/%u). Passing up.\n",
+@@ -935,6 +981,7 @@ static int l2tp_udp_recv_core(struct l2t
+ goto error;
+
+ l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook);
++ l2tp_session_dec_refcount(session);
+
+ return 0;
+
+--- a/net/l2tp/l2tp_core.h
++++ b/net/l2tp/l2tp_core.h
+@@ -243,6 +243,9 @@ out:
+ return tunnel;
+ }
+
++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);
+--- a/net/l2tp/l2tp_ip.c
++++ b/net/l2tp/l2tp_ip.c
+@@ -142,19 +142,19 @@ static int l2tp_ip_recv(struct sk_buff *
+ }
+
+ /* Ok, this is a data packet. Lookup the session. */
+- session = l2tp_session_find(net, NULL, session_id);
+- if (session == NULL)
++ session = l2tp_session_get(net, NULL, session_id, true);
++ if (!session)
+ goto discard;
+
+ tunnel = session->tunnel;
+- if (tunnel == NULL)
+- goto discard;
++ if (!tunnel)
++ goto discard_sess;
+
+ /* Trace packet contents, if enabled */
+ if (tunnel->debug & L2TP_MSG_DATA) {
+ length = min(32u, skb->len);
+ if (!pskb_may_pull(skb, length))
+- goto discard;
++ goto discard_sess;
+
+ /* Point to L2TP header */
+ optr = ptr = skb->data;
+@@ -167,6 +167,7 @@ static int l2tp_ip_recv(struct sk_buff *
+ goto discard;
+
+ l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook);
++ l2tp_session_dec_refcount(session);
+
+ return 0;
+
+@@ -204,6 +205,12 @@ pass_up:
+
+ return sk_receive_skb(sk, skb, 1);
+
++discard_sess:
++ if (session->deref)
++ session->deref(session);
++ l2tp_session_dec_refcount(session);
++ goto discard;
++
+ discard_put:
+ sock_put(sk);
+
+--- a/net/l2tp/l2tp_ip6.c
++++ b/net/l2tp/l2tp_ip6.c
+@@ -154,19 +154,19 @@ static int l2tp_ip6_recv(struct sk_buff
+ }
+
+ /* Ok, this is a data packet. Lookup the session. */
+- session = l2tp_session_find(net, NULL, session_id);
+- if (session == NULL)
++ session = l2tp_session_get(net, NULL, session_id, true);
++ if (!session)
+ goto discard;
+
+ tunnel = session->tunnel;
+- if (tunnel == NULL)
+- goto discard;
++ if (!tunnel)
++ goto discard_sess;
+
+ /* Trace packet contents, if enabled */
+ if (tunnel->debug & L2TP_MSG_DATA) {
+ length = min(32u, skb->len);
+ if (!pskb_may_pull(skb, length))
+- goto discard;
++ goto discard_sess;
+
+ /* Point to L2TP header */
+ optr = ptr = skb->data;
+@@ -180,6 +180,8 @@ static int l2tp_ip6_recv(struct sk_buff
+
+ l2tp_recv_common(session, skb, ptr, optr, 0, skb->len,
+ tunnel->recv_payload_hook);
++ l2tp_session_dec_refcount(session);
++
+ return 0;
+
+ pass_up:
+@@ -217,6 +219,12 @@ pass_up:
+
+ return sk_receive_skb(sk, skb, 1);
+
++discard_sess:
++ if (session->deref)
++ session->deref(session);
++ l2tp_session_dec_refcount(session);
++ goto discard;
++
+ discard_put:
+ sock_put(sk);
+
--- /dev/null
+From foo@baz Fri 03 Apr 2020 02:35:58 PM CEST
+From: Will Deacon <will@kernel.org>
+Date: Thu, 2 Apr 2020 18:32:48 +0100
+Subject: l2tp: Refactor the codes with existing macros instead of literal number
+To: gregkh@linuxfoundation.org
+Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, Gao Feng <fgao@ikuai8.com>, "David S . Miller" <davem@davemloft.net>, Will Deacon <will@kernel.org>
+Message-ID: <20200402173250.7858-7-will@kernel.org>
+
+From: Gao Feng <fgao@ikuai8.com>
+
+commit 54c151d9ed1321e6e623c80ffe42cd2eb1571744 upstream.
+
+Use PPP_ALLSTATIONS, PPP_UI, and SEND_SHUTDOWN instead of 0xff,
+0x03, and 2 separately.
+
+Signed-off-by: Gao Feng <fgao@ikuai8.com>
+Acked-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ppp.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -177,7 +177,7 @@ static int pppol2tp_recv_payload_hook(st
+ if (!pskb_may_pull(skb, 2))
+ return 1;
+
+- if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
++ if ((skb->data[0] == PPP_ALLSTATIONS) && (skb->data[1] == PPP_UI))
+ skb_pull(skb, 2);
+
+ return 0;
+@@ -297,7 +297,6 @@ static void pppol2tp_session_sock_put(st
+ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
+ size_t total_len)
+ {
+- static const unsigned char ppph[2] = { 0xff, 0x03 };
+ struct sock *sk = sock->sk;
+ struct sk_buff *skb;
+ int error;
+@@ -327,7 +326,7 @@ static int pppol2tp_sendmsg(struct socke
+ error = -ENOMEM;
+ skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
+ uhlen + session->hdr_len +
+- sizeof(ppph) + total_len,
++ 2 + total_len, /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */
+ 0, GFP_KERNEL);
+ if (!skb)
+ goto error_put_sess_tun;
+@@ -340,8 +339,8 @@ static int pppol2tp_sendmsg(struct socke
+ skb_reserve(skb, uhlen);
+
+ /* Add PPP header */
+- skb->data[0] = ppph[0];
+- skb->data[1] = ppph[1];
++ skb->data[0] = PPP_ALLSTATIONS;
++ skb->data[1] = PPP_UI;
+ skb_put(skb, 2);
+
+ /* Copy user data into skb */
+@@ -384,7 +383,6 @@ error:
+ */
+ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+ {
+- static const u8 ppph[2] = { 0xff, 0x03 };
+ struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk_tun;
+ struct l2tp_session *session;
+@@ -413,14 +411,14 @@ static int pppol2tp_xmit(struct ppp_chan
+ sizeof(struct iphdr) + /* IP header */
+ uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */
+ session->hdr_len + /* L2TP header */
+- sizeof(ppph); /* PPP header */
++ 2; /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */
+ if (skb_cow_head(skb, headroom))
+ goto abort_put_sess_tun;
+
+ /* Setup PPP header */
+- __skb_push(skb, sizeof(ppph));
+- skb->data[0] = ppph[0];
+- skb->data[1] = ppph[1];
++ __skb_push(skb, 2);
++ skb->data[0] = PPP_ALLSTATIONS;
++ skb->data[1] = PPP_UI;
+
+ local_bh_disable();
+ l2tp_xmit_skb(session, skb, session->hdr_len);
+@@ -455,7 +453,7 @@ static void pppol2tp_session_close(struc
+ BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
+ if (sock) {
+- inet_shutdown(sock, 2);
++ inet_shutdown(sock, SEND_SHUTDOWN);
+ /* Don't let the session go away before our socket does */
+ l2tp_session_inc_refcount(session);
+ }
--- /dev/null
+From 0e6b5259824e97a0f7e7b450421ff12865d3b0e2 Mon Sep 17 00:00:00 2001
+From: Shmulik Ladkani <shmulik.ladkani@gmail.com>
+Date: Thu, 26 May 2016 20:16:36 +0300
+Subject: net: l2tp: Make l2tp_ip6 namespace aware
+
+From: Shmulik Ladkani <shmulik.ladkani@gmail.com>
+
+commit 0e6b5259824e97a0f7e7b450421ff12865d3b0e2 upstream.
+
+l2tp_ip6 tunnel and session lookups were still using init_net, although
+the l2tp core infrastructure already supports lookups keyed by 'net'.
+
+As a result, l2tp_ip6_recv discarded packets for tunnels/sessions
+created in namespaces other than the init_net.
+
+Fix, by using dev_net(skb->dev) or sock_net(sk) where appropriate.
+
+Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/l2tp/l2tp_ip6.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/net/l2tp/l2tp_ip6.c
++++ b/net/l2tp/l2tp_ip6.c
+@@ -127,6 +127,7 @@ static inline struct sock *l2tp_ip6_bind
+ */
+ static int l2tp_ip6_recv(struct sk_buff *skb)
+ {
++ struct net *net = dev_net(skb->dev);
+ struct sock *sk;
+ u32 session_id;
+ u32 tunnel_id;
+@@ -153,7 +154,7 @@ static int l2tp_ip6_recv(struct sk_buff
+ }
+
+ /* Ok, this is a data packet. Lookup the session. */
+- session = l2tp_session_find(&init_net, NULL, session_id);
++ session = l2tp_session_find(net, NULL, session_id);
+ if (session == NULL)
+ goto discard;
+
+@@ -190,7 +191,7 @@ pass_up:
+ goto discard;
+
+ tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
+- tunnel = l2tp_tunnel_find(&init_net, tunnel_id);
++ tunnel = l2tp_tunnel_find(net, tunnel_id);
+ if (tunnel) {
+ sk = tunnel->sock;
+ sock_hold(sk);
+@@ -198,7 +199,7 @@ pass_up:
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+
+ read_lock_bh(&l2tp_ip6_lock);
+- sk = __l2tp_ip6_bind_lookup(&init_net, &iph->daddr,
++ sk = __l2tp_ip6_bind_lookup(net, &iph->daddr,
+ 0, tunnel_id);
+ if (!sk) {
+ read_unlock_bh(&l2tp_ip6_lock);
+@@ -267,6 +268,7 @@ static int l2tp_ip6_bind(struct sock *sk
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
++ struct net *net = sock_net(sk);
+ __be32 v4addr = 0;
+ int addr_type;
+ int err;
+@@ -288,7 +290,7 @@ static int l2tp_ip6_bind(struct sock *sk
+
+ err = -EADDRINUSE;
+ read_lock_bh(&l2tp_ip6_lock);
+- if (__l2tp_ip6_bind_lookup(&init_net, &addr->l2tp_addr,
++ if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr,
+ sk->sk_bound_dev_if, addr->l2tp_conn_id))
+ goto out_in_use;
+ read_unlock_bh(&l2tp_ip6_lock);
+@@ -461,7 +463,7 @@ static int l2tp_ip6_backlog_recv(struct
+ return 0;
+
+ drop:
+- IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS);
++ IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);
+ kfree_skb(skb);
+ return -1;
+ }
ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch
net-ip_tunnel-fix-interface-lookup-with-no-key.patch
sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch
+l2tp-correctly-return-ebadf-from-pppol2tp_getname.patch
+net-l2tp-make-l2tp_ip6-namespace-aware.patch
+l2tp-fix-race-in-l2tp_recv_common.patch
+l2tp-ensure-session-can-t-get-removed-during-pppol2tp_session_ioctl.patch
+l2tp-fix-duplicate-session-creation.patch
+l2tp-refactor-the-codes-with-existing-macros-instead-of-literal-number.patch
+l2tp-ensure-sessions-are-freed-after-their-pppol2tp-socket.patch
+l2tp-fix-race-between-l2tp_session_delete-and-l2tp_tunnel_closeall.patch