Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102628745
D16851.id57763.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D16851.id57763.diff
View Options
Index: sys/netinet/dccp.h
===================================================================
--- /dev/null
+++ sys/netinet/dccp.h
@@ -0,0 +1,64 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Tom Jones <thj@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef _NETINET_DCCP_H_
+#define _NETINET_DCCP_H_
+
+__FBSDID("$FreeBSD$");
+
+/* DCCP protocol header as per RFC4340 */
+struct dccphdr {
+ uint16_t d_sport;
+ uint16_t d_dport;
+ uint8_t d_doff;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t d_cscov:4,
+ d_ccval:4;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ uint8_t d_ccval:4,
+ d_cscov:4;
+#endif
+ uint16_t d_cksum;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t d_res:3,
+ d_type:4,
+ d_x:1;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ uint8_t d_x:1,
+ d_type:4,
+ d_res:3;
+#endif
+ uint8_t d_seq[6];
+};
+
+#define DCCP_SHORTHDR 12
+#define DCCP_LONGHDR 16
+#define DCCP_EXTHDR 0x80
+
+#endif /* _NETINET_DCCP_H */
Index: sys/netinet/icmp6.h
===================================================================
--- sys/netinet/icmp6.h
+++ sys/netinet/icmp6.h
@@ -156,6 +156,7 @@
#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */
#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized next header */
#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized option */
+#define ICMP6_PARAMPROB_FRAGHDRCHAIN 3 /* first fragment has incomplete header chain */
#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
@@ -587,6 +588,7 @@
uint64_t icp6errs_paramprob_header;
uint64_t icp6errs_paramprob_nextheader;
uint64_t icp6errs_paramprob_option;
+ uint64_t icp6errs_paramprob_fraghdrchain;
uint64_t icp6errs_redirect; /* we regard redirect as an error here */
uint64_t icp6errs_unknown;
};
@@ -626,6 +628,8 @@
#define icp6s_oparamprob_nextheader \
icp6s_outerrhist.icp6errs_paramprob_nextheader
#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
+#define icp6s_oparamprob_fraghdrchain \
+ icp6s_outerrhist.icp6errs_paramprob_fraghdrchain
#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
uint64_t icp6s_pmtuchg; /* path MTU changes */
Index: sys/netinet/in.h
===================================================================
--- sys/netinet/in.h
+++ sys/netinet/in.h
@@ -169,7 +169,7 @@
#define IPPROTO_BLT 30 /* Bulk Data Transfer */
#define IPPROTO_NSP 31 /* Network Services */
#define IPPROTO_INP 32 /* Merit Internodal */
-#define IPPROTO_SEP 33 /* Sequential Exchange */
+#define IPPROTO_DCCP 33 /* Datagram Congestion Control Protocol */
#define IPPROTO_3PC 34 /* Third Party Connect */
#define IPPROTO_IDPR 35 /* InterDomain Policy Routing */
#define IPPROTO_XTP 36 /* XTP */
Index: sys/netinet6/frag6.c
===================================================================
--- sys/netinet6/frag6.c
+++ sys/netinet6/frag6.c
@@ -67,6 +67,13 @@
#include <netinet/in_systm.h> /* for ECN definitions */
#include <netinet/ip.h> /* for ECN definitions */
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/sctp.h>
+#include <netinet/udp.h>
+#include <netinet/dccp.h>
+#include <net/if_gre.h>
+
#include <security/mac/mac_framework.h>
/*
@@ -331,6 +338,29 @@
)
break;
+ /*
+ * If first fragment (frag offset is 0) doesn't have a valid upper
+ * layer header drop it per RFC7112.
+ */
+ fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
+ if (fragoff == 0 &&
+ (ip6_upperlayerhdr(ip6f->ip6f_nxt) ||
+ V_ip6_allow_unknown_upperlayerhdr)) {
+ if(!ip6_validhdrchain(&m, offset, ip6f->ip6f_nxt, frgpartlen)) {
+ /* remove any fragments that have arrived */
+ if (q6 != head) {
+ IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag);
+ frag6_freef(q6, hash);
+ }
+ icmp6_error(m, ICMP6_PARAM_PROB,
+ ICMP6_PARAMPROB_FRAGHDRCHAIN, offset);
+ in6_ifstat_inc(dstifp, ifs6_reass_fail);
+ IP6STAT_INC(ip6s_fragdropped);
+ IP6Q_UNLOCK(hash);
+ return (IPPROTO_DONE);
+ }
+ }
+
if (q6 == head) {
/*
* the first fragment to arrive, create a reassembly queue.
@@ -385,7 +415,6 @@
* If it's the 1st fragment, record the length of the
* unfragmentable part and the next header of the fragment header.
*/
- fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
if (fragoff == 0) {
q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
sizeof(struct ip6_frag);
@@ -965,3 +994,94 @@
m->m_flags |= M_FRAGMENTED;
return (0);
}
+
+/*
+ * Ensure that proto is an upper layer header and there is enough space for the
+ * upper layer header.
+ */
+int
+ip6_validhdrchain(struct mbuf **mp, int offset, uint8_t proto, uint16_t length)
+{
+ struct mbuf *m;
+ struct ipv6_hdr *ip6;
+ struct ip *ip4;
+ struct tcphdr *tp;
+ struct dccphdr *dccp;
+ uint16_t hdrlen;
+
+ m = *mp;
+ ip6 = mtod(m, struct ipv6_hdr *);
+
+ switch (proto) {
+ case IPPROTO_ICMPV6:
+ if (length < sizeof(struct icmp6_hdr))
+ return 0;
+ return 1;
+ case IPPROTO_IPV6:
+ if (length < sizeof(struct ip6_hdr))
+ return 0;
+ return 1;
+ case IPPROTO_ESP:
+ if (length < sizeof(uint32_t))
+ return 0;
+ return 1;
+ case IPPROTO_SCTP:
+ if (length < sizeof(struct sctphdr))
+ return 0;
+ return 1;
+ case IPPROTO_TCP:
+ if (length < sizeof(struct tcphdr))
+ return 0;
+ /* Get the tcp header in the first mbuf. */
+ if (m->m_len < offset + sizeof(struct tcphdr))
+ if ((m = m_pullup(m, offset + sizeof(struct tcphdr))) == NULL) {
+ *mp = NULL;
+ return 0;
+ }
+ tp = (struct tcphdr *)((caddr_t)ip6 + offset);
+ hdrlen = tp->th_off << 2;
+ if (length < hdrlen)
+ return 0;
+ return 1;
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ if (length < sizeof(struct udphdr))
+ return 0;
+ return 1;
+ case IPPROTO_DCCP:
+ if (length < DCCP_SHORTHDR)
+ return 0;
+ /* Get the dccp short header in the first mbuf. */
+ if (m->m_len < offset + DCCP_SHORTHDR)
+ if ((m = m_pullup(m, offset + DCCP_SHORTHDR)) == NULL) {
+ *mp = NULL;
+ return 0;
+ }
+ dccp = (struct dccphdr *)((caddr_t)ip6 + offset);
+ hdrlen = dccp->d_x;
+ if (hdrlen & DCCP_EXTHDR && length < DCCP_LONGHDR)
+ return 0;
+ return 1;
+ case IPPROTO_IP:
+ if (length < sizeof(struct ip))
+ return 0;
+ /* Get the ip header in the first mbuf. */
+ if (m->m_len < offset + sizeof(struct ip))
+ if ((m = m_pullup(m, offset + sizeof(struct ip))) == NULL) {
+ *mp = NULL;
+ return 0;
+ }
+ ip4 = (struct ip *)((caddr_t)ip6 + offset);
+ hdrlen = ip4->ip_hl << 2;
+ if (length < hdrlen)
+ return 0;
+ return 1;
+ case IPPROTO_GRE:
+ if (length < sizeof(struct grehdr))
+ return 0;
+ return 1;
+ default:
+ /* not a known upper layer protocol */
+ return 0;
+ }
+}
Index: sys/netinet6/icmp6.c
===================================================================
--- sys/netinet6/icmp6.c
+++ sys/netinet6/icmp6.c
@@ -210,6 +210,9 @@
case ICMP6_PARAMPROB_OPTION:
ICMP6STAT_INC(icp6s_oparamprob_option);
return;
+ case ICMP6_PARAMPROB_FRAGHDRCHAIN:
+ ICMP6STAT_INC(icp6s_oparamprob_fraghdrchain);
+ return;
}
break;
case ND_REDIRECT:
@@ -535,6 +538,7 @@
break;
case ICMP6_PARAMPROB_HEADER:
case ICMP6_PARAMPROB_OPTION:
+ case ICMP6_PARAMPROB_FRAGHDRCHAIN:
code = PRC_PARAMPROB;
break;
default:
Index: sys/netinet6/in6.h
===================================================================
--- sys/netinet6/in6.h
+++ sys/netinet6/in6.h
@@ -644,7 +644,8 @@
* queue */
#define IPV6CTL_MAXFRAGSPERPACKET 53 /* Max fragments per packet */
#define IPV6CTL_MAXFRAGBUCKETSIZE 54 /* Max reassembly queues per bucket */
-#define IPV6CTL_MAXID 55
+#define IPV6CTL_UNKNOWN_UPPERLAYERHDR 55 /* Allow unknown upper layer headers */
+#define IPV6CTL_MAXID 56
#endif /* __BSD_VISIBLE */
/*
Index: sys/netinet6/in6_proto.c
===================================================================
--- sys/netinet6/in6_proto.c
+++ sys/netinet6/in6_proto.c
@@ -399,6 +399,7 @@
* walk list every 5 sec. */
VNET_DEFINE(int, ip6_mcast_pmtu) = 0; /* enable pMTU discovery for multicast? */
VNET_DEFINE(int, ip6_v6only) = 1;
+VNET_DEFINE(int, ip6_allow_unknown_upperlayerhdr) = 1;
VNET_DEFINE(time_t, ip6_log_time) = (time_t)0L;
#ifdef IPSTEALTH
@@ -562,6 +563,9 @@
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_V6ONLY, v6only,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_v6only), 0,
"Restrict AF_INET6 sockets to IPv6 addresses only");
+SYSCTL_INT(_net_inet6_ip6, IPV6CTL_UNKNOWN_UPPERLAYERHDR, allow_unknown_upperlayerhdr,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_allow_unknown_upperlayerhdr), 0,
+ "Allow unknown upper layer protocols to skip header chain validation");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, auto_linklocal,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_auto_linklocal), 0,
"Default value of per-interface flag for automatically adding an IPv6 "
Index: sys/netinet6/ip6_input.c
===================================================================
--- sys/netinet6/ip6_input.c
+++ sys/netinet6/ip6_input.c
@@ -544,6 +544,9 @@
struct in6_ifaddr *ia;
struct ifnet *rcvif;
u_int32_t plen;
+#ifdef INVARIANTS
+ u_int16_t length;
+#endif
u_int32_t rtalert = ~0;
int off = sizeof(struct ip6_hdr), nest;
int nxt, ours = 0;
@@ -957,6 +960,12 @@
return;
}
#endif /* IPSEC */
+#ifdef INVARIANTS
+ length = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - off;
+ if (ip6_upperlayerhdr(nxt))
+ if (!ip6_validhdrchain(&m, off, nxt, length))
+ goto bad;
+#endif
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
}
@@ -1847,6 +1856,29 @@
}
}
+/*
+ * Check if proto is a supported upper layer protocol.
+ */
+int
+ip6_upperlayerhdr(uint8_t proto)
+{
+ switch (proto) {
+ case IPPROTO_ICMPV6:
+ case IPPROTO_IPV6:
+ case IPPROTO_ESP:
+ case IPPROTO_SCTP:
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ case IPPROTO_DCCP:
+ case IPPROTO_IP:
+ case IPPROTO_GRE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/*
* System control for IP6
*/
Index: sys/netinet6/ip6_var.h
===================================================================
--- sys/netinet6/ip6_var.h
+++ sys/netinet6/ip6_var.h
@@ -290,6 +290,7 @@
* walk list every 5 sec. */
VNET_DECLARE(int, ip6_mcast_pmtu); /* enable pMTU discovery for multicast? */
VNET_DECLARE(int, ip6_v6only);
+VNET_DECLARE(int, ip6_allow_unknown_upperlayerhdr);
#define V_ip6_defhlim VNET(ip6_defhlim)
#define V_ip6_defmcasthlim VNET(ip6_defmcasthlim)
#define V_ip6_forwarding VNET(ip6_forwarding)
@@ -297,6 +298,7 @@
#define V_ip6_rr_prune VNET(ip6_rr_prune)
#define V_ip6_mcast_pmtu VNET(ip6_mcast_pmtu)
#define V_ip6_v6only VNET(ip6_v6only)
+#define V_ip6_allow_unknown_upperlayerhdr VNET(ip6_allow_unknown_upperlayerhdr)
VNET_DECLARE(struct socket *, ip6_mrouter); /* multicast routing daemon */
VNET_DECLARE(int, ip6_sendredirects); /* send IP redirects when forwarding? */
@@ -410,8 +412,10 @@
struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int);
int ip6_optlen(struct inpcb *);
int ip6_deletefraghdr(struct mbuf *, int, int);
+int ip6_validhdrchain(struct mbuf **, int, uint8_t, uint16_t);
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int,
uint32_t);
+int ip6_upperlayerhdr(uint8_t);
int route6_input(struct mbuf **, int *, int);
Index: usr.bin/netstat/inet6.c
===================================================================
--- usr.bin/netstat/inet6.c
+++ usr.bin/netstat/inet6.c
@@ -1035,6 +1035,8 @@
"{N:/unrecognized next header}\n");
p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} "
"{N:/unrecognized option}\n");
+ p_5(icp6s_oparamprob_fraghdrchain, "\t\t{:bad-header-chain/%ju} "
+ "{N:/incomplete upper layer first fragment}\n");
p_5(icp6s_oredirect, "\t\t{:redirects/%ju} "
"{N:/redirect}\n");
p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 16, 1:18 AM (18 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14650452
Default Alt Text
D16851.id57763.diff (12 KB)
Attached To
Mode
D16851: Add support for header chain validation on IPv6 Fragments (RFC7112)
Attached
Detach File
Event Timeline
Log In to Comment