From eec23fb54a2c8bf940a78b603e8c265c44fd50e3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 10 Sep 2019 15:37:12 +0100 Subject: [PATCH] 4.9-stable patches added patches: ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch xfrm-clean-up-xfrm-protocol-checks.patch --- ...kb-leak-in-ip6frag_expire_frag_queue.patch | 58 +++++++++ queue-4.9/series | 2 + .../xfrm-clean-up-xfrm-protocol-checks.patch | 116 ++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 queue-4.9/ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch create mode 100644 queue-4.9/xfrm-clean-up-xfrm-protocol-checks.patch diff --git a/queue-4.9/ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch b/queue-4.9/ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch new file mode 100644 index 00000000000..765ef9825a8 --- /dev/null +++ b/queue-4.9/ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch @@ -0,0 +1,58 @@ +From 47d3d7fdb10a21c223036b58bd70ffdc24a472c4 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 3 May 2019 08:24:44 -0700 +Subject: ip6: fix skb leak in ip6frag_expire_frag_queue() + +From: Eric Dumazet + +commit 47d3d7fdb10a21c223036b58bd70ffdc24a472c4 upstream. + +Since ip6frag_expire_frag_queue() now pulls the head skb +from frag queue, we should no longer use skb_get(), since +this leads to an skb leak. + +Stefan Bader initially reported a problem in 4.4.stable [1] caused +by the skb_get(), so this patch should also fix this issue. + +296583.091021] kernel BUG at /build/linux-6VmqmP/linux-4.4.0/net/core/skbuff.c:1207! +[296583.091734] Call Trace: +[296583.091749] [] __pskb_pull_tail+0x50/0x350 +[296583.091764] [] _decode_session6+0x26a/0x400 +[296583.091779] [] __xfrm_decode_session+0x39/0x50 +[296583.091795] [] icmpv6_route_lookup+0xf0/0x1c0 +[296583.091809] [] icmp6_send+0x5e1/0x940 +[296583.091823] [] ? __netif_receive_skb+0x18/0x60 +[296583.091838] [] ? netif_receive_skb_internal+0x32/0xa0 +[296583.091858] [] ? ixgbe_clean_rx_irq+0x594/0xac0 [ixgbe] +[296583.091876] [] ? nf_ct_net_exit+0x50/0x50 [nf_defrag_ipv6] +[296583.091893] [] icmpv6_send+0x21/0x30 +[296583.091906] [] ip6_expire_frag_queue+0xe0/0x120 +[296583.091921] [] nf_ct_frag6_expire+0x1f/0x30 [nf_defrag_ipv6] +[296583.091938] [] call_timer_fn+0x37/0x140 +[296583.091951] [] ? nf_ct_net_exit+0x50/0x50 [nf_defrag_ipv6] +[296583.091968] [] run_timer_softirq+0x234/0x330 +[296583.091982] [] __do_softirq+0x109/0x2b0 + +Fixes: d4289fcc9b16 ("net: IP6 defrag: use rbtrees for IPv6 defrag") +Signed-off-by: Eric Dumazet +Reported-by: Stefan Bader +Cc: Peter Oskolkov +Cc: Florian Westphal +Signed-off-by: David S. Miller +Signed-off-by: Baolin Wang +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/ipv6_frag.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/include/net/ipv6_frag.h ++++ b/include/net/ipv6_frag.h +@@ -94,7 +94,6 @@ ip6frag_expire_frag_queue(struct net *ne + goto out; + + head->dev = dev; +- skb_get(head); + spin_unlock(&fq->q.lock); + + icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); diff --git a/queue-4.9/series b/queue-4.9/series index 4228e5b287f..391856f3fd3 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -3,3 +3,5 @@ alsa-hda-realtek-fix-overridden-device-specific-initialization.patch sched-fair-don-t-assign-runtime-for-throttled-cfs_rq.patch drm-vmwgfx-fix-double-free-in-vmw_recv_msg.patch powerpc-tm-fix-fp-vmx-unavailable-exceptions-inside-a-transaction.patch +xfrm-clean-up-xfrm-protocol-checks.patch +ip6-fix-skb-leak-in-ip6frag_expire_frag_queue.patch diff --git a/queue-4.9/xfrm-clean-up-xfrm-protocol-checks.patch b/queue-4.9/xfrm-clean-up-xfrm-protocol-checks.patch new file mode 100644 index 00000000000..1329960a857 --- /dev/null +++ b/queue-4.9/xfrm-clean-up-xfrm-protocol-checks.patch @@ -0,0 +1,116 @@ +From dbb2483b2a46fbaf833cfb5deb5ed9cace9c7399 Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Fri, 22 Mar 2019 16:26:19 -0700 +Subject: xfrm: clean up xfrm protocol checks + +From: Cong Wang + +commit dbb2483b2a46fbaf833cfb5deb5ed9cace9c7399 upstream. + +In commit 6a53b7593233 ("xfrm: check id proto in validate_tmpl()") +I introduced a check for xfrm protocol, but according to Herbert +IPSEC_PROTO_ANY should only be used as a wildcard for lookup, so +it should be removed from validate_tmpl(). + +And, IPSEC_PROTO_ANY is expected to only match 3 IPSec-specific +protocols, this is why xfrm_state_flush() could still miss +IPPROTO_ROUTING, which leads that those entries are left in +net->xfrm.state_all before exit net. Fix this by replacing +IPSEC_PROTO_ANY with zero. + +This patch also extracts the check from validate_tmpl() to +xfrm_id_proto_valid() and uses it in parse_ipsecrequest(). +With this, no other protocols should be added into xfrm. + +Fixes: 6a53b7593233 ("xfrm: check id proto in validate_tmpl()") +Reported-by: syzbot+0bf0519d6e0de15914fe@syzkaller.appspotmail.com +Cc: Steffen Klassert +Cc: Herbert Xu +Signed-off-by: Cong Wang +Acked-by: Herbert Xu +Signed-off-by: Steffen Klassert +Signed-off-by: Zubin Mithra +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/xfrm.h | 17 +++++++++++++++++ + net/key/af_key.c | 4 +++- + net/xfrm/xfrm_state.c | 2 +- + net/xfrm/xfrm_user.c | 14 +------------- + 4 files changed, 22 insertions(+), 15 deletions(-) + +--- a/include/net/xfrm.h ++++ b/include/net/xfrm.h +@@ -1297,6 +1297,23 @@ static inline int xfrm_state_kern(const + return atomic_read(&x->tunnel_users); + } + ++static inline bool xfrm_id_proto_valid(u8 proto) ++{ ++ switch (proto) { ++ case IPPROTO_AH: ++ case IPPROTO_ESP: ++ case IPPROTO_COMP: ++#if IS_ENABLED(CONFIG_IPV6) ++ case IPPROTO_ROUTING: ++ case IPPROTO_DSTOPTS: ++#endif ++ return true; ++ default: ++ return false; ++ } ++} ++ ++/* IPSEC_PROTO_ANY only matches 3 IPsec protocols, 0 could match all. */ + static inline int xfrm_id_proto_match(u8 proto, u8 userproto) + { + return (!userproto || proto == userproto || +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -1969,8 +1969,10 @@ parse_ipsecrequest(struct xfrm_policy *x + + if (rq->sadb_x_ipsecrequest_mode == 0) + return -EINVAL; ++ if (!xfrm_id_proto_valid(rq->sadb_x_ipsecrequest_proto)) ++ return -EINVAL; + +- t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */ ++ t->id.proto = rq->sadb_x_ipsecrequest_proto; + if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0) + return -EINVAL; + t->mode = mode; +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -2168,7 +2168,7 @@ void xfrm_state_fini(struct net *net) + unsigned int sz; + + flush_work(&net->xfrm.state_hash_work); +- xfrm_state_flush(net, IPSEC_PROTO_ANY, false); ++ xfrm_state_flush(net, 0, false); + flush_work(&xfrm_state_gc_work); + + WARN_ON(!list_empty(&net->xfrm.state_all)); +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -1452,20 +1452,8 @@ static int validate_tmpl(int nr, struct + return -EINVAL; + } + +- switch (ut[i].id.proto) { +- case IPPROTO_AH: +- case IPPROTO_ESP: +- case IPPROTO_COMP: +-#if IS_ENABLED(CONFIG_IPV6) +- case IPPROTO_ROUTING: +- case IPPROTO_DSTOPTS: +-#endif +- case IPSEC_PROTO_ANY: +- break; +- default: ++ if (!xfrm_id_proto_valid(ut[i].id.proto)) + return -EINVAL; +- } +- + } + + return 0; -- 2.47.3