svn commit: r319654 - stable/11/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Wed Jun 7 12:50:56 UTC 2017


Author: tuexen
Date: Wed Jun  7 12:50:54 2017
New Revision: 319654
URL: https://svnweb.freebsd.org/changeset/base/319654

Log:
  MFC r319556:
  Fix the ICMP6 handling for TCP.
  
  The ICMP6 packets might not be contained in a single mbuf. So don't
  assume this. Keep the IPv4 and IPv6 code in sync and make explicit
  that the syncache code only need the TCP sequence number, not the
  complete TCP header.
  
  Approved by:	re (marius)

Modified:
  stable/11/sys/netinet/tcp_subr.c
  stable/11/sys/netinet/tcp_syncache.c
  stable/11/sys/netinet/tcp_syncache.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/netinet/tcp_subr.c
==============================================================================
--- stable/11/sys/netinet/tcp_subr.c	Wed Jun  7 11:43:36 2017	(r319653)
+++ stable/11/sys/netinet/tcp_subr.c	Wed Jun  7 12:50:54 2017	(r319654)
@@ -1966,16 +1966,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 	if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
 		/* signal EHOSTDOWN, as it flushes the cached route */
 		inp = (*notify)(inp, EHOSTDOWN);
-		if (inp != NULL)
-			INP_WUNLOCK(inp);
-	} else if (inp != NULL)  {
+		goto out;
+	}
+	icmp_tcp_seq = th->th_seq;
+	if (inp != NULL)  {
 		if (!(inp->inp_flags & INP_TIMEWAIT) &&
 		    !(inp->inp_flags & INP_DROPPED) &&
 		    !(inp->inp_socket == NULL)) {
-			icmp_tcp_seq = ntohl(th->th_seq);
 			tp = intotcpcb(inp);
-			if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
-			    SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+			if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+			    SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
 				if (cmd == PRC_MSGSIZE) {
 					/*
 					 * MTU discovery:
@@ -1983,7 +1983,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 					 * in the route to the suggested new
 					 * value (if given) and then notify.
 					 */
-				    	mtu = ntohs(icp->icmp_nextmtu);
+					mtu = ntohs(icp->icmp_nextmtu);
 					/*
 					 * If no alternative MTU was
 					 * proposed, try the next smaller
@@ -2014,16 +2014,17 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 					    inetctlerrmap[cmd]);
 			}
 		}
-		if (inp != NULL)
-			INP_WUNLOCK(inp);
 	} else {
 		bzero(&inc, sizeof(inc));
 		inc.inc_fport = th->th_dport;
 		inc.inc_lport = th->th_sport;
 		inc.inc_faddr = faddr;
 		inc.inc_laddr = ip->ip_src;
-		syncache_unreach(&inc, th);
+		syncache_unreach(&inc, icmp_tcp_seq);
 	}
+out:
+	if (inp != NULL)
+		INP_WUNLOCK(inp);
 	INP_INFO_RUNLOCK(&V_tcbinfo);
 }
 #endif /* INET */
@@ -2033,7 +2034,6 @@ void
 tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
 {
 	struct in6_addr *dst;
-	struct tcphdr *th;
 	struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify;
 	struct ip6_hdr *ip6;
 	struct mbuf *m;
@@ -2043,11 +2043,14 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
 	struct ip6ctlparam *ip6cp = NULL;
 	const struct sockaddr_in6 *sa6_src = NULL;
 	struct in_conninfo inc;
+	struct tcp_ports {
+		uint16_t th_sport;
+		uint16_t th_dport;
+	} t_ports;
 	tcp_seq icmp_tcp_seq;
 	unsigned int mtu;
 	unsigned int off;
 
-
 	if (sa->sa_family != AF_INET6 ||
 	    sa->sa_len != sizeof(struct sockaddr_in6))
 		return;
@@ -2096,27 +2099,31 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
 	/* Check if we can safely get the ports from the tcp hdr */
 	if (m == NULL ||
 	    (m->m_pkthdr.len <
-		(int32_t) (off + offsetof(struct tcphdr, th_seq)))) {
+		(int32_t) (off + sizeof(struct tcp_ports)))) {
 		return;
 	}
-
-	th = (struct tcphdr *) mtodo(ip6cp->ip6c_m, ip6cp->ip6c_off);
+	bzero(&t_ports, sizeof(struct tcp_ports));
+	m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports);
 	INP_INFO_RLOCK(&V_tcbinfo);
-	inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, th->th_dport,
-	    &ip6->ip6_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
+	inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport,
+	    &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL);
 	if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
 		/* signal EHOSTDOWN, as it flushes the cached route */
 		inp = (*notify)(inp, EHOSTDOWN);
-		if (inp != NULL)
-			INP_WUNLOCK(inp);
-	} else if (inp != NULL)  {
+		goto out;
+	}
+	off += sizeof(struct tcp_ports);
+	if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) {
+		goto out;
+	}
+	m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
+	if (inp != NULL)  {
 		if (!(inp->inp_flags & INP_TIMEWAIT) &&
 		    !(inp->inp_flags & INP_DROPPED) &&
 		    !(inp->inp_socket == NULL)) {
-			icmp_tcp_seq = ntohl(th->th_seq);
 			tp = intotcpcb(inp);
-			if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
-			    SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+			if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+			    SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
 				if (cmd == PRC_MSGSIZE) {
 					/*
 					 * MTU discovery:
@@ -2133,22 +2140,20 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
 					 */
 					if (mtu < IPV6_MMTU)
 						mtu = IPV6_MMTU - 8;
-
-
 					bzero(&inc, sizeof(inc));
 					inc.inc_fibnum = M_GETFIB(m);
 					inc.inc_flags |= INC_ISIPV6;
 					inc.inc6_faddr = *dst;
 					if (in6_setscope(&inc.inc6_faddr,
 						m->m_pkthdr.rcvif, NULL))
-						goto unlock_inp;
-
+						goto out;
 					/*
 					 * Only process the offered MTU if it
 					 * is smaller than the current one.
 					 */
 					if (mtu < tp->t_maxseg +
-					    (sizeof (*th) + sizeof (*ip6))) {
+					    sizeof (struct tcphdr) +
+					    sizeof (struct ip6_hdr)) {
 						tcp_hc_updatemtu(&inc, mtu);
 						tcp_mtudisc(inp, mtu);
 						ICMP6STAT_INC(icp6s_pmtuchg);
@@ -2158,19 +2163,19 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
 					    inet6ctlerrmap[cmd]);
 			}
 		}
-unlock_inp:
-		if (inp != NULL)
-			INP_WUNLOCK(inp);
 	} else {
 		bzero(&inc, sizeof(inc));
 		inc.inc_fibnum = M_GETFIB(m);
 		inc.inc_flags |= INC_ISIPV6;
-		inc.inc_fport = th->th_dport;
-		inc.inc_lport = th->th_sport;
+		inc.inc_fport = t_ports.th_dport;
+		inc.inc_lport = t_ports.th_sport;
 		inc.inc6_faddr = *dst;
 		inc.inc6_laddr = ip6->ip6_src;
-		syncache_unreach(&inc, th);
+		syncache_unreach(&inc, icmp_tcp_seq);
 	}
