git: 18c38eda39bb - stable/14 - if_ovpn: cope with loops

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Mon, 20 May 2024 07:57:42 UTC
The branch stable/14 has been updated by kp:

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

commit 18c38eda39bb8162ddce9acc4de4d6e4bbf48ef0
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-05-13 10:06:47 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-05-20 07:39:52 +0000

    if_ovpn: cope with loops
    
    User misconfiguration may lead to routing loops where we try to send the tunnel
    packet into the tunnel. This eventually leads to stack overflows and panics.
    
    Avoid this using if_tunnel_check_nesting(), which will drop the packet if we're
    looping or we hit three layers of nested tunnels.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    
    (cherry picked from commit 59a6666ec91d71f97aaae5195bbfafd9d422db2e)
---
 sys/net/if_ovpn.c                | 9 +++++++++
 tests/sys/net/if_ovpn/if_ovpn.sh | 8 ++++++++
 2 files changed, 17 insertions(+)

diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index 1b5d419fe58b..7af669c69511 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -255,6 +255,7 @@ static const char ovpnname[] = "ovpn";
 static const char ovpngroupname[] = "openvpn";
 
 static MALLOC_DEFINE(M_OVPN, ovpnname, "OpenVPN DCO Interface");
+#define	MTAG_OVPN_LOOP		0x6f76706e /* ovpn */
 
 SYSCTL_DECL(_net_link);
 static SYSCTL_NODE(_net_link, IFT_OTHER, openvpn, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
@@ -1858,6 +1859,14 @@ ovpn_transmit_to_peer(struct ifnet *ifp, struct mbuf *m,
 	if (af != 0)
 		BPF_MTAP2(ifp, &af, sizeof(af), m);
 
+	if (__predict_false(if_tunnel_check_nesting(ifp, m, MTAG_OVPN_LOOP, 3))) {
+		if (_ovpn_lock_trackerp != NULL)
+			OVPN_RUNLOCK(sc);
+		OVPN_COUNTER_ADD(sc, lost_data_pkts_out, 1);
+		m_freem(m);
+		return (ELOOP);
+	}
+
 	len = m->m_pkthdr.len;
 	MPASS(len <= ifp->if_mtu);
 
diff --git a/tests/sys/net/if_ovpn/if_ovpn.sh b/tests/sys/net/if_ovpn/if_ovpn.sh
index bbaffa0bce73..88df430aead6 100644
--- a/tests/sys/net/if_ovpn/if_ovpn.sh
+++ b/tests/sys/net/if_ovpn/if_ovpn.sh
@@ -95,6 +95,10 @@ atf_test_case "4in4" "cleanup"
 
 	echo 'foo' | jexec b nc -u -w 2 192.0.2.1 1194
 	atf_check -s exit:0 -o ignore jexec b ping -c 3 198.51.100.1
+
+	# Test routing loop protection
+	jexec b route add 192.0.2.1 198.51.100.1
+	atf_check -s exit:2 -o ignore jexec b ping -t 1 -c 1 198.51.100.1
 }
 
 4in4_cleanup()
@@ -386,6 +390,10 @@ atf_test_case "6in6" "cleanup"
 
 	atf_check -s exit:0 -o ignore jexec b ping6 -c 3 2001:db8:1::1
 	atf_check -s exit:0 -o ignore jexec b ping6 -c 3 -z 16 2001:db8:1::1
+
+	# Test routing loop protection
+	jexec b route add -6 2001:db8::1 2001:db8:1::1
+	atf_check -s exit:2 -o ignore jexec b ping6 -t 1 -c 3 2001:db8:1::1
 }
 
 6in6_cleanup()