From 498815c75780c0b38983bfc39e41b13ea49c7208 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 30 Mar 2020 15:45:11 +0200 Subject: [PATCH] 4.4-stable patches added patches: genirq-fix-reference-leaks-on-irq-affinity-notifiers.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 --- ...ence-leaks-on-irq-affinity-notifiers.patch | 60 +++++++++ queue-4.4/series | 5 + ...x-through-bpf_redirect-in-xiny-cases.patch | 124 ++++++++++++++++++ ...ec_ctx_len-check-in-xfrm_add_acquire.patch | 60 +++++++++ ...uctx-len-check-in-verify_sec_ctx_len.patch | 37 ++++++ ...fix-doulbe-free-in-xfrm_policy_timer.patch | 73 +++++++++++ 6 files changed, 359 insertions(+) create mode 100644 queue-4.4/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch create mode 100644 queue-4.4/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch create mode 100644 queue-4.4/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch create mode 100644 queue-4.4/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch create mode 100644 queue-4.4/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch diff --git a/queue-4.4/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch b/queue-4.4/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch new file mode 100644 index 00000000000..39c480bde7b --- /dev/null +++ b/queue-4.4/genirq-fix-reference-leaks-on-irq-affinity-notifiers.patch @@ -0,0 +1,60 @@ +From df81dfcfd6991d547653d46c051bac195cd182c1 Mon Sep 17 00:00:00 2001 +From: Edward Cree +Date: Fri, 13 Mar 2020 20:33:07 +0000 +Subject: genirq: Fix reference leaks on irq affinity notifiers + +From: Edward Cree + +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 +Signed-off-by: Thomas Gleixner +Acked-by: Ben Hutchings +Link: https://lkml.kernel.org/r/24f5983f-2ab5-e83a-44ee-a45b5f9300f5@solarflare.com +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/irq/manage.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -220,7 +220,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); + +@@ -320,7 +324,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.4/series b/queue-4.4/series index 0d28152587b..f1d2b8aa94a 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -57,3 +57,8 @@ 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 diff --git a/queue-4.4/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch b/queue-4.4/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch new file mode 100644 index 00000000000..92c4b09f7dd --- /dev/null +++ b/queue-4.4/vti-fix-packet-tx-through-bpf_redirect-in-xiny-cases.patch @@ -0,0 +1,124 @@ +From f1ed10264ed6b66b9cd5e8461cffce69be482356 Mon Sep 17 00:00:00 2001 +From: Nicolas Dichtel +Date: Tue, 4 Feb 2020 17:00:27 +0100 +Subject: vti[6]: fix packet tx through bpf_redirect() in XinY cases + +From: Nicolas Dichtel + +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 +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -195,17 +195,39 @@ static netdev_tx_t vti_xmit(struct sk_bu + int err; + + 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 +@@ -442,15 +442,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.4/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch b/queue-4.4/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch new file mode 100644 index 00000000000..2d91666190c --- /dev/null +++ b/queue-4.4/xfrm-add-the-missing-verify_sec_ctx_len-check-in-xfrm_add_acquire.patch @@ -0,0 +1,60 @@ +From a1a7e3a36e01ca6e67014f8cf673cb8e47be5550 Mon Sep 17 00:00:00 2001 +From: Xin Long +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 + +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 +Signed-off-by: Xin Long +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/xfrm/xfrm_user.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -2175,6 +2175,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 bad_policy; + + /* build an XP */ diff --git a/queue-4.4/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch b/queue-4.4/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch new file mode 100644 index 00000000000..966cb1d2217 --- /dev/null +++ b/queue-4.4/xfrm-fix-uctx-len-check-in-verify_sec_ctx_len.patch @@ -0,0 +1,37 @@ +From 171d449a028573b2f0acdc7f31ecbb045391b320 Mon Sep 17 00:00:00 2001 +From: Xin Long +Date: Sun, 9 Feb 2020 21:15:29 +0800 +Subject: xfrm: fix uctx len check in verify_sec_ctx_len + +From: Xin Long + +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 +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + 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.4/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch b/queue-4.4/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch new file mode 100644 index 00000000000..af81e3d15fa --- /dev/null +++ b/queue-4.4/xfrm-policy-fix-doulbe-free-in-xfrm_policy_timer.patch @@ -0,0 +1,73 @@ +From 4c59406ed00379c8663f8663d82b2537467ce9d7 Mon Sep 17 00:00:00 2001 +From: YueHaibing +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 + +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 +Acked-by: Timo Teräs +Acked-by: Herbert Xu +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/xfrm/xfrm_policy.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -330,7 +330,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); + -- 2.47.3