--- /dev/null
+From 4c86d77743a54fb2d8a4d18a037a074c892bb3be Mon Sep 17 00:00:00 2001
+From: Steffen Klassert <steffen.klassert@secunet.com>
+Date: Tue, 14 Feb 2017 07:43:56 +0100
+Subject: xfrm: Don't use sk_family for socket policy lookups
+
+From: Steffen Klassert <steffen.klassert@secunet.com>
+
+commit 4c86d77743a54fb2d8a4d18a037a074c892bb3be upstream.
+
+On IPv4-mapped IPv6 addresses sk_family is AF_INET6,
+but the flow informations are created based on AF_INET.
+So the routing set up 'struct flowi4' but we try to
+access 'struct flowi6' what leads to an out of bounds
+access. Fix this by using the family we get with the
+dst_entry, like we do it for the standard policy lookup.
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xfrm/xfrm_policy.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -1211,15 +1211,14 @@ static inline int policy_to_flow_dir(int
+ }
+
+ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
+- const struct flowi *fl)
++ const struct flowi *fl, u16 family)
+ {
+ struct xfrm_policy *pol;
+ struct net *net = sock_net(sk);
+
+ read_lock_bh(&net->xfrm.xfrm_policy_lock);
+ if ((pol = sk->sk_policy[dir]) != NULL) {
+- bool match = xfrm_selector_match(&pol->selector, fl,
+- sk->sk_family);
++ bool match = xfrm_selector_match(&pol->selector, fl, family);
+ int err = 0;
+
+ if (match) {
+@@ -2150,7 +2149,7 @@ struct dst_entry *xfrm_lookup(struct net
+
+ if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
+ num_pols = 1;
+- pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
++ pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family);
+ err = xfrm_expand_policies(fl, family, pols,
+ &num_pols, &num_xfrms);
+ if (err < 0)
+@@ -2428,7 +2427,7 @@ int __xfrm_policy_check(struct sock *sk,
+
+ pol = NULL;
+ if (sk && sk->sk_policy[dir]) {
+- pol = xfrm_sk_policy_lookup(sk, dir, &fl);
++ pol = xfrm_sk_policy_lookup(sk, dir, &fl, family);
+ if (IS_ERR(pol)) {
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
+ return 0;