+out:
+	if (inp != NULL)
+		INP_WUNLOCK(inp);
 	INP_INFO_RUNLOCK(&V_tcbinfo);
 }
 #endif /* INET6 */

Modified: stable/11/sys/netinet/tcp_syncache.c
==============================================================================
--- stable/11/sys/netinet/tcp_syncache.c	Wed Jun  7 11:43:36 2017	(r319653)
+++ stable/11/sys/netinet/tcp_syncache.c	Wed Jun  7 12:50:54 2017	(r319654)
@@ -594,7 +594,7 @@ syncache_badack(struct in_conninfo *inc)
 }
 
 void
-syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
+syncache_unreach(struct in_conninfo *inc, tcp_seq th_seq)
 {
 	struct syncache *sc;
 	struct syncache_head *sch;
@@ -605,7 +605,7 @@ syncache_unreach(struct in_conninfo *inc, struct tcphd
 		goto done;
 
 	/* If the sequence number != sc_iss, then it's a bogus ICMP msg */
-	if (ntohl(th->th_seq) != sc->sc_iss)
+	if (ntohl(th_seq) != sc->sc_iss)
 		goto done;
 
 	/*

Modified: stable/11/sys/netinet/tcp_syncache.h
==============================================================================
--- stable/11/sys/netinet/tcp_syncache.h	Wed Jun  7 11:43:36 2017	(r319653)
+++ stable/11/sys/netinet/tcp_syncache.h	Wed Jun  7 12:50:54 2017	(r319654)
@@ -38,7 +38,7 @@ void	 syncache_init(void);
 #ifdef VIMAGE
 void	syncache_destroy(void);
 #endif
-void	 syncache_unreach(struct in_conninfo *, struct tcphdr *);
+void	 syncache_unreach(struct in_conninfo *, tcp_seq);
 int	 syncache_expand(struct in_conninfo *, struct tcpopt *,
 	     struct tcphdr *, struct socket **, struct mbuf *);
 int	 syncache_add(struct in_conninfo *, struct tcpopt *,


More information about the svn-src-all mailing list