Skip to content

Commit 6596a02

Browse files
jiribohacklassert
authored andcommitted
xfrm: fix MTU regression
Commit 749439b ("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 749439b. 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 b515d26 ("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 749439b commit message. Signed-off-by: Jiri Bohac <[email protected]> Fixes: 749439b ("ipv6: fix udpv6 sendmsg crash caused by too small MTU") Signed-off-by: Steffen Klassert <[email protected]>
1 parent de8a820 commit 6596a02

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

net/ipv6/ip6_output.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,8 +1408,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
14081408
if (np->frag_size)
14091409
mtu = np->frag_size;
14101410
}
1411-
if (mtu < IPV6_MIN_MTU)
1412-
return -EINVAL;
14131411
cork->base.fragsize = mtu;
14141412
cork->base.gso_size = ipc6->gso_size;
14151413
cork->base.tx_flags = 0;
@@ -1471,15 +1469,20 @@ static int __ip6_append_data(struct sock *sk,
14711469

14721470
fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
14731471
(opt ? opt->opt_nflen : 0);
1474-
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
1475-
sizeof(struct frag_hdr);
14761472

14771473
headersize = sizeof(struct ipv6hdr) +
14781474
(opt ? opt->opt_flen + opt->opt_nflen : 0) +
14791475
(dst_allfrag(&rt->dst) ?
14801476
sizeof(struct frag_hdr) : 0) +
14811477
rt->rt6i_nfheader_len;
14821478

1479+
if (mtu < fragheaderlen ||
1480+
((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr))
1481+
goto emsgsize;
1482+
1483+
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
1484+
sizeof(struct frag_hdr);
1485+
14831486
/* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
14841487
* the first fragment
14851488
*/

0 commit comments

Comments
 (0)