summaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_output.c
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2021-03-19 11:27:58 +0100
committerSteffen Klassert <steffen.klassert@secunet.com>2021-03-24 09:58:19 +0100
commit68dc022d04eb0fd60a540e242dcb11ec1bee07e2 (patch)
treefe8b0d3445e69f691b73d7d6c3404e6db6e7ff48 /net/xfrm/xfrm_output.c
parentesp: delete NETIF_F_SCTP_CRC bit from features for esp offload (diff)
downloadlinux-68dc022d04eb0fd60a540e242dcb11ec1bee07e2.tar.xz
linux-68dc022d04eb0fd60a540e242dcb11ec1bee07e2.zip
xfrm: BEET mode doesn't support fragments for inner packets
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>
Diffstat (limited to 'net/xfrm/xfrm_output.c')
-rw-r--r--net/xfrm/xfrm_output.c13
1 files changed, 13 insertions, 0 deletions
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;