git: c8cc66928b8b - stable/13 - icmp6: Improve validation of PMTU

From: Kornel Dulęba <kd_at_FreeBSD.org>
Date: Tue, 16 Aug 2022 08:21:47 UTC
The branch stable/13 has been updated by kd:

URL: https://cgit.FreeBSD.org/src/commit/?id=c8cc66928b8bba07b3c50ab346035848ab685e03

commit c8cc66928b8bba07b3c50ab346035848ab685e03
Author:     Kornel Dulęba <kd@FreeBSD.org>
AuthorDate: 2022-08-16 08:16:50 +0000
Commit:     Kornel Dulęba <kd@FreeBSD.org>
CommitDate: 2022-08-16 08:16:50 +0000

    icmp6: Improve validation of PMTU
    
    Currently we accept any pmtu between IPV6_MMTU(1280B) and the link mtu.
    In some network topologies could allow a bad actor to perform a DOS attack.
    Contrary to IPv4 in IPv6 oversized packets are dropped, and a ICMP
    PACKET_TOO_BIG message is sent back to the sender.
    After receiving an ICMPv6 packet with pmtu bigger than the
    current one the victim will start sending frames that will be dropped
    a router with reduced MTU.
    Although it will eventually receive another message with correct pmtu,
    an attacker can still just inject their spoofed packets frequently
    enough to overwrite the correct value.
    This issue is described in detail in RFC8201, section 6.
    Fix this by checking the current pmtu, and accepting the new one only
    if it's smaller.
    
    Approved by:    mw(mentor)
    Reviewed by:    tuexen
    MFC after:      1 week
    Sponsored by:   Stormshield
    Obtained from:  Semihalf
    Differential Revision: https://reviews.freebsd.org/D35871
    
    (cherry picked from commit 82042465c3b5477fc4f44be36077eab11b6b511b)
---
 sys/netinet6/icmp6.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index f4a5574084fd..dd3444d42750 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1113,6 +1113,7 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
 	struct mbuf *m = ip6cp->ip6c_m;	/* will be necessary for scope issue */
 	u_int mtu = ntohl(icmp6->icmp6_mtu);
 	struct in_conninfo inc;
+	uint32_t max_mtu;
 
 #if 0
 	/*
@@ -1153,7 +1154,11 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
 	if (in6_setscope(&inc.inc6_faddr, m->m_pkthdr.rcvif, NULL))
 		return;
 
-	if (mtu < tcp_maxmtu6(&inc, NULL)) {
+	max_mtu = tcp_hc_getmtu(&inc);
+	if (max_mtu == 0)
+		max_mtu = tcp_maxmtu6(&inc, NULL);
+
+	if (mtu < max_mtu) {
 		tcp_hc_updatemtu(&inc, mtu);
 		ICMP6STAT_INC(icp6s_pmtuchg);
 	}