Skip to content

Commit b6c5734

Browse files
marceloleitnerdavem330
authored andcommitted
sctp: fix the handling of ICMP Frag Needed for too small MTUs
syzbot reported a hang involving SCTP, on which it kept flooding dmesg with the message: [ 246.742374] sctp: sctp_transport_update_pmtu: Reported pmtu 508 too low, using default minimum of 512 That happened because whenever SCTP hits an ICMP Frag Needed, it tries to adjust to the new MTU and triggers an immediate retransmission. But it didn't consider the fact that MTUs smaller than the SCTP minimum MTU allowed (512) would not cause the PMTU to change, and issued the retransmission anyway (thus leading to another ICMP Frag Needed, and so on). As IPv4 (ip_rt_min_pmtu=556) and IPv6 (IPV6_MIN_MTU=1280) minimum MTU are higher than that, sctp_transport_update_pmtu() is changed to re-fetch the PMTU that got set after our request, and with that, detect if there was an actual change or not. The fix, thus, skips the immediate retransmission if the received ICMP resulted in no change, in the hope that SCTP will select another path. Note: The value being used for the minimum MTU (512, SCTP_DEFAULT_MINSEGMENT) is not right and instead it should be (576, SCTP_MIN_PMTU), but such change belongs to another patch. Changes from v1: - do not disable PMTU discovery, in the light of commit 06ad391 ("[SCTP] Don't disable PMTU discovery when mtu is small") and as suggested by Xin Long. - changed the way to break the rtx loop by detecting if the icmp resulted in a change or not Changes from v2: none See-also: https://lkml.org/lkml/2017/12/22/811 Reported-by: syzbot <[email protected]> Signed-off-by: Marcelo Ricardo Leitner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cc35c3d commit b6c5734

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

include/net/sctp/structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ void sctp_transport_burst_limited(struct sctp_transport *);
966966
void sctp_transport_burst_reset(struct sctp_transport *);
967967
unsigned long sctp_transport_timeout(struct sctp_transport *);
968968
void sctp_transport_reset(struct sctp_transport *t);
969-
void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu);
969+
bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu);
970970
void sctp_transport_immediate_rtx(struct sctp_transport *);
971971
void sctp_transport_dst_release(struct sctp_transport *t);
972972
void sctp_transport_dst_confirm(struct sctp_transport *t);

net/sctp/input.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,12 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
406406
*/
407407
return;
408408

409-
/* Update transports view of the MTU */
410-
sctp_transport_update_pmtu(t, pmtu);
409+
/* Update transports view of the MTU. Return if no update was needed.
410+
* If an update wasn't needed/possible, it also doesn't make sense to
411+
* try to retransmit now.
412+
*/
413+
if (!sctp_transport_update_pmtu(t, pmtu))
414+
return;
411415

412416
/* Update association pmtu. */
413417
sctp_assoc_sync_pmtu(asoc);

net/sctp/transport.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,28 +248,37 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
248248
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
249249
}
250250

251-
void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
251+
bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
252252
{
253253
struct dst_entry *dst = sctp_transport_dst_check(t);
254+
bool change = true;
254255

255256
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
256-
pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n",
257-
__func__, pmtu, SCTP_DEFAULT_MINSEGMENT);
258-
/* Use default minimum segment size and disable
259-
* pmtu discovery on this transport.
260-
*/
261-
t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
262-
} else {
263-
t->pathmtu = pmtu;
257+
pr_warn_ratelimited("%s: Reported pmtu %d too low, using default minimum of %d\n",
258+
__func__, pmtu, SCTP_DEFAULT_MINSEGMENT);
259+
/* Use default minimum segment instead */
260+
pmtu = SCTP_DEFAULT_MINSEGMENT;
264261
}
262+
pmtu = SCTP_TRUNC4(pmtu);
265263

266264
if (dst) {
267265
dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu);
268266
dst = sctp_transport_dst_check(t);
269267
}
270268

271-
if (!dst)
269+
if (!dst) {
272270
t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk);
271+
dst = t->dst;
272+
}
273+
274+
if (dst) {
275+
/* Re-fetch, as under layers may have a higher minimum size */
276+
pmtu = SCTP_TRUNC4(dst_mtu(dst));
277+
change = t->pathmtu != pmtu;
278+
}
279+
t->pathmtu = pmtu;
280+
281+
return change;
273282
}
274283

275284
/* Caches the dst entry and source address for a transport's destination

0 commit comments

Comments
 (0)