diff options
| author | Michael Tuexen <tuexen@FreeBSD.org> | 2026-02-20 21:21:37 +0000 |
|---|---|---|
| committer | Michael Tuexen <tuexen@FreeBSD.org> | 2026-02-20 21:21:37 +0000 |
| commit | e1886559ea477add82a0a86cddf728f6778f1603 (patch) | |
| tree | 7fc3c49e1d2204b4019bc7da6b40b408d23caa7f | |
| parent | 1602f0013bddc7b59b0b8de94c0e6cd742ffc9be (diff) | |
tcp: improve validation of received TCP over UDP packets
Reviewed by: glebius, pouria
MFC after: 3 days
Sponsored by: Netflix, Inc.
Differential Revision: https://reviews.freebsd.org/D55410
| -rw-r--r-- | sys/netinet/tcp_subr.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 6b0aa76527f4..6a6eef32e777 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -575,7 +575,7 @@ tcp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, #endif struct udphdr *uh; struct tcphdr *th; - int thlen; + int len, thlen; uint16_t port; TCPSTAT_INC(tcps_tunneled_pkts); @@ -619,15 +619,27 @@ tcp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, switch (iph->ip_v) { #ifdef INET case IPVERSION: - iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); - tcp_input_with_port(&m, &off, IPPROTO_TCP, port); + len = ntohs(iph->ip_len) - sizeof(struct udphdr); + if (len != m->m_pkthdr.len) { + TCPSTAT_INC(tcps_tunneled_errs); + goto out; + } else { + iph->ip_len = htons(len); + tcp_input_with_port(&m, &off, IPPROTO_TCP, port); + } break; #endif #ifdef INET6 case IPV6_VERSION >> 4: ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); - tcp6_input_with_port(&m, &off, IPPROTO_TCP, port); + len = ntohs(ip6->ip6_plen) - sizeof(struct udphdr); + if (len + sizeof(struct ip6_hdr) != m->m_pkthdr.len) { + TCPSTAT_INC(tcps_tunneled_errs); + goto out; + } else { + ip6->ip6_plen = htons(len); + tcp6_input_with_port(&m, &off, IPPROTO_TCP, port); + } break; #endif default: |
