Commit 4c86d777 authored by Steffen Klassert's avatar Steffen Klassert

xfrm: Don't use sk_family for socket policy lookups

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: default avatarDmitry Vyukov <dvyukov@google.com>
Tested-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent c282222a
...@@ -1248,7 +1248,7 @@ static inline int policy_to_flow_dir(int dir) ...@@ -1248,7 +1248,7 @@ static inline int policy_to_flow_dir(int dir)
} }
static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
const struct flowi *fl) const struct flowi *fl, u16 family)
{ {
struct xfrm_policy *pol; struct xfrm_policy *pol;
...@@ -1256,8 +1256,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, ...@@ -1256,8 +1256,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
again: again:
pol = rcu_dereference(sk->sk_policy[dir]); pol = rcu_dereference(sk->sk_policy[dir]);
if (pol != NULL) { if (pol != NULL) {
bool match = xfrm_selector_match(&pol->selector, fl, bool match = xfrm_selector_match(&pol->selector, fl, family);
sk->sk_family);
int err = 0; int err = 0;
if (match) { if (match) {
...@@ -2253,7 +2252,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, ...@@ -2253,7 +2252,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
sk = sk_const_to_full_sk(sk); sk = sk_const_to_full_sk(sk);
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
num_pols = 1; 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, err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms); &num_pols, &num_xfrms);
if (err < 0) if (err < 0)
...@@ -2532,7 +2531,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -2532,7 +2531,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
pol = NULL; pol = NULL;
sk = sk_to_full_sk(sk); sk = sk_to_full_sk(sk);
if (sk && sk->sk_policy[dir]) { 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)) { if (IS_ERR(pol)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment