From: Greg Kroah-Hartman Date: Mon, 3 Jul 2017 11:51:43 +0000 (+0200) Subject: 4.11-stable patches X-Git-Tag: v3.18.60~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=43c806dc7f104d2a9300aa29a159fc338e903a86;p=thirdparty%2Fkernel%2Fstable-queue.git 4.11-stable patches added patches: xfrm-fix-stack-access-out-of-bounds-with-config_xfrm_sub_policy.patch xfrm-move-xfrm_garbage_collect-out-of-xfrm_policy_flush.patch xfrm-null-dereference-on-allocation-failure.patch xfrm-oops-on-error-in-pfkey_msg2xfrm_state.patch xfrm6-fix-ipv6-payload_len-in-xfrm6_transport_finish.patch --- diff --git a/queue-4.11/series b/queue-4.11/series index 4577d94273d..8393b1d7b0e 100644 --- a/queue-4.11/series +++ b/queue-4.11/series @@ -52,3 +52,8 @@ x86-mm-fix-boot-crash-caused-by-incorrect-loop-count-calculation-in-sync_global_ pinctrl-amd-use-regular-interrupt-instead-of-chained.patch mm-vmalloc.c-huge-vmap-fail-gracefully-on-unexpected-huge-vmap-mappings.patch xen-blkback-don-t-free-be-structure-too-early.patch +xfrm6-fix-ipv6-payload_len-in-xfrm6_transport_finish.patch +xfrm-move-xfrm_garbage_collect-out-of-xfrm_policy_flush.patch +xfrm-fix-stack-access-out-of-bounds-with-config_xfrm_sub_policy.patch +xfrm-null-dereference-on-allocation-failure.patch +xfrm-oops-on-error-in-pfkey_msg2xfrm_state.patch diff --git a/queue-4.11/xfrm-fix-stack-access-out-of-bounds-with-config_xfrm_sub_policy.patch b/queue-4.11/xfrm-fix-stack-access-out-of-bounds-with-config_xfrm_sub_policy.patch new file mode 100644 index 00000000000..22f9878c7d5 --- /dev/null +++ b/queue-4.11/xfrm-fix-stack-access-out-of-bounds-with-config_xfrm_sub_policy.patch @@ -0,0 +1,121 @@ +From 9b3eb54106cf6acd03f07cf0ab01c13676a226c2 Mon Sep 17 00:00:00 2001 +From: Sabrina Dubroca +Date: Wed, 3 May 2017 16:43:19 +0200 +Subject: xfrm: fix stack access out of bounds with CONFIG_XFRM_SUB_POLICY + +From: Sabrina Dubroca + +commit 9b3eb54106cf6acd03f07cf0ab01c13676a226c2 upstream. + +When CONFIG_XFRM_SUB_POLICY=y, xfrm_dst stores a copy of the flowi for +that dst. Unfortunately, the code that allocates and fills this copy +doesn't care about what type of flowi (flowi, flowi4, flowi6) gets +passed. In multiple code paths (from raw_sendmsg, from TCP when +replying to a FIN, in vxlan, geneve, and gre), the flowi that gets +passed to xfrm is actually an on-stack flowi4, so we end up reading +stuff from the stack past the end of the flowi4 struct. + +Since xfrm_dst->origin isn't used anywhere following commit +ca116922afa8 ("xfrm: Eliminate "fl" and "pol" args to +xfrm_bundle_ok()."), just get rid of it. xfrm_dst->partner isn't used +either, so get rid of that too. + +Fixes: 9d6ec938019c ("ipv4: Use flowi4 in public route lookup interfaces.") +Signed-off-by: Sabrina Dubroca +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/xfrm.h | 10 ---------- + net/xfrm/xfrm_policy.c | 47 ----------------------------------------------- + 2 files changed, 57 deletions(-) + +--- a/include/net/xfrm.h ++++ b/include/net/xfrm.h +@@ -945,10 +945,6 @@ struct xfrm_dst { + struct flow_cache_object flo; + struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; + int num_pols, num_xfrms; +-#ifdef CONFIG_XFRM_SUB_POLICY +- struct flowi *origin; +- struct xfrm_selector *partner; +-#endif + u32 xfrm_genid; + u32 policy_genid; + u32 route_mtu_cached; +@@ -964,12 +960,6 @@ static inline void xfrm_dst_destroy(stru + dst_release(xdst->route); + if (likely(xdst->u.dst.xfrm)) + xfrm_state_put(xdst->u.dst.xfrm); +-#ifdef CONFIG_XFRM_SUB_POLICY +- kfree(xdst->origin); +- xdst->origin = NULL; +- kfree(xdst->partner); +- xdst->partner = NULL; +-#endif + } + #endif + +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1793,43 +1793,6 @@ free_dst: + goto out; + } + +-#ifdef CONFIG_XFRM_SUB_POLICY +-static int xfrm_dst_alloc_copy(void **target, const void *src, int size) +-{ +- if (!*target) { +- *target = kmalloc(size, GFP_ATOMIC); +- if (!*target) +- return -ENOMEM; +- } +- +- memcpy(*target, src, size); +- return 0; +-} +-#endif +- +-static int xfrm_dst_update_parent(struct dst_entry *dst, +- const struct xfrm_selector *sel) +-{ +-#ifdef CONFIG_XFRM_SUB_POLICY +- struct xfrm_dst *xdst = (struct xfrm_dst *)dst; +- return xfrm_dst_alloc_copy((void **)&(xdst->partner), +- sel, sizeof(*sel)); +-#else +- return 0; +-#endif +-} +- +-static int xfrm_dst_update_origin(struct dst_entry *dst, +- const struct flowi *fl) +-{ +-#ifdef CONFIG_XFRM_SUB_POLICY +- struct xfrm_dst *xdst = (struct xfrm_dst *)dst; +- return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl)); +-#else +- return 0; +-#endif +-} +- + static int xfrm_expand_policies(const struct flowi *fl, u16 family, + struct xfrm_policy **pols, + int *num_pols, int *num_xfrms) +@@ -1901,16 +1864,6 @@ xfrm_resolve_and_create_bundle(struct xf + + xdst = (struct xfrm_dst *)dst; + xdst->num_xfrms = err; +- if (num_pols > 1) +- err = xfrm_dst_update_parent(dst, &pols[1]->selector); +- else +- err = xfrm_dst_update_origin(dst, fl); +- if (unlikely(err)) { +- dst_free(dst); +- XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); +- return ERR_PTR(err); +- } +- + xdst->num_pols = num_pols; + memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); + xdst->policy_genid = atomic_read(&pols[0]->genid); diff --git a/queue-4.11/xfrm-move-xfrm_garbage_collect-out-of-xfrm_policy_flush.patch b/queue-4.11/xfrm-move-xfrm_garbage_collect-out-of-xfrm_policy_flush.patch new file mode 100644 index 00000000000..4a1b58fe63e --- /dev/null +++ b/queue-4.11/xfrm-move-xfrm_garbage_collect-out-of-xfrm_policy_flush.patch @@ -0,0 +1,79 @@ +From 138437f591dd9a42d53c6fed1a3c85e02678851c Mon Sep 17 00:00:00 2001 +From: Hangbin Liu +Date: Sun, 11 Jun 2017 09:44:20 +0800 +Subject: xfrm: move xfrm_garbage_collect out of xfrm_policy_flush + +From: Hangbin Liu + +commit 138437f591dd9a42d53c6fed1a3c85e02678851c upstream. + +Now we will force to do garbage collection if any policy removed in +xfrm_policy_flush(). But during xfrm_net_exit(). We call flow_cache_fini() +first and set set fc->percpu to NULL. Then after we call xfrm_policy_fini() +-> frxm_policy_flush() -> flow_cache_flush(), we will get NULL pointer +dereference when check percpu_empty. The code path looks like: + +flow_cache_fini() + - fc->percpu = NULL +xfrm_policy_fini() + - xfrm_policy_flush() + - xfrm_garbage_collect() + - flow_cache_flush() + - flow_cache_percpu_empty() + - fcp = per_cpu_ptr(fc->percpu, cpu) + +To reproduce, just add ipsec in netns and then remove the netns. + +v2: +As Xin Long suggested, since only two other places need to call it. move +xfrm_garbage_collect() outside xfrm_policy_flush(). + +v3: +Fix subject mismatch after v2 fix. + +Fixes: 35db06912189 ("xfrm: do the garbage collection after flushing policy") +Signed-off-by: Hangbin Liu +Reviewed-by: Xin Long +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/key/af_key.c | 2 ++ + net/xfrm/xfrm_policy.c | 4 ---- + net/xfrm/xfrm_user.c | 1 + + 3 files changed, 3 insertions(+), 4 deletions(-) + +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -2755,6 +2755,8 @@ static int pfkey_spdflush(struct sock *s + int err, err2; + + err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, true); ++ if (!err) ++ xfrm_garbage_collect(net); + err2 = unicast_flush_resp(sk, hdr); + if (err || err2) { + if (err == -ESRCH) /* empty table - old silent behavior */ +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1006,10 +1006,6 @@ int xfrm_policy_flush(struct net *net, u + err = -ESRCH; + out: + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +- +- if (cnt) +- xfrm_garbage_collect(net); +- + return err; + } + EXPORT_SYMBOL(xfrm_policy_flush); +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -1999,6 +1999,7 @@ static int xfrm_flush_policy(struct sk_b + return 0; + return err; + } ++ xfrm_garbage_collect(net); + + c.data.type = type; + c.event = nlh->nlmsg_type; diff --git a/queue-4.11/xfrm-null-dereference-on-allocation-failure.patch b/queue-4.11/xfrm-null-dereference-on-allocation-failure.patch new file mode 100644 index 00000000000..5289ed6a45f --- /dev/null +++ b/queue-4.11/xfrm-null-dereference-on-allocation-failure.patch @@ -0,0 +1,34 @@ +From e747f64336fc15e1c823344942923195b800aa1e Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 14 Jun 2017 13:35:37 +0300 +Subject: xfrm: NULL dereference on allocation failure + +From: Dan Carpenter + +commit e747f64336fc15e1c823344942923195b800aa1e upstream. + +The default error code in pfkey_msg2xfrm_state() is -ENOBUFS. We +added a new call to security_xfrm_state_alloc() which sets "err" to zero +so there several places where we can return ERR_PTR(0) if kmalloc() +fails. The caller is expecting error pointers so it leads to a NULL +dereference. + +Fixes: df71837d5024 ("[LSM-IPSec]: Security association restriction.") +Signed-off-by: Dan Carpenter +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/key/af_key.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -1157,6 +1157,7 @@ static struct xfrm_state * pfkey_msg2xfr + goto out; + } + ++ err = -ENOBUFS; + key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; + if (sa->sadb_sa_auth) { + int keysize = 0; diff --git a/queue-4.11/xfrm-oops-on-error-in-pfkey_msg2xfrm_state.patch b/queue-4.11/xfrm-oops-on-error-in-pfkey_msg2xfrm_state.patch new file mode 100644 index 00000000000..ce4f8beea42 --- /dev/null +++ b/queue-4.11/xfrm-oops-on-error-in-pfkey_msg2xfrm_state.patch @@ -0,0 +1,71 @@ +From 1e3d0c2c70cd3edb5deed186c5f5c75f2b84a633 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 14 Jun 2017 13:34:05 +0300 +Subject: xfrm: Oops on error in pfkey_msg2xfrm_state() + +From: Dan Carpenter + +commit 1e3d0c2c70cd3edb5deed186c5f5c75f2b84a633 upstream. + +There are some missing error codes here so we accidentally return NULL +instead of an error pointer. It results in a NULL pointer dereference. + +Fixes: df71837d5024 ("[LSM-IPSec]: Security association restriction.") +Signed-off-by: Dan Carpenter +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/key/af_key.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -1169,8 +1169,10 @@ static struct xfrm_state * pfkey_msg2xfr + if (key) + keysize = (key->sadb_key_bits + 7) / 8; + x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); +- if (!x->aalg) ++ if (!x->aalg) { ++ err = -ENOMEM; + goto out; ++ } + strcpy(x->aalg->alg_name, a->name); + x->aalg->alg_key_len = 0; + if (key) { +@@ -1189,8 +1191,10 @@ static struct xfrm_state * pfkey_msg2xfr + goto out; + } + x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL); +- if (!x->calg) ++ if (!x->calg) { ++ err = -ENOMEM; + goto out; ++ } + strcpy(x->calg->alg_name, a->name); + x->props.calgo = sa->sadb_sa_encrypt; + } else { +@@ -1204,8 +1208,10 @@ static struct xfrm_state * pfkey_msg2xfr + if (key) + keysize = (key->sadb_key_bits + 7) / 8; + x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); +- if (!x->ealg) ++ if (!x->ealg) { ++ err = -ENOMEM; + goto out; ++ } + strcpy(x->ealg->alg_name, a->name); + x->ealg->alg_key_len = 0; + if (key) { +@@ -1250,8 +1256,10 @@ static struct xfrm_state * pfkey_msg2xfr + struct xfrm_encap_tmpl *natt; + + x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL); +- if (!x->encap) ++ if (!x->encap) { ++ err = -ENOMEM; + goto out; ++ } + + natt = x->encap; + n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; diff --git a/queue-4.11/xfrm6-fix-ipv6-payload_len-in-xfrm6_transport_finish.patch b/queue-4.11/xfrm6-fix-ipv6-payload_len-in-xfrm6_transport_finish.patch new file mode 100644 index 00000000000..64dc1b55be4 --- /dev/null +++ b/queue-4.11/xfrm6-fix-ipv6-payload_len-in-xfrm6_transport_finish.patch @@ -0,0 +1,40 @@ +From 7c88e21aefcf86fb41b48b2e04528db5a30fbe18 Mon Sep 17 00:00:00 2001 +From: Yossi Kuperman +Date: Thu, 22 Jun 2017 11:37:10 +0300 +Subject: xfrm6: Fix IPv6 payload_len in xfrm6_transport_finish + +From: Yossi Kuperman + +commit 7c88e21aefcf86fb41b48b2e04528db5a30fbe18 upstream. + +IPv6 payload length indicates the size of the payload, including any +extension headers. + +In xfrm6_transport_finish, ipv6_hdr(skb)->payload_len is set to the +payload size only, regardless of the presence of any extension headers. +After ESP GRO transport mode decapsulation, ipv6_rcv trims the packet +according to the wrong payload_len, thus corrupting the packet. + +Set payload_len to account for extension headers as well. + +Fixes: 7785bba299a8 ("esp: Add a software GRO codepath") +Signed-off-by: Yossi Kuperman +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv6/xfrm6_input.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv6/xfrm6_input.c ++++ b/net/ipv6/xfrm6_input.c +@@ -43,8 +43,8 @@ int xfrm6_transport_finish(struct sk_buf + return 1; + #endif + +- ipv6_hdr(skb)->payload_len = htons(skb->len); + __skb_push(skb, skb->data - skb_network_header(skb)); ++ ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + + if (xo && (xo->flags & XFRM_GRO)) { + skb_mac_header_rebuild(skb);