| From 6596a0229541270fb8d38d989f91b78838e5e9da Mon Sep 17 00:00:00 2001 |
| From: Jiri Bohac <jbohac@suse.cz> |
| Date: Wed, 19 Jan 2022 10:22:53 +0100 |
| Subject: xfrm: fix MTU regression |
| |
| From: Jiri Bohac <jbohac@suse.cz> |
| |
| commit 6596a0229541270fb8d38d989f91b78838e5e9da upstream. |
| |
| Commit 749439bfac6e1a2932c582e2699f91d329658196 ("ipv6: fix udpv6 |
| sendmsg crash caused by too small MTU") breaks PMTU for xfrm. |
| |
| A Packet Too Big ICMPv6 message received in response to an ESP |
| packet will prevent all further communication through the tunnel |
| if the reported MTU minus the ESP overhead is smaller than 1280. |
| |
| E.g. in a case of a tunnel-mode ESP with sha256/aes the overhead |
| is 92 bytes. Receiving a PTB with MTU of 1371 or less will result |
| in all further packets in the tunnel dropped. A ping through the |
| tunnel fails with "ping: sendmsg: Invalid argument". |
| |
| Apparently the MTU on the xfrm route is smaller than 1280 and |
| fails the check inside ip6_setup_cork() added by 749439bf. |
| |
| We found this by debugging USGv6/ipv6ready failures. Failing |
| tests are: "Phase-2 Interoperability Test Scenario IPsec" / |
| 5.3.11 and 5.4.11 (Tunnel Mode: Fragmentation). |
| |
| Commit b515d2637276a3810d6595e10ab02c13bfd0b63a ("xfrm: |
| xfrm_state_mtu should return at least 1280 for ipv6") attempted |
| to fix this but caused another regression in TCP MSS calculations |
| and had to be reverted. |
| |
| The patch below fixes the situation by dropping the MTU |
| check and instead checking for the underflows described in the |
| 749439bf commit message. |
| |
| Signed-off-by: Jiri Bohac <jbohac@suse.cz> |
| Fixes: 749439bfac6e ("ipv6: fix udpv6 sendmsg crash caused by too small MTU") |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/ip6_output.c | 11 +++++++---- |
| 1 file changed, 7 insertions(+), 4 deletions(-) |
| |
| --- a/net/ipv6/ip6_output.c |
| +++ b/net/ipv6/ip6_output.c |
| @@ -1361,8 +1361,6 @@ static int ip6_setup_cork(struct sock *s |
| if (np->frag_size) |
| mtu = np->frag_size; |
| } |
| - if (mtu < IPV6_MIN_MTU) |
| - return -EINVAL; |
| cork->base.fragsize = mtu; |
| cork->base.gso_size = ipc6->gso_size; |
| cork->base.tx_flags = 0; |
| @@ -1424,8 +1422,6 @@ static int __ip6_append_data(struct sock |
| |
| fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + |
| (opt ? opt->opt_nflen : 0); |
| - maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - |
| - sizeof(struct frag_hdr); |
| |
| headersize = sizeof(struct ipv6hdr) + |
| (opt ? opt->opt_flen + opt->opt_nflen : 0) + |
| @@ -1433,6 +1429,13 @@ static int __ip6_append_data(struct sock |
| sizeof(struct frag_hdr) : 0) + |
| rt->rt6i_nfheader_len; |
| |
| + if (mtu < fragheaderlen || |
| + ((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr)) |
| + goto emsgsize; |
| + |
| + maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - |
| + sizeof(struct frag_hdr); |
| + |
| /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit |
| * the first fragment |
| */ |