Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102559633
D16851.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D16851.diff
View Options
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -646,7 +646,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 */
/*
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -216,6 +216,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
@@ -365,6 +366,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 "
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -131,6 +131,13 @@
#include <netinet6/ip6protosw.h>
+#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>
+
ipproto_input_t *ip6_protox[IPPROTO_MAX] = {
[0 ... IPPROTO_MAX - 1] = rip6_input };
ipproto_ctlinput_t *ip6_ctlprotox[IPPROTO_MAX] = {
@@ -526,6 +533,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;
@@ -919,6 +929,12 @@
return;
}
#endif /* IPSEC */
+#ifdef INVARIANTS
+ length = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - off;
+ if (ip6_upperlayerhdr(nxt))
+ if (!ip6_valid_hdrchain(&m, off, nxt, length))
+ goto bad;
+#endif
nxt = ip6_protox[nxt](&m, &off, nxt);
}
@@ -1715,6 +1731,172 @@
}
}
+/*
+ * 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;
+ }
+}
+
+/*
+ * Search the header chain for the first upper layer protocol and return the
+ * offset of that header. m will be kept untainted.
+ */
+int
+ip6_first_upperlayerhdr(const struct mbuf *m, int off, int proto, int *nxtp)
+{
+ int newoff;
+ int nxt;
+ int nest = 0;
+
+ if (!nxtp) {
+ nxt = -1;
+ nxtp = &nxt;
+ }
+ while (nest++ < V_ip6_hdrnestlimit) {
+ if (ip6_upperlayerhdr(proto) == 1)
+ return off;
+ newoff = ip6_nexthdr(m, off, proto, nxtp);
+ if (newoff < 0)
+ return -1;
+ else if (newoff < off)
+ return -1; /* invalid */
+ else if (newoff == off)
+ return -1;
+
+ off = newoff;
+ proto = *nxtp;
+ }
+ return -1;
+}
+
+/*
+ * Ensure that proto is an upper layer header and there is enough space for the
+ * upper layer header.
+ */
+int
+ip6_valid_upperlayerhdr(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;
+ }
+}
+
+uint8_t
+ip6_valid_hdrchain(struct mbuf **mp, int offset, uint8_t proto, uint16_t length)
+{
+ int nxtp = proto;
+ struct mbuf *m;
+ m = *mp;
+
+ offset = ip6_first_upperlayerhdr(m, offset, proto, &nxtp);
+
+ if (offset == -1) {
+ if (V_ip6_allow_unknown_upperlayerhdr)
+ return 1;
+
+ else
+ return 0;
+ }
+
+ return ip6_valid_upperlayerhdr(mp, offset, proto, length - offset);
+}
+
/*
* System control for IP6
*/
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -277,6 +277,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)
@@ -284,6 +285,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? */
@@ -385,6 +387,10 @@
int ip6_deletefraghdr(struct mbuf *, int, int);
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int,
uint32_t);
+int ip6_upperlayerhdr(uint8_t);
+int ip6_first_upperlayerhdr(const struct mbuf *, int , int , int *);
+int ip6_valid_upperlayerhdr(struct mbuf **, int , uint8_t , uint16_t);
+uint8_t ip6_valid_hdrchain(struct mbuf **, int , uint8_t , uint16_t);
int route6_input(struct mbuf **, int *, int);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 15, 1:48 AM (4 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14636630
Default Alt Text
D16851.diff (7 KB)
Attached To
Mode
D16851: Add support for header chain validation on IPv6 Fragments (RFC7112)
Attached
Detach File
Event Timeline
Log In to Comment