| From 31579f83146bacacc825537c897aebd321877b6f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 19 Mar 2021 18:27:58 +0800 |
| Subject: xfrm: BEET mode doesn't support fragments for inner packets |
| |
| From: Xin Long <lucien.xin@gmail.com> |
| |
| [ Upstream commit 68dc022d04eb0fd60a540e242dcb11ec1bee07e2 ] |
| |
| BEET mode replaces the IP(6) Headers with new IP(6) Headers when sending |
| packets. However, when it's a fragment before the replacement, currently |
| kernel keeps the fragment flag and replace the address field then encaps |
| it with ESP. It would cause in RX side the fragments to get reassembled |
| before decapping with ESP, which is incorrect. |
| |
| In Xiumei's testing, these fragments went over an xfrm interface and got |
| encapped with ESP in the device driver, and the traffic was broken. |
| |
| I don't have a good way to fix it, but only to warn this out in dmesg. |
| |
| Reported-by: Xiumei Mu <xmu@redhat.com> |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/xfrm/xfrm_output.c | 13 +++++++++++++ |
| 1 file changed, 13 insertions(+) |
| |
| diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c |
| index b81ca117dac7..e4cb0ff4dcf4 100644 |
| --- a/net/xfrm/xfrm_output.c |
| +++ b/net/xfrm/xfrm_output.c |
| @@ -660,6 +660,12 @@ static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) |
| { |
| int err; |
| |
| + if (x->outer_mode.encap == XFRM_MODE_BEET && |
| + ip_is_fragment(ip_hdr(skb))) { |
| + net_warn_ratelimited("BEET mode doesn't support inner IPv4 fragments\n"); |
| + return -EAFNOSUPPORT; |
| + } |
| + |
| err = xfrm4_tunnel_check_size(skb); |
| if (err) |
| return err; |
| @@ -705,8 +711,15 @@ out: |
| static int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb) |
| { |
| #if IS_ENABLED(CONFIG_IPV6) |
| + unsigned int ptr = 0; |
| int err; |
| |
| + if (x->outer_mode.encap == XFRM_MODE_BEET && |
| + ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL, NULL) >= 0) { |
| + net_warn_ratelimited("BEET mode doesn't support inner IPv6 fragments\n"); |
| + return -EAFNOSUPPORT; |
| + } |
| + |
| err = xfrm6_tunnel_check_size(skb); |
| if (err) |
| return err; |
| -- |
| 2.30.2 |
| |