Skip to content

Commit

Permalink
xfrm: Use actual socket sk instead of skb socket for xfrm_output_resume
Browse files Browse the repository at this point in the history
[ Upstream commit 9ab1265 ]

A situation can occur where the interface bound to the sk is different
to the interface bound to the sk attached to the skb. The interface
bound to the sk is the correct one however this information is lost inside
xfrm_output2 and instead the sk on the skb is used in xfrm_output_resume
instead. This assumes that the sk bound interface and the bound interface
attached to the sk within the skb are the same which can lead to lookup
failures inside ip_route_me_harder resulting in the packet being dropped.

We have an l2tp v3 tunnel with ipsec protection. The tunnel is in the
global VRF however we have an encapsulated dot1q tunnel interface that
is within a different VRF. We also have a mangle rule that marks the
packets causing them to be processed inside ip_route_me_harder.

Prior to commit 31c70d5 ("l2tp: keep original skb ownership") this
worked fine as the sk attached to the skb was changed from the dot1q
encapsulated interface to the sk for the tunnel which meant the interface
bound to the sk and the interface bound to the skb were identical.
Commit 46d6c5a ("netfilter: use actual socket sk rather than skb sk
when routing harder") fixed some of these issues however a similar
problem existed in the xfrm code.

Fixes: 31c70d5 ("l2tp: keep original skb ownership")
Signed-off-by: Evan Nimmo <evan.nimmo@alliedtelesis.co.nz>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Evann-atl authored and gregkh committed Apr 14, 2021
1 parent 88da40f commit 1d0d9d6
Show file tree
Hide file tree
Showing 6 changed files with 10 additions and 10 deletions.
2 changes: 1 addition & 1 deletion include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
int xfrm_trans_queue(struct sk_buff *skb,
int (*finish)(struct net *, struct sock *,
struct sk_buff *));
int xfrm_output_resume(struct sk_buff *skb, int err);
int xfrm_output_resume(struct sock *sk, struct sk_buff *skb, int err);
int xfrm_output(struct sock *sk, struct sk_buff *skb);

#if IS_ENABLED(CONFIG_NET_PKTGEN)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/ah4.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static void ah_output_done(struct crypto_async_request *base, int err)
}

kfree(AH_SKB_CB(skb)->tmp);
xfrm_output_resume(skb, err);
xfrm_output_resume(skb->sk, skb, err);
}

static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ static void esp_output_done(struct crypto_async_request *base, int err)
x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
esp_output_tail_tcp(x, skb);
else
xfrm_output_resume(skb, err);
xfrm_output_resume(skb->sk, skb, err);
}
}

Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/ah6.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ static void ah6_output_done(struct crypto_async_request *base, int err)
}

kfree(AH_SKB_CB(skb)->tmp);
xfrm_output_resume(skb, err);
xfrm_output_resume(skb->sk, skb, err);
}

static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ static void esp_output_done(struct crypto_async_request *base, int err)
x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
esp_output_tail_tcp(x, skb);
else
xfrm_output_resume(skb, err);
xfrm_output_resume(skb->sk, skb, err);
}
}

Expand Down
10 changes: 5 additions & 5 deletions net/xfrm/xfrm_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,22 +503,22 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
return err;
}

int xfrm_output_resume(struct sk_buff *skb, int err)
int xfrm_output_resume(struct sock *sk, struct sk_buff *skb, int err)
{
struct net *net = xs_net(skb_dst(skb)->xfrm);

while (likely((err = xfrm_output_one(skb, err)) == 0)) {
nf_reset_ct(skb);

err = skb_dst(skb)->ops->local_out(net, skb->sk, skb);
err = skb_dst(skb)->ops->local_out(net, sk, skb);
if (unlikely(err != 1))
goto out;

if (!skb_dst(skb)->xfrm)
return dst_output(net, skb->sk, skb);
return dst_output(net, sk, skb);

err = nf_hook(skb_dst(skb)->ops->family,
NF_INET_POST_ROUTING, net, skb->sk, skb,
NF_INET_POST_ROUTING, net, sk, skb,
NULL, skb_dst(skb)->dev, xfrm_output2);
if (unlikely(err != 1))
goto out;
Expand All @@ -534,7 +534,7 @@ EXPORT_SYMBOL_GPL(xfrm_output_resume);

static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
{
return xfrm_output_resume(skb, 1);
return xfrm_output_resume(sk, skb, 1);
}

static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb)
Expand Down

0 comments on commit 1d0d9d6

Please sign in to comment.