]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2020 13:45:29 +0000 (15:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2020 13:45:29 +0000 (15:45 +0200)
added patches:
genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch
netfilter-nft_fwd_netdev-validate-family-and-chain-type.patch
vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch
xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch
xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch
xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch

queue-4.9/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch [new file with mode: 0644]
queue-4.9/netfilter-nft_fwd_netdev-validate-family-and-chain-type.patch [new file with mode: 0644]
queue-4.9/series
queue-4.9/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch [new file with mode: 0644]
queue-4.9/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch [new file with mode: 0644]
queue-4.9/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch [new file with mode: 0644]
queue-4.9/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch [new file with mode: 0644]

diff --git a/queue-4.9/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch b/queue-4.9/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch
new file mode 100644 (file)
index 0000000..e7281cc
--- /dev/null
@@ -0,0 +1,60 @@
+From df81dfcfd6991d547653d46c051bac195cd182c1 Mon Sep 17 00:00:00 2001
+From: Edward Cree <ecree@solarflare.com>
+Date: Fri, 13 Mar 2020 20:33:07 +0000
+Subject: genirq: Fix reference leaks on irq affinity notifiers
+
+From: Edward Cree <ecree@solarflare.com>
+
+commit df81dfcfd6991d547653d46c051bac195cd182c1 upstream.
+
+The handling of notify->work did not properly maintain notify->kref in two
+ cases:
+1) where the work was already scheduled, another irq_set_affinity_locked()
+   would get the ref and (no-op-ly) schedule the work.  Thus when
+   irq_affinity_notify() ran, it would drop the original ref but not the
+   additional one.
+2) when cancelling the (old) work in irq_set_affinity_notifier(), if there
+   was outstanding work a ref had been got for it but was never put.
+Fix both by checking the return values of the work handling functions
+ (schedule_work() for (1) and cancel_work_sync() for (2)) and put the
+ extra ref if the return value indicates preexisting work.
+
+Fixes: cd7eab44e994 ("genirq: Add IRQ affinity notifiers")
+Fixes: 59c39840f5ab ("genirq: Prevent use-after-free and work list corruption")
+Signed-off-by: Edward Cree <ecree@solarflare.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Ben Hutchings <ben@decadent.org.uk>
+Link: https://lkml.kernel.org/r/24f5983f-2ab5-e83a-44ee-a45b5f9300f5@solarflare.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/irq/manage.c |   11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/kernel/irq/manage.c
++++ b/kernel/irq/manage.c
+@@ -233,7 +233,11 @@ int irq_set_affinity_locked(struct irq_d
+       if (desc->affinity_notify) {
+               kref_get(&desc->affinity_notify->kref);
+-              schedule_work(&desc->affinity_notify->work);
++              if (!schedule_work(&desc->affinity_notify->work)) {
++                      /* Work was already scheduled, drop our extra ref */
++                      kref_put(&desc->affinity_notify->kref,
++                               desc->affinity_notify->release);
++              }
+       }
+       irqd_set(data, IRQD_AFFINITY_SET);
+@@ -333,7 +337,10 @@ irq_set_affinity_notifier(unsigned int i
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       if (old_notify) {
+-              cancel_work_sync(&old_notify->work);
++              if (cancel_work_sync(&old_notify->work)) {
++                      /* Pending work had a ref, put that one too */
++                      kref_put(&old_notify->kref, old_notify->release);
++              }
+               kref_put(&old_notify->kref, old_notify->release);
+       }
diff --git a/queue-4.9/netfilter-nft_fwd_netdev-validate-family-and-chain-type.patch b/queue-4.9/netfilter-nft_fwd_netdev-validate-family-and-chain-type.patch
new file mode 100644 (file)
index 0000000..2874729
--- /dev/null
@@ -0,0 +1,43 @@
+From 76a109fac206e158eb3c967af98c178cff738e6a Mon Sep 17 00:00:00 2001
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 23 Mar 2020 14:27:16 +0100
+Subject: netfilter: nft_fwd_netdev: validate family and chain type
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 76a109fac206e158eb3c967af98c178cff738e6a upstream.
+
+Make sure the forward action is only used from ingress.
+
+Fixes: 39e6dea28adc ("netfilter: nf_tables: add forward expression to the netdev family")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nft_fwd_netdev.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/net/netfilter/nft_fwd_netdev.c
++++ b/net/netfilter/nft_fwd_netdev.c
+@@ -62,6 +62,13 @@ nla_put_failure:
+       return -1;
+ }
++static int nft_fwd_validate(const struct nft_ctx *ctx,
++                          const struct nft_expr *expr,
++                          const struct nft_data **data)
++{
++      return nft_chain_validate_hooks(ctx->chain, (1 << NF_NETDEV_INGRESS));
++}
++
+ static struct nft_expr_type nft_fwd_netdev_type;
+ static const struct nft_expr_ops nft_fwd_netdev_ops = {
+       .type           = &nft_fwd_netdev_type,
+@@ -69,6 +76,7 @@ static const struct nft_expr_ops nft_fwd
+       .eval           = nft_fwd_netdev_eval,
+       .init           = nft_fwd_netdev_init,
+       .dump           = nft_fwd_netdev_dump,
++      .validate       = nft_fwd_validate,
+ };
+ static struct nft_expr_type nft_fwd_netdev_type __read_mostly = {
index 77ddff8a76b038c5f14e0e5eeadc88510f8fb99c..34a1134597f8e16d401a4dae599564b622a91b02 100644 (file)
@@ -61,3 +61,9 @@ perf-probe-do-not-depend-on-dwfl_module_addrsym.patch
 scripts-dtc-remove-redundant-yyloc-global-declaration.patch
 scsi-sd-fix-optimal-i-o-size-for-devices-that-change-reported-values.patch
 mac80211-mark-station-unauthorized-before-key-removal.patch
+genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch
+vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch
+xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch
+xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch
+xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch
+netfilter-nft_fwd_netdev-validate-family-and-chain-type.patch
diff --git a/queue-4.9/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch b/queue-4.9/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch
new file mode 100644 (file)
index 0000000..defcde4
--- /dev/null
@@ -0,0 +1,124 @@
+From f1ed10264ed6b66b9cd5e8461cffce69be482356 Mon Sep 17 00:00:00 2001
+From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date: Tue, 4 Feb 2020 17:00:27 +0100
+Subject: vti[6]: fix packet tx through bpf_redirect() in XinY cases
+
+From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+commit f1ed10264ed6b66b9cd5e8461cffce69be482356 upstream.
+
+I forgot the 4in6/6in4 cases in my previous patch. Let's fix them.
+
+Fixes: 95224166a903 ("vti[6]: fix packet tx through bpf_redirect()")
+Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/ipv4/Kconfig   |    1 +
+ net/ipv4/ip_vti.c  |   36 +++++++++++++++++++++++++++++-------
+ net/ipv6/ip6_vti.c |   32 +++++++++++++++++++++++++-------
+ 3 files changed, 55 insertions(+), 14 deletions(-)
+
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -298,6 +298,7 @@ config SYN_COOKIES
+ config NET_IPVTI
+       tristate "Virtual (secure) IP: tunneling"
++      depends on IPV6 || IPV6=n
+       select INET_TUNNEL
+       select NET_IP_TUNNEL
+       depends on INET_XFRM_MODE_TUNNEL
+--- a/net/ipv4/ip_vti.c
++++ b/net/ipv4/ip_vti.c
+@@ -208,17 +208,39 @@ static netdev_tx_t vti_xmit(struct sk_bu
+       int mtu;
+       if (!dst) {
+-              struct rtable *rt;
++              switch (skb->protocol) {
++              case htons(ETH_P_IP): {
++                      struct rtable *rt;
+-              fl->u.ip4.flowi4_oif = dev->ifindex;
+-              fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
+-              rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
+-              if (IS_ERR(rt)) {
++                      fl->u.ip4.flowi4_oif = dev->ifindex;
++                      fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
++                      rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
++                      if (IS_ERR(rt)) {
++                              dev->stats.tx_carrier_errors++;
++                              goto tx_error_icmp;
++                      }
++                      dst = &rt->dst;
++                      skb_dst_set(skb, dst);
++                      break;
++              }
++#if IS_ENABLED(CONFIG_IPV6)
++              case htons(ETH_P_IPV6):
++                      fl->u.ip6.flowi6_oif = dev->ifindex;
++                      fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
++                      dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
++                      if (dst->error) {
++                              dst_release(dst);
++                              dst = NULL;
++                              dev->stats.tx_carrier_errors++;
++                              goto tx_error_icmp;
++                      }
++                      skb_dst_set(skb, dst);
++                      break;
++#endif
++              default:
+                       dev->stats.tx_carrier_errors++;
+                       goto tx_error_icmp;
+               }
+-              dst = &rt->dst;
+-              skb_dst_set(skb, dst);
+       }
+       dst_hold(dst);
+--- a/net/ipv6/ip6_vti.c
++++ b/net/ipv6/ip6_vti.c
+@@ -454,15 +454,33 @@ vti6_xmit(struct sk_buff *skb, struct ne
+       int mtu;
+       if (!dst) {
+-              fl->u.ip6.flowi6_oif = dev->ifindex;
+-              fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+-              dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
+-              if (dst->error) {
+-                      dst_release(dst);
+-                      dst = NULL;
++              switch (skb->protocol) {
++              case htons(ETH_P_IP): {
++                      struct rtable *rt;
++
++                      fl->u.ip4.flowi4_oif = dev->ifindex;
++                      fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
++                      rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
++                      if (IS_ERR(rt))
++                              goto tx_err_link_failure;
++                      dst = &rt->dst;
++                      skb_dst_set(skb, dst);
++                      break;
++              }
++              case htons(ETH_P_IPV6):
++                      fl->u.ip6.flowi6_oif = dev->ifindex;
++                      fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
++                      dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
++                      if (dst->error) {
++                              dst_release(dst);
++                              dst = NULL;
++                              goto tx_err_link_failure;
++                      }
++                      skb_dst_set(skb, dst);
++                      break;
++              default:
+                       goto tx_err_link_failure;
+               }
+-              skb_dst_set(skb, dst);
+       }
+       dst_hold(dst);
diff --git a/queue-4.9/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch b/queue-4.9/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch
new file mode 100644 (file)
index 0000000..3c7dd98
--- /dev/null
@@ -0,0 +1,60 @@
+From a1a7e3a36e01ca6e67014f8cf673cb8e47be5550 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Sun, 9 Feb 2020 21:16:38 +0800
+Subject: xfrm: add the missing verify_sec_ctx_len check in xfrm_add_acquire
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit a1a7e3a36e01ca6e67014f8cf673cb8e47be5550 upstream.
+
+Without doing verify_sec_ctx_len() check in xfrm_add_acquire(), it may be
+out-of-bounds to access uctx->ctx_str with uctx->ctx_len, as noticed by
+syz:
+
+  BUG: KASAN: slab-out-of-bounds in selinux_xfrm_alloc_user+0x237/0x430
+  Read of size 768 at addr ffff8880123be9b4 by task syz-executor.1/11650
+
+  Call Trace:
+   dump_stack+0xe8/0x16e
+   print_address_description.cold.3+0x9/0x23b
+   kasan_report.cold.4+0x64/0x95
+   memcpy+0x1f/0x50
+   selinux_xfrm_alloc_user+0x237/0x430
+   security_xfrm_policy_alloc+0x5c/0xb0
+   xfrm_policy_construct+0x2b1/0x650
+   xfrm_add_acquire+0x21d/0xa10
+   xfrm_user_rcv_msg+0x431/0x6f0
+   netlink_rcv_skb+0x15a/0x410
+   xfrm_netlink_rcv+0x6d/0x90
+   netlink_unicast+0x50e/0x6a0
+   netlink_sendmsg+0x8ae/0xd40
+   sock_sendmsg+0x133/0x170
+   ___sys_sendmsg+0x834/0x9a0
+   __sys_sendmsg+0x100/0x1e0
+   do_syscall_64+0xe5/0x660
+   entry_SYSCALL_64_after_hwframe+0x6a/0xdf
+
+So fix it by adding the missing verify_sec_ctx_len check there.
+
+Fixes: 980ebd25794f ("[IPSEC]: Sync series - acquire insert")
+Reported-by: Hangbin Liu <liuhangbin@gmail.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xfrm/xfrm_user.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -2178,6 +2178,9 @@ static int xfrm_add_acquire(struct sk_bu
+       err = verify_newpolicy_info(&ua->policy);
+       if (err)
+               goto free_state;
++      err = verify_sec_ctx_len(attrs);
++      if (err)
++              goto free_state;
+       /*   build an XP */
+       xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
diff --git a/queue-4.9/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch b/queue-4.9/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch
new file mode 100644 (file)
index 0000000..966cb1d
--- /dev/null
@@ -0,0 +1,37 @@
+From 171d449a028573b2f0acdc7f31ecbb045391b320 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Sun, 9 Feb 2020 21:15:29 +0800
+Subject: xfrm: fix uctx len check in verify_sec_ctx_len
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit 171d449a028573b2f0acdc7f31ecbb045391b320 upstream.
+
+It's not sufficient to do 'uctx->len != (sizeof(struct xfrm_user_sec_ctx) +
+uctx->ctx_len)' check only, as uctx->len may be greater than nla_len(rt),
+in which case it will cause slab-out-of-bounds when accessing uctx->ctx_str
+later.
+
+This patch is to fix it by return -EINVAL when uctx->len > nla_len(rt).
+
+Fixes: df71837d5024 ("[LSM-IPSec]: Security association restriction.")
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xfrm/xfrm_user.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -109,7 +109,8 @@ static inline int verify_sec_ctx_len(str
+               return 0;
+       uctx = nla_data(rt);
+-      if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
++      if (uctx->len > nla_len(rt) ||
++          uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
+               return -EINVAL;
+       return 0;
diff --git a/queue-4.9/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch b/queue-4.9/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch
new file mode 100644 (file)
index 0000000..5d5e8aa
--- /dev/null
@@ -0,0 +1,73 @@
+From 4c59406ed00379c8663f8663d82b2537467ce9d7 Mon Sep 17 00:00:00 2001
+From: YueHaibing <yuehaibing@huawei.com>
+Date: Mon, 23 Mar 2020 15:32:39 +0800
+Subject: xfrm: policy: Fix doulbe free in xfrm_policy_timer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: YueHaibing <yuehaibing@huawei.com>
+
+commit 4c59406ed00379c8663f8663d82b2537467ce9d7 upstream.
+
+After xfrm_add_policy add a policy, its ref is 2, then
+
+                             xfrm_policy_timer
+                               read_lock
+                               xp->walk.dead is 0
+                               ....
+                               mod_timer()
+xfrm_policy_kill
+  policy->walk.dead = 1
+  ....
+  del_timer(&policy->timer)
+    xfrm_pol_put //ref is 1
+  xfrm_pol_put  //ref is 0
+    xfrm_policy_destroy
+      call_rcu
+                                 xfrm_pol_hold //ref is 1
+                               read_unlock
+                               xfrm_pol_put //ref is 0
+                                 xfrm_policy_destroy
+                                  call_rcu
+
+xfrm_policy_destroy is called twice, which may leads to
+double free.
+
+Call Trace:
+RIP: 0010:refcount_warn_saturate+0x161/0x210
+...
+ xfrm_policy_timer+0x522/0x600
+ call_timer_fn+0x1b3/0x5e0
+ ? __xfrm_decode_session+0x2990/0x2990
+ ? msleep+0xb0/0xb0
+ ? _raw_spin_unlock_irq+0x24/0x40
+ ? __xfrm_decode_session+0x2990/0x2990
+ ? __xfrm_decode_session+0x2990/0x2990
+ run_timer_softirq+0x5c5/0x10e0
+
+Fix this by use write_lock_bh in xfrm_policy_kill.
+
+Fixes: ea2dea9dacc2 ("xfrm: remove policy lock when accessing policy->walk.dead")
+Signed-off-by: YueHaibing <yuehaibing@huawei.com>
+Acked-by: Timo Teräs <timo.teras@iki.fi>
+Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xfrm/xfrm_policy.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -336,7 +336,9 @@ EXPORT_SYMBOL(xfrm_policy_destroy);
+ static void xfrm_policy_kill(struct xfrm_policy *policy)
+ {
++      write_lock_bh(&policy->lock);
+       policy->walk.dead = 1;
++      write_unlock_bh(&policy->lock);
+       atomic_inc(&policy->genid);