svn commit: r328876 - head/sys/netinet6

Andrey V. Elsukov ae at FreeBSD.org
Mon Feb 5 09:22:08 UTC 2018


Author: ae
Date: Mon Feb  5 09:22:07 2018
New Revision: 328876
URL: https://svnweb.freebsd.org/changeset/base/328876

Log:
  Modify ip6_get_prevhdr() to be able use it safely.
  
  Instead of returning pointer to the previous header, return its offset.
  In frag6_input() use m_copyback() and determined offset to store next
  header instead of accessing to it by pointer and assuming that the memory
  is contiguous.
  
  In rip6_input() use offset returned by ip6_get_prevhdr() instead of
  calculating it from pointers arithmetic, because IP header can belong
  to another mbuf in the chain.
  
  Reported by:	Maxime Villard <max at m00nbsd dot net>
  Reviewed by:	kp
  MFC after:	1 week
  Differential Revision:	https://reviews.freebsd.org/D14158

Modified:
  head/sys/netinet6/frag6.c
  head/sys/netinet6/ip6_input.c
  head/sys/netinet6/ip6_var.h
  head/sys/netinet6/raw_ip6.c

Modified: head/sys/netinet6/frag6.c
==============================================================================
--- head/sys/netinet6/frag6.c	Mon Feb  5 08:50:34 2018	(r328875)
+++ head/sys/netinet6/frag6.c	Mon Feb  5 09:22:07 2018	(r328876)
@@ -578,10 +578,8 @@ insert:
 	/*
 	 * Store NXT to the original.
 	 */
-	{
-		char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
-		*prvnxtp = nxt;
-	}
+	m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t),
+	    (caddr_t)&nxt);
 
 	frag6_remque(q6);
 	V_frag6_nfrags -= q6->ip6q_nfrag;

Modified: head/sys/netinet6/ip6_input.c
==============================================================================
--- head/sys/netinet6/ip6_input.c	Mon Feb  5 08:50:34 2018	(r328875)
+++ head/sys/netinet6/ip6_input.c	Mon Feb  5 09:22:07 2018	(r328876)
@@ -1711,49 +1711,39 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt)
 /*
  * Get pointer to the previous header followed by the header
  * currently processed.
- * XXX: This function supposes that
- *	M includes all headers,
- *	the next header field and the header length field of each header
- *	are valid, and
- *	the sum of each header length equals to OFF.
- * Because of these assumptions, this function must be called very
- * carefully. Moreover, it will not be used in the near future when
- * we develop `neater' mechanism to process extension headers.
  */
-char *
+int
 ip6_get_prevhdr(const struct mbuf *m, int off)
 {
-	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+	struct ip6_ext ip6e;
+	struct ip6_hdr *ip6;
+	int len, nlen, nxt;
 
 	if (off == sizeof(struct ip6_hdr))
-		return (&ip6->ip6_nxt);
-	else {
-		int len, nxt;
-		struct ip6_ext *ip6e = NULL;
+		return (offsetof(struct ip6_hdr, ip6_nxt));
+	if (off < sizeof(struct ip6_hdr))
+		panic("%s: off < sizeof(struct ip6_hdr)", __func__);
 
-		nxt = ip6->ip6_nxt;
-		len = sizeof(struct ip6_hdr);
-		while (len < off) {
-			ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
-
-			switch (nxt) {
-			case IPPROTO_FRAGMENT:
-				len += sizeof(struct ip6_frag);
-				break;
-			case IPPROTO_AH:
-				len += (ip6e->ip6e_len + 2) << 2;
-				break;
-			default:
-				len += (ip6e->ip6e_len + 1) << 3;
-				break;
-			}
-			nxt = ip6e->ip6e_nxt;
+	ip6 = mtod(m, struct ip6_hdr *);
+	nxt = ip6->ip6_nxt;
+	len = sizeof(struct ip6_hdr);
+	nlen = 0;
+	while (len < off) {
+		m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e);
+		switch (nxt) {
+		case IPPROTO_FRAGMENT:
+			nlen = sizeof(struct ip6_frag);
+			break;
+		case IPPROTO_AH:
+			nlen = (ip6e.ip6e_len + 2) << 2;
+			break;
+		default:
+			nlen = (ip6e.ip6e_len + 1) << 3;
 		}
-		if (ip6e)
-			return (&ip6e->ip6e_nxt);
-		else
-			return NULL;
+		len += nlen;
+		nxt = ip6e.ip6e_nxt;
 	}
+	return (len - nlen);
 }
 
 /*

Modified: head/sys/netinet6/ip6_var.h
==============================================================================
--- head/sys/netinet6/ip6_var.h	Mon Feb  5 08:50:34 2018	(r328875)
+++ head/sys/netinet6/ip6_var.h	Mon Feb  5 09:22:07 2018	(r328876)
@@ -364,7 +364,7 @@ void	ip6_direct_input(struct mbuf *);
 void	ip6_freepcbopts(struct ip6_pktopts *);
 
 int	ip6_unknown_opt(u_int8_t *, struct mbuf *, int);
-char *	ip6_get_prevhdr(const struct mbuf *, int);
+int	ip6_get_prevhdr(const struct mbuf *, int);
 int	ip6_nexthdr(const struct mbuf *, int, int, int *);
 int	ip6_lasthdr(const struct mbuf *, int, int, int *);
 

Modified: head/sys/netinet6/raw_ip6.c
==============================================================================
--- head/sys/netinet6/raw_ip6.c	Mon Feb  5 08:50:34 2018	(r328875)
+++ head/sys/netinet6/raw_ip6.c	Mon Feb  5 09:22:07 2018	(r328876)
@@ -325,12 +325,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
 			RIP6STAT_INC(rip6s_nosockmcast);
 		if (proto == IPPROTO_NONE)
 			m_freem(m);
-		else {
-			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
+		else
 			icmp6_error(m, ICMP6_PARAM_PROB,
 			    ICMP6_PARAMPROB_NEXTHEADER,
-			    prvnxtp - mtod(m, char *));
-		}
+			    ip6_get_prevhdr(m, *offp));
 		IP6STAT_DEC(ip6s_delivered);
 	}
 	return (IPPROTO_DONE);


More information about the svn-src-all mailing list