]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Apr 2020 09:10:39 +0000 (11:10 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Apr 2020 09:10:39 +0000 (11:10 +0200)
added patches:
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

queue-4.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch [new file with mode: 0644]
queue-4.4/net-ip_tunnel-fix-interface-lookup-with-no-key.patch [new file with mode: 0644]
queue-4.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch b/queue-4.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch
new file mode 100644 (file)
index 0000000..5fcd48c
--- /dev/null
@@ -0,0 +1,63 @@
+From foo@baz Fri 03 Apr 2020 11:06:15 AM CEST
+From: Qian Cai <cai@lca.pw>
+Date: Wed, 25 Mar 2020 18:01:00 -0400
+Subject: ipv4: fix a RCU-list lock in fib_triestat_seq_show
+
+From: Qian Cai <cai@lca.pw>
+
+[ Upstream commit fbe4e0c1b298b4665ee6915266c9d6c5b934ef4a ]
+
+fib_triestat_seq_show() calls hlist_for_each_entry_rcu(tb, head,
+tb_hlist) without rcu_read_lock() will trigger a warning,
+
+ net/ipv4/fib_trie.c:2579 RCU-list traversed in non-reader section!!
+
+ other info that might help us debug this:
+
+ rcu_scheduler_active = 2, debug_locks = 1
+ 1 lock held by proc01/115277:
+  #0: c0000014507acf00 (&p->lock){+.+.}-{3:3}, at: seq_read+0x58/0x670
+
+ Call Trace:
+  dump_stack+0xf4/0x164 (unreliable)
+  lockdep_rcu_suspicious+0x140/0x164
+  fib_triestat_seq_show+0x750/0x880
+  seq_read+0x1a0/0x670
+  proc_reg_read+0x10c/0x1b0
+  __vfs_read+0x3c/0x70
+  vfs_read+0xac/0x170
+  ksys_read+0x7c/0x140
+  system_call+0x5c/0x68
+
+Fix it by adding a pair of rcu_read_lock/unlock() and use
+cond_resched_rcu() to avoid the situation where walking of a large
+number of items  may prevent scheduling for a long time.
+
+Signed-off-by: Qian Cai <cai@lca.pw>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/fib_trie.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2230,6 +2230,7 @@ static int fib_triestat_seq_show(struct
+                  " %Zd bytes, size of tnode: %Zd bytes.\n",
+                  LEAF_SIZE, TNODE_SIZE(0));
++      rcu_read_lock();
+       for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               struct fib_table *tb;
+@@ -2249,7 +2250,9 @@ static int fib_triestat_seq_show(struct
+                       trie_show_usage(seq, t->stats);
+ #endif
+               }
++              cond_resched_rcu();
+       }
++      rcu_read_unlock();
+       return 0;
+ }
diff --git a/queue-4.4/net-ip_tunnel-fix-interface-lookup-with-no-key.patch b/queue-4.4/net-ip_tunnel-fix-interface-lookup-with-no-key.patch
new file mode 100644 (file)
index 0000000..b837b08
--- /dev/null
@@ -0,0 +1,54 @@
+From foo@baz Fri 03 Apr 2020 11:06:15 AM CEST
+From: William Dauchy <w.dauchy@criteo.com>
+Date: Fri, 27 Mar 2020 19:56:39 +0100
+Subject: net, ip_tunnel: fix interface lookup with no key
+
+From: William Dauchy <w.dauchy@criteo.com>
+
+[ Upstream commit 25629fdaff2ff509dd0b3f5ff93d70a75e79e0a1 ]
+
+when creating a new ipip interface with no local/remote configuration,
+the lookup is done with TUNNEL_NO_KEY flag, making it impossible to
+match the new interface (only possible match being fallback or metada
+case interface); e.g: `ip link add tunl1 type ipip dev eth0`
+
+To fix this case, adding a flag check before the key comparison so we
+permit to match an interface with no local/remote config; it also avoids
+breaking possible userland tools relying on TUNNEL_NO_KEY flag and
+uninitialised key.
+
+context being on my side, I'm creating an extra ipip interface attached
+to the physical one, and moving it to a dedicated namespace.
+
+Fixes: c54419321455 ("GRE: Refactor GRE tunneling code.")
+Signed-off-by: William Dauchy <w.dauchy@criteo.com>
+Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/ip_tunnel.c |    6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/net/ipv4/ip_tunnel.c
++++ b/net/ipv4/ip_tunnel.c
+@@ -155,11 +155,8 @@ struct ip_tunnel *ip_tunnel_lookup(struc
+                       cand = t;
+       }
+-      if (flags & TUNNEL_NO_KEY)
+-              goto skip_key_lookup;
+-
+       hlist_for_each_entry_rcu(t, head, hash_node) {
+-              if (t->parms.i_key != key ||
++              if ((!(flags & TUNNEL_NO_KEY) && t->parms.i_key != key) ||
+                   t->parms.iph.saddr != 0 ||
+                   t->parms.iph.daddr != 0 ||
+                   !(t->dev->flags & IFF_UP))
+@@ -171,7 +168,6 @@ struct ip_tunnel *ip_tunnel_lookup(struc
+                       cand = t;
+       }
+-skip_key_lookup:
+       if (cand)
+               return cand;
diff --git a/queue-4.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch b/queue-4.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch
new file mode 100644 (file)
index 0000000..8064725
--- /dev/null
@@ -0,0 +1,187 @@
+From foo@baz Fri 03 Apr 2020 10:57:34 AM CEST
+From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Date: Thu, 26 Mar 2020 20:47:46 -0300
+Subject: sctp: fix possibly using a bad saddr with a given dst
+
+From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+
+[ Upstream commit 582eea230536a6f104097dd46205822005d5fe3a ]
+
+Under certain circumstances, depending on the order of addresses on the
+interfaces, it could be that sctp_v[46]_get_dst() would return a dst
+with a mismatched struct flowi.
+
+For example, if when walking through the bind addresses and the first
+one is not a match, it saves the dst as a fallback (added in
+410f03831c07), but not the flowi. Then if the next one is also not a
+match, the previous dst will be returned but with the flowi information
+for the 2nd address, which is wrong.
+
+The fix is to use a locally stored flowi that can be used for such
+attempts, and copy it to the parameter only in case it is a possible
+match, together with the corresponding dst entry.
+
+The patch updates IPv6 code mostly just to be in sync. Even though the issue
+is also present there, it fallback is not expected to work with IPv6.
+
+Fixes: 410f03831c07 ("sctp: add routing output fallback")
+Reported-by: Jin Meng <meng.a.jin@nokia-sbell.com>
+Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Tested-by: Xin Long <lucien.xin@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/ipv6.c     |   20 ++++++++++++++------
+ net/sctp/protocol.c |   28 +++++++++++++++++++---------
+ 2 files changed, 33 insertions(+), 15 deletions(-)
+
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -234,7 +234,8 @@ static void sctp_v6_get_dst(struct sctp_
+ {
+       struct sctp_association *asoc = t->asoc;
+       struct dst_entry *dst = NULL;
+-      struct flowi6 *fl6 = &fl->u.ip6;
++      struct flowi _fl;
++      struct flowi6 *fl6 = &_fl.u.ip6;
+       struct sctp_bind_addr *bp;
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct sctp_sockaddr_entry *laddr;
+@@ -244,7 +245,7 @@ static void sctp_v6_get_dst(struct sctp_
+       __u8 matchlen = 0;
+       sctp_scope_t scope;
+-      memset(fl6, 0, sizeof(struct flowi6));
++      memset(&_fl, 0, sizeof(_fl));
+       fl6->daddr = daddr->v6.sin6_addr;
+       fl6->fl6_dport = daddr->v6.sin6_port;
+       fl6->flowi6_proto = IPPROTO_SCTP;
+@@ -268,8 +269,11 @@ static void sctp_v6_get_dst(struct sctp_
+       rcu_read_unlock();
+       dst = ip6_dst_lookup_flow(sk, fl6, final_p);
+-      if (!asoc || saddr)
++      if (!asoc || saddr) {
++              t->dst = dst;
++              memcpy(fl, &_fl, sizeof(_fl));
+               goto out;
++      }
+       bp = &asoc->base.bind_addr;
+       scope = sctp_scope(daddr);
+@@ -292,6 +296,8 @@ static void sctp_v6_get_dst(struct sctp_
+                       if ((laddr->a.sa.sa_family == AF_INET6) &&
+                           (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
+                               rcu_read_unlock();
++                              t->dst = dst;
++                              memcpy(fl, &_fl, sizeof(_fl));
+                               goto out;
+                       }
+               }
+@@ -330,6 +336,8 @@ static void sctp_v6_get_dst(struct sctp_
+                       if (!IS_ERR_OR_NULL(dst))
+                               dst_release(dst);
+                       dst = bdst;
++                      t->dst = dst;
++                      memcpy(fl, &_fl, sizeof(_fl));
+                       break;
+               }
+@@ -343,6 +351,8 @@ static void sctp_v6_get_dst(struct sctp_
+                       dst_release(dst);
+               dst = bdst;
+               matchlen = bmatchlen;
++              t->dst = dst;
++              memcpy(fl, &_fl, sizeof(_fl));
+       }
+       rcu_read_unlock();
+@@ -351,14 +361,12 @@ out:
+               struct rt6_info *rt;
+               rt = (struct rt6_info *)dst;
+-              t->dst = dst;
+               t->dst_cookie = rt6_get_cookie(rt);
+               pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n",
+                        &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
+-                       &fl6->saddr);
++                       &fl->u.ip6.saddr);
+       } else {
+               t->dst = NULL;
+-
+               pr_debug("no route\n");
+       }
+ }
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -428,14 +428,15 @@ static void sctp_v4_get_dst(struct sctp_
+ {
+       struct sctp_association *asoc = t->asoc;
+       struct rtable *rt;
+-      struct flowi4 *fl4 = &fl->u.ip4;
++      struct flowi _fl;
++      struct flowi4 *fl4 = &_fl.u.ip4;
+       struct sctp_bind_addr *bp;
+       struct sctp_sockaddr_entry *laddr;
+       struct dst_entry *dst = NULL;
+       union sctp_addr *daddr = &t->ipaddr;
+       union sctp_addr dst_saddr;
+-      memset(fl4, 0x0, sizeof(struct flowi4));
++      memset(&_fl, 0x0, sizeof(_fl));
+       fl4->daddr  = daddr->v4.sin_addr.s_addr;
+       fl4->fl4_dport = daddr->v4.sin_port;
+       fl4->flowi4_proto = IPPROTO_SCTP;
+@@ -453,8 +454,11 @@ static void sctp_v4_get_dst(struct sctp_
+                &fl4->saddr);
+       rt = ip_route_output_key(sock_net(sk), fl4);
+-      if (!IS_ERR(rt))
++      if (!IS_ERR(rt)) {
+               dst = &rt->dst;
++              t->dst = dst;
++              memcpy(fl, &_fl, sizeof(_fl));
++      }
+       /* If there is no association or if a source address is passed, no
+        * more validation is required.
+@@ -517,27 +521,33 @@ static void sctp_v4_get_dst(struct sctp_
+               odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr,
+                                    false);
+               if (!odev || odev->ifindex != fl4->flowi4_oif) {
+-                      if (!dst)
++                      if (!dst) {
+                               dst = &rt->dst;
+-                      else
++                              t->dst = dst;
++                              memcpy(fl, &_fl, sizeof(_fl));
++                      } else {
+                               dst_release(&rt->dst);
++                      }
+                       continue;
+               }
+               dst_release(dst);
+               dst = &rt->dst;
++              t->dst = dst;
++              memcpy(fl, &_fl, sizeof(_fl));
+               break;
+       }
+ out_unlock:
+       rcu_read_unlock();
+ out:
+-      t->dst = dst;
+-      if (dst)
++      if (dst) {
+               pr_debug("rt_dst:%pI4, rt_src:%pI4\n",
+-                       &fl4->daddr, &fl4->saddr);
+-      else
++                       &fl->u.ip4.daddr, &fl->u.ip4.saddr);
++      } else {
++              t->dst = NULL;
+               pr_debug("no route\n");
++      }
+ }
+ /* For v4, the source address is cached in the route entry(dst). So no need
index c01f499c84a0032d5d4e6903f7b382d955b5a9c7..9f283d408d276c71011d50579da4ff6956298252 100644 (file)
@@ -1 +1,4 @@
 drm-bochs-downgrade-pci_request_region-failure-from-.patch
+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