]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Mon, 15 Jun 2020 03:27:38 +0000 (23:27 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 15 Jun 2020 03:27:38 +0000 (23:27 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch [new file with mode: 0644]
queue-5.4/iwlwifi-mvm-fix-nvm-check-for-3168-devices.patch [new file with mode: 0644]
queue-5.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch [new file with mode: 0644]
queue-5.4/sctp-fix-refcount-bug-in-sctp_wfree.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch b/queue-5.4/ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch
new file mode 100644 (file)
index 0000000..3b85634
--- /dev/null
@@ -0,0 +1,68 @@
+From 45196976f627fc6e08aafd469d579d3d465a8cc3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_trie.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index f12fa8da6127..1b851fd82613 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2455,6 +2455,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
+                  " %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;
+@@ -2474,7 +2475,9 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
+                       trie_show_usage(seq, t->stats);
+ #endif
+               }
++              cond_resched_rcu();
+       }
++      rcu_read_unlock();
+       return 0;
+ }
+-- 
+2.25.1
+
diff --git a/queue-5.4/iwlwifi-mvm-fix-nvm-check-for-3168-devices.patch b/queue-5.4/iwlwifi-mvm-fix-nvm-check-for-3168-devices.patch
new file mode 100644 (file)
index 0000000..849d48d
--- /dev/null
@@ -0,0 +1,39 @@
+From 53988ea786ba98a9f203262a308cc1a1aad8d11f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2019 13:21:58 +0200
+Subject: iwlwifi: mvm: fix NVM check for 3168 devices
+
+From: Luca Coelho <luciano.coelho@intel.com>
+
+[ Upstream commit b3f20e098293892388d6a0491d6bbb2efb46fbff ]
+
+We had a check on !NVM_EXT and then a check for NVM_SDP in the else
+block of this if.  The else block, obviously, could only be reached if
+using NVM_EXT, so it would never be NVM_SDP.
+
+Fix that by checking whether the nvm_type is IWL_NVM instead of
+checking for !IWL_NVM_EXT to solve this issue.
+
+Reported-by: Stefan Sperling <stsp@stsp.name>
+Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+index ed367b0a185c..f49887379c43 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+@@ -281,7 +281,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
+       int regulatory_type;
+       /* Checking for required sections */
+-      if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {
++      if (mvm->trans->cfg->nvm_type == IWL_NVM) {
+               if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+                   !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
+                       IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");
+-- 
+2.25.1
+
diff --git a/queue-5.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch b/queue-5.4/sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch
new file mode 100644 (file)
index 0000000..43858f1
--- /dev/null
@@ -0,0 +1,195 @@
+From e9c5ef5d7ff9547c42923ebff7858fb15a43e44c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/ipv6.c     | 20 ++++++++++++++------
+ net/sctp/protocol.c | 28 +++++++++++++++++++---------
+ 2 files changed, 33 insertions(+), 15 deletions(-)
+
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index bc734cfaa29e..c87af430107a 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -228,7 +228,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ {
+       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;
+@@ -238,7 +239,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+       enum sctp_scope scope;
+       __u8 matchlen = 0;
+-      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;
+@@ -276,8 +277,11 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+       rcu_read_unlock();
+       dst = ip6_dst_lookup_flow(sock_net(sk), 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);
+@@ -300,6 +304,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                       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;
+                       }
+               }
+@@ -338,6 +344,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                       if (!IS_ERR_OR_NULL(dst))
+                               dst_release(dst);
+                       dst = bdst;
++                      t->dst = dst;
++                      memcpy(fl, &_fl, sizeof(_fl));
+                       break;
+               }
+@@ -351,6 +359,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                       dst_release(dst);
+               dst = bdst;
+               matchlen = bmatchlen;
++              t->dst = dst;
++              memcpy(fl, &_fl, sizeof(_fl));
+       }
+       rcu_read_unlock();
+@@ -359,14 +369,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+               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");
+       }
+ }
+diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
+index 681ffb3545db..237c88eeb538 100644
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -409,7 +409,8 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ {
+       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;
+@@ -419,7 +420,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+       if (t->dscp & SCTP_DSCP_SET_MASK)
+               tos = t->dscp & SCTP_DSCP_VAL_MASK;
+-      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;
+@@ -438,8 +439,11 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+                &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.
+@@ -502,27 +506,33 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+               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
+-- 
+2.25.1
+
diff --git a/queue-5.4/sctp-fix-refcount-bug-in-sctp_wfree.patch b/queue-5.4/sctp-fix-refcount-bug-in-sctp_wfree.patch
new file mode 100644 (file)
index 0000000..39684aa
--- /dev/null
@@ -0,0 +1,120 @@
+From 5a54044cb23fbb3bf8614995014782779a975738 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2020 11:07:51 +0800
+Subject: sctp: fix refcount bug in sctp_wfree
+
+From: Qiujun Huang <hqjagain@gmail.com>
+
+[ Upstream commit 5c3e82fe159622e46e91458c1a6509c321a62820 ]
+
+We should iterate over the datamsgs to move
+all chunks(skbs) to newsk.
+
+The following case cause the bug:
+for the trouble SKB, it was in outq->transmitted list
+
+sctp_outq_sack
+        sctp_check_transmitted
+                SKB was moved to outq->sacked list
+        then throw away the sack queue
+                SKB was deleted from outq->sacked
+(but it was held by datamsg at sctp_datamsg_to_asoc
+So, sctp_wfree was not called here)
+
+then migrate happened
+
+        sctp_for_each_tx_datachunk(
+        sctp_clear_owner_w);
+        sctp_assoc_migrate();
+        sctp_for_each_tx_datachunk(
+        sctp_set_owner_w);
+SKB was not in the outq, and was not changed to newsk
+
+finally
+
+__sctp_outq_teardown
+        sctp_chunk_put (for another skb)
+                sctp_datamsg_put
+                        __kfree_skb(msg->frag_list)
+                                sctp_wfree (for SKB)
+       SKB->sk was still oldsk (skb->sk != asoc->base.sk).
+
+Reported-and-tested-by: syzbot+cea71eec5d6de256d54d@syzkaller.appspotmail.com
+Signed-off-by: Qiujun Huang <hqjagain@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <mleitner@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sctp/socket.c | 31 +++++++++++++++++++++++--------
+ 1 file changed, 23 insertions(+), 8 deletions(-)
+
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index ffd3262b7a41..58fe6556cdf5 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -147,29 +147,44 @@ static void sctp_clear_owner_w(struct sctp_chunk *chunk)
+       skb_orphan(chunk->skb);
+ }
++#define traverse_and_process()        \
++do {                          \
++      msg = chunk->msg;       \
++      if (msg == prev_msg)    \
++              continue;       \
++      list_for_each_entry(c, &msg->chunks, frag_list) {       \
++              if ((clear && asoc->base.sk == c->skb->sk) ||   \
++                  (!clear && asoc->base.sk != c->skb->sk))    \
++                      cb(c);  \
++      }                       \
++      prev_msg = msg;         \
++} while (0)
++
+ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
++                                     bool clear,
+                                      void (*cb)(struct sctp_chunk *))
+ {
++      struct sctp_datamsg *msg, *prev_msg = NULL;
+       struct sctp_outq *q = &asoc->outqueue;
++      struct sctp_chunk *chunk, *c;
+       struct sctp_transport *t;
+-      struct sctp_chunk *chunk;
+       list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
+               list_for_each_entry(chunk, &t->transmitted, transmitted_list)
+-                      cb(chunk);
++                      traverse_and_process();
+       list_for_each_entry(chunk, &q->retransmit, transmitted_list)
+-              cb(chunk);
++              traverse_and_process();
+       list_for_each_entry(chunk, &q->sacked, transmitted_list)
+-              cb(chunk);
++              traverse_and_process();
+       list_for_each_entry(chunk, &q->abandoned, transmitted_list)
+-              cb(chunk);
++              traverse_and_process();
+       list_for_each_entry(chunk, &q->out_chunk_list, list)
+-              cb(chunk);
++              traverse_and_process();
+ }
+ static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk,
+@@ -9461,9 +9476,9 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
+        * paths won't try to lock it and then oldsk.
+        */
+       lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
+-      sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w);
++      sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w);
+       sctp_assoc_migrate(assoc, newsk);
+-      sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w);
++      sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w);
+       /* If the association on the newsk is already closed before accept()
+        * is called, set RCV_SHUTDOWN flag.
+-- 
+2.25.1
+
index 37870de9a20e1949b76ff1606e0dac38eb66e0ec..13c46aca0fcfd98e2a85128d963b53d95e888974 100644 (file)
@@ -30,3 +30,7 @@ perf-probe-accept-the-instance-number-of-kretprobe-e.patch
 mm-add-kvfree_sensitive-for-freeing-sensitive-data-o.patch
 selftests-fix-flower-parent-qdisc.patch
 fanotify-fix-ignore-mask-logic-for-events-on-child-a.patch
+ipv4-fix-a-rcu-list-lock-in-fib_triestat_seq_show.patch
+iwlwifi-mvm-fix-nvm-check-for-3168-devices.patch
+sctp-fix-possibly-using-a-bad-saddr-with-a-given-dst.patch
+sctp-fix-refcount-bug-in-sctp_wfree.patch