From ca36436157b5e739a9b2c2dd36e89a955af9fc57 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 21 Feb 2019 00:43:04 -0500 Subject: [PATCH] patches for 4.14 Signed-off-by: Sasha Levin --- ...sure-all-pending-interrupts-are-hand.patch | 92 ++++++++++++++++++ ...issing-unlock-on-error-in-set_fan_di.patch | 37 ++++++++ .../net-fix-ipv6-prefix-route-residue.patch | 49 ++++++++++ ...edicated-counter-for-icmp_v4-redirec.patch | 93 +++++++++++++++++++ queue-4.14/series | 6 ++ ...memory-allocation-failure-at-socket-.patch | 43 +++++++++ ...flags-iff_up-before-calling-netif_rx.patch | 86 +++++++++++++++++ 7 files changed, 406 insertions(+) create mode 100644 queue-4.14/dsa-mv88e6xxx-ensure-all-pending-interrupts-are-hand.patch create mode 100644 queue-4.14/hwmon-lm80-fix-missing-unlock-on-error-in-set_fan_di.patch create mode 100644 queue-4.14/net-fix-ipv6-prefix-route-residue.patch create mode 100644 queue-4.14/net-ipv4-use-a-dedicated-counter-for-icmp_v4-redirec.patch create mode 100644 queue-4.14/series create mode 100644 queue-4.14/vsock-cope-with-memory-allocation-failure-at-socket-.patch create mode 100644 queue-4.14/vxlan-test-dev-flags-iff_up-before-calling-netif_rx.patch diff --git a/queue-4.14/dsa-mv88e6xxx-ensure-all-pending-interrupts-are-hand.patch b/queue-4.14/dsa-mv88e6xxx-ensure-all-pending-interrupts-are-hand.patch new file mode 100644 index 00000000000..245b4d17a9b --- /dev/null +++ b/queue-4.14/dsa-mv88e6xxx-ensure-all-pending-interrupts-are-hand.patch @@ -0,0 +1,92 @@ +From 2cf4f70c3353918d477db6c2a2f90db4bb8c2548 Mon Sep 17 00:00:00 2001 +From: John David Anglin +Date: Mon, 11 Feb 2019 13:40:21 -0500 +Subject: dsa: mv88e6xxx: Ensure all pending interrupts are handled prior to + exit + +[ Upstream commit 7c0db24cc431e2196d98a5d5ddaa9088e2fcbfe5 ] + +The GPIO interrupt controller on the espressobin board only supports edge interrupts. +If one enables the use of hardware interrupts in the device tree for the 88E6341, it is +possible to miss an edge. When this happens, the INTn pin on the Marvell switch is +stuck low and no further interrupts occur. + +I found after adding debug statements to mv88e6xxx_g1_irq_thread_work() that there is +a race in handling device interrupts (e.g. PHY link interrupts). Some interrupts are +directly cleared by reading the Global 1 status register. However, the device interrupt +flag, for example, is not cleared until all the unmasked SERDES and PHY ports are serviced. +This is done by reading the relevant SERDES and PHY status register. + +The code only services interrupts whose status bit is set at the time of reading its status +register. If an interrupt event occurs after its status is read and before all interrupts +are serviced, then this event will not be serviced and the INTn output pin will remain low. + +This is not a problem with polling or level interrupts since the handler will be called +again to process the event. However, it's a big problem when using level interrupts. + +The fix presented here is to add a loop around the code servicing switch interrupts. If +any pending interrupts remain after the current set has been handled, we loop and process +the new set. If there are no pending interrupts after servicing, we are sure that INTn has +gone high and we will get an edge when a new event occurs. + +Tested on espressobin board. + +Fixes: dc30c35be720 ("net: dsa: mv88e6xxx: Implement interrupt support.") +Signed-off-by: John David Anglin +Tested-by: Andrew Lunn +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/mv88e6xxx/chip.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 34998ecd9cc93..a3543d637736c 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -258,6 +258,7 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) + unsigned int sub_irq; + unsigned int n; + u16 reg; ++ u16 ctl1; + int err; + + mutex_lock(&chip->reg_lock); +@@ -267,13 +268,28 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) + if (err) + goto out; + +- for (n = 0; n < chip->g1_irq.nirqs; ++n) { +- if (reg & (1 << n)) { +- sub_irq = irq_find_mapping(chip->g1_irq.domain, n); +- handle_nested_irq(sub_irq); +- ++nhandled; ++ do { ++ for (n = 0; n < chip->g1_irq.nirqs; ++n) { ++ if (reg & (1 << n)) { ++ sub_irq = irq_find_mapping(chip->g1_irq.domain, ++ n); ++ handle_nested_irq(sub_irq); ++ ++nhandled; ++ } + } +- } ++ ++ mutex_lock(&chip->reg_lock); ++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); ++ if (err) ++ goto unlock; ++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ if (err) ++ goto out; ++ ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); ++ } while (reg & ctl1); ++ + out: + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); + } +-- +2.19.1 + diff --git a/queue-4.14/hwmon-lm80-fix-missing-unlock-on-error-in-set_fan_di.patch b/queue-4.14/hwmon-lm80-fix-missing-unlock-on-error-in-set_fan_di.patch new file mode 100644 index 00000000000..56ea6f7dc36 --- /dev/null +++ b/queue-4.14/hwmon-lm80-fix-missing-unlock-on-error-in-set_fan_di.patch @@ -0,0 +1,37 @@ +From 06c0dde175a2b64a42db500f2d9b980bb11a56a5 Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Wed, 26 Dec 2018 11:28:24 +0000 +Subject: hwmon: (lm80) Fix missing unlock on error in set_fan_div() + +[ Upstream commit 07bd14ccc3049f9c0147a91a4227a571f981601a ] + +Add the missing unlock before return from function set_fan_div() +in the error handling case. + +Fixes: c9c63915519b ("hwmon: (lm80) fix a missing check of the status of SMBus read") +Signed-off-by: Wei Yongjun +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/lm80.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c +index 0e30fa00204cd..f9b8e3e23a8e8 100644 +--- a/drivers/hwmon/lm80.c ++++ b/drivers/hwmon/lm80.c +@@ -393,8 +393,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + } + + rv = lm80_read_value(client, LM80_REG_FANDIV); +- if (rv < 0) ++ if (rv < 0) { ++ mutex_unlock(&data->update_lock); + return rv; ++ } + reg = (rv & ~(3 << (2 * (nr + 1)))) + | (data->fan_div[nr] << (2 * (nr + 1))); + lm80_write_value(client, LM80_REG_FANDIV, reg); +-- +2.19.1 + diff --git a/queue-4.14/net-fix-ipv6-prefix-route-residue.patch b/queue-4.14/net-fix-ipv6-prefix-route-residue.patch new file mode 100644 index 00000000000..721a9c4b42f --- /dev/null +++ b/queue-4.14/net-fix-ipv6-prefix-route-residue.patch @@ -0,0 +1,49 @@ +From 61922e35284017ede2e0b4c50e63296289e10f2f Mon Sep 17 00:00:00 2001 +From: Zhiqiang Liu +Date: Mon, 11 Feb 2019 10:57:46 +0800 +Subject: net: fix IPv6 prefix route residue + +[ Upstream commit e75913c93f7cd5f338ab373c34c93a655bd309cb ] + +Follow those steps: + # ip addr add 2001:123::1/32 dev eth0 + # ip addr add 2001:123:456::2/64 dev eth0 + # ip addr del 2001:123::1/32 dev eth0 + # ip addr del 2001:123:456::2/64 dev eth0 +and then prefix route of 2001:123::1/32 will still exist. + +This is because ipv6_prefix_equal in check_cleanup_prefix_route +func does not check whether two IPv6 addresses have the same +prefix length. If the prefix of one address starts with another +shorter address prefix, even though their prefix lengths are +different, the return value of ipv6_prefix_equal is true. + +Here I add a check of whether two addresses have the same prefix +to decide whether their prefixes are equal. + +Fixes: 5b84efecb7d9 ("ipv6 addrconf: don't cleanup prefix route for IFA_F_NOPREFIXROUTE") +Signed-off-by: Zhiqiang Liu +Reported-by: Wenhao Zhang +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 9ac6f62322946..c47161e92407b 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1124,7 +1124,8 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) + list_for_each_entry(ifa, &idev->addr_list, if_list) { + if (ifa == ifp) + continue; +- if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, ++ if (ifa->prefix_len != ifp->prefix_len || ++ !ipv6_prefix_equal(&ifa->addr, &ifp->addr, + ifp->prefix_len)) + continue; + if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) +-- +2.19.1 + diff --git a/queue-4.14/net-ipv4-use-a-dedicated-counter-for-icmp_v4-redirec.patch b/queue-4.14/net-ipv4-use-a-dedicated-counter-for-icmp_v4-redirec.patch new file mode 100644 index 00000000000..7474d99dfee --- /dev/null +++ b/queue-4.14/net-ipv4-use-a-dedicated-counter-for-icmp_v4-redirec.patch @@ -0,0 +1,93 @@ +From 44e2244ec6bb932ee5b3bf6e6e8f3504a26910c3 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 6 Feb 2019 19:18:04 +0100 +Subject: net: ipv4: use a dedicated counter for icmp_v4 redirect packets + +[ Upstream commit c09551c6ff7fe16a79a42133bcecba5fc2fc3291 ] + +According to the algorithm described in the comment block at the +beginning of ip_rt_send_redirect, the host should try to send +'ip_rt_redirect_number' ICMP redirect packets with an exponential +backoff and then stop sending them at all assuming that the destination +ignores redirects. +If the device has previously sent some ICMP error packets that are +rate-limited (e.g TTL expired) and continues to receive traffic, +the redirect packets will never be transmitted. This happens since +peer->rate_tokens will be typically greater than 'ip_rt_redirect_number' +and so it will never be reset even if the redirect silence timeout +(ip_rt_redirect_silence) has elapsed without receiving any packet +requiring redirects. + +Fix it by using a dedicated counter for the number of ICMP redirect +packets that has been sent by the host + +I have not been able to identify a given commit that introduced the +issue since ip_rt_send_redirect implements the same rate-limiting +algorithm from commit 1da177e4c3f4 ("Linux-2.6.12-rc2") + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + include/net/inetpeer.h | 1 + + net/ipv4/inetpeer.c | 1 + + net/ipv4/route.c | 7 +++++-- + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h +index 00b5e7825508a..74ff688568a0c 100644 +--- a/include/net/inetpeer.h ++++ b/include/net/inetpeer.h +@@ -39,6 +39,7 @@ struct inet_peer { + + u32 metrics[RTAX_MAX]; + u32 rate_tokens; /* rate limiting for ICMP */ ++ u32 n_redirects; + unsigned long rate_last; + /* + * Once inet_peer is queued for deletion (refcnt == 0), following field +diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c +index 64007ce87273e..f9cef27907ed4 100644 +--- a/net/ipv4/inetpeer.c ++++ b/net/ipv4/inetpeer.c +@@ -215,6 +215,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base, + atomic_set(&p->rid, 0); + p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; + p->rate_tokens = 0; ++ p->n_redirects = 0; + /* 60*HZ is arbitrary, but chosen enough high so that the first + * calculation of tokens is at its maximum. + */ +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 7afa8d2463d85..cb30f4e4e5533 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -904,13 +904,15 @@ void ip_rt_send_redirect(struct sk_buff *skb) + /* No redirected packets during ip_rt_redirect_silence; + * reset the algorithm. + */ +- if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) ++ if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) { + peer->rate_tokens = 0; ++ peer->n_redirects = 0; ++ } + + /* Too many ignored redirects; do not send anything + * set dst.rate_last to the last seen redirected packet. + */ +- if (peer->rate_tokens >= ip_rt_redirect_number) { ++ if (peer->n_redirects >= ip_rt_redirect_number) { + peer->rate_last = jiffies; + goto out_put_peer; + } +@@ -927,6 +929,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) + icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); + peer->rate_last = jiffies; + ++peer->rate_tokens; ++ ++peer->n_redirects; + #ifdef CONFIG_IP_ROUTE_VERBOSE + if (log_martians && + peer->rate_tokens == ip_rt_redirect_number) +-- +2.19.1 + diff --git a/queue-4.14/series b/queue-4.14/series new file mode 100644 index 00000000000..21a0d8bfcbd --- /dev/null +++ b/queue-4.14/series @@ -0,0 +1,6 @@ +dsa-mv88e6xxx-ensure-all-pending-interrupts-are-hand.patch +net-fix-ipv6-prefix-route-residue.patch +net-ipv4-use-a-dedicated-counter-for-icmp_v4-redirec.patch +vsock-cope-with-memory-allocation-failure-at-socket-.patch +vxlan-test-dev-flags-iff_up-before-calling-netif_rx.patch +hwmon-lm80-fix-missing-unlock-on-error-in-set_fan_di.patch diff --git a/queue-4.14/vsock-cope-with-memory-allocation-failure-at-socket-.patch b/queue-4.14/vsock-cope-with-memory-allocation-failure-at-socket-.patch new file mode 100644 index 00000000000..2220abccf43 --- /dev/null +++ b/queue-4.14/vsock-cope-with-memory-allocation-failure-at-socket-.patch @@ -0,0 +1,43 @@ +From c082e91d6db7880f59feee6e812fce40495345fe Mon Sep 17 00:00:00 2001 +From: Paolo Abeni +Date: Thu, 7 Feb 2019 14:13:18 +0100 +Subject: vsock: cope with memory allocation failure at socket creation time + +[ Upstream commit 225d9464268599a5b4d094d02ec17808e44c7553 ] + +In the unlikely event that the kmalloc call in vmci_transport_socket_init() +fails, we end-up calling vmci_transport_destruct() with a NULL vmci_trans() +and oopsing. + +This change addresses the above explicitly checking for zero vmci_trans() +at destruction time. + +Reported-by: Xiumei Mu +Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") +Signed-off-by: Paolo Abeni +Reviewed-by: Stefano Garzarella +Reviewed-by: Jorgen Hansen +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/vmci_transport.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c +index bf7c516444467..ad3f47a714f36 100644 +--- a/net/vmw_vsock/vmci_transport.c ++++ b/net/vmw_vsock/vmci_transport.c +@@ -1648,6 +1648,10 @@ static void vmci_transport_cleanup(struct work_struct *work) + + static void vmci_transport_destruct(struct vsock_sock *vsk) + { ++ /* transport can be NULL if we hit a failure at init() time */ ++ if (!vmci_trans(vsk)) ++ return; ++ + /* Ensure that the detach callback doesn't use the sk/vsk + * we are about to destruct. + */ +-- +2.19.1 + diff --git a/queue-4.14/vxlan-test-dev-flags-iff_up-before-calling-netif_rx.patch b/queue-4.14/vxlan-test-dev-flags-iff_up-before-calling-netif_rx.patch new file mode 100644 index 00000000000..83606e5df3f --- /dev/null +++ b/queue-4.14/vxlan-test-dev-flags-iff_up-before-calling-netif_rx.patch @@ -0,0 +1,86 @@ +From 4d9e6204e082a9002e072089d151a985551af0ec Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 7 Feb 2019 12:27:38 -0800 +Subject: vxlan: test dev->flags & IFF_UP before calling netif_rx() + +[ Upstream commit 4179cb5a4c924cd233eaadd081882425bc98f44e ] + +netif_rx() must be called under a strict contract. + +At device dismantle phase, core networking clears IFF_UP +and flush_all_backlogs() is called after rcu grace period +to make sure no incoming packet might be in a cpu backlog +and still referencing the device. + +Most drivers call netif_rx() from their interrupt handler, +and since the interrupts are disabled at device dismantle, +netif_rx() does not have to check dev->flags & IFF_UP + +Virtual drivers do not have this guarantee, and must +therefore make the check themselves. + +Otherwise we risk use-after-free and/or crashes. + +Note this patch also fixes a small issue that came +with commit ce6502a8f957 ("vxlan: fix a use after free +in vxlan_encap_bypass"), since the dev->stats.rx_dropped +change was done on the wrong device. + +Fixes: d342894c5d2f ("vxlan: virtual extensible lan") +Fixes: ce6502a8f957 ("vxlan: fix a use after free in vxlan_encap_bypass") +Signed-off-by: Eric Dumazet +Cc: Petr Machata +Cc: Ido Schimmel +Cc: Roopa Prabhu +Cc: Stefano Brivio +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c +index 13d39a72fe0d0..a1b40b9c4906e 100644 +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -2002,7 +2002,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, + struct pcpu_sw_netstats *tx_stats, *rx_stats; + union vxlan_addr loopback; + union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip; +- struct net_device *dev = skb->dev; ++ struct net_device *dev; + int len = skb->len; + + tx_stats = this_cpu_ptr(src_vxlan->dev->tstats); +@@ -2022,9 +2022,15 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, + #endif + } + ++ rcu_read_lock(); ++ dev = skb->dev; ++ if (unlikely(!(dev->flags & IFF_UP))) { ++ kfree_skb(skb); ++ goto drop; ++ } ++ + if (dst_vxlan->cfg.flags & VXLAN_F_LEARN) +- vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, 0, +- vni); ++ vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni); + + u64_stats_update_begin(&tx_stats->syncp); + tx_stats->tx_packets++; +@@ -2037,8 +2043,10 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, + rx_stats->rx_bytes += len; + u64_stats_update_end(&rx_stats->syncp); + } else { ++drop: + dev->stats.rx_dropped++; + } ++ rcu_read_unlock(); + } + + static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, +-- +2.19.1 + -- 2.47.2