Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 May 2019 16:32:19 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r348435 - stable/11/sys/netinet
Message-ID:  <201905301632.x4UGWJSJ066904@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Thu May 30 16:32:18 2019
New Revision: 348435
URL: https://svnweb.freebsd.org/changeset/base/348435

Log:
  MFC r338053:
  
  Don't expose the uptime via the TCP timestamps.
  
  The TCP client side or the TCP server side when not using SYN-cookies
  used the uptime as the TCP timestamp value. This patch uses in all
  cases an offset, which is the result of a keyed hash function taking
  the source and destination addresses and port numbers into account.
  The keyed hash function is the same a used for the initial TSN.
  
  The use of
  VNET_DEFINE_STATIC(u_char, ts_offset_secret[32]);
  had to be replaced by
  VNET_DEFINE(u_char, ts_offset_secret[32]);
  
  MFC r348290:
  
  When an ACK segment as the third message of the three way handshake is
  received and support for time stamps was negotiated in the SYN/SYNACK
  exchange, perform the PAWS check and only expand the syn cache entry if
  the check is passed.
  Without this check, endpoints may get stuck on the incomplete queue.
  
  Reviewed by:		jtl@, rrs@
  Approved by:		re (kib@))
  Sponsored by:		Netflix, Inc.
  Differential Revision:	https://reviews.freebsd.org/D16636
  Differential Revision:	https://reviews.freebsd.org/D20374

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

Modified: stable/11/sys/netinet/tcp_subr.c
==============================================================================
--- stable/11/sys/netinet/tcp_subr.c	Thu May 30 16:11:20 2019	(r348434)
+++ stable/11/sys/netinet/tcp_subr.c	Thu May 30 16:32:18 2019	(r348435)
@@ -226,6 +226,12 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone);
 
 VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
 
+VNET_DEFINE(u_char, ts_offset_secret[32]);
+#define	V_ts_offset_secret	VNET(ts_offset_secret)
+
+static int	tcp_default_fb_init(struct tcpcb *tp);
+static void	tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged);
+static int	tcp_default_handoff_ok(struct tcpcb *tp);
 static struct inpcb *tcp_notify(struct inpcb *, int);
 static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int);
 static void tcp_mtudisc(struct inpcb *, int);
@@ -683,6 +689,7 @@ tcp_init(void)
 	/* Setup the tcp function block list */
 	init_tcp_functions();
 	register_tcp_functions(&tcp_def_funcblk, M_WAITOK);
+	read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret));
 
 	if (tcp_soreceive_stream) {
 #ifdef INET
@@ -2185,7 +2192,41 @@ out:
 }
 #endif /* INET6 */
 
+static uint32_t
+tcp_keyed_hash(struct in_conninfo *inc, u_char *key)
+{
+	MD5_CTX ctx;
+	uint32_t hash[4];
 
+	MD5Init(&ctx);
+	MD5Update(&ctx, &inc->inc_fport, sizeof(uint16_t));
+	MD5Update(&ctx, &inc->inc_lport, sizeof(uint16_t));
+	switch (inc->inc_flags & INC_ISIPV6) {
+#ifdef INET
+	case 0:
+		MD5Update(&ctx, &inc->inc_faddr, sizeof(struct in_addr));
+		MD5Update(&ctx, &inc->inc_laddr, sizeof(struct in_addr));
+		break;
+#endif
+#ifdef INET6
+	case INC_ISIPV6:
+		MD5Update(&ctx, &inc->inc6_faddr, sizeof(struct in6_addr));
+		MD5Update(&ctx, &inc->inc6_laddr, sizeof(struct in6_addr));
+		break;
+#endif
+	}
+	MD5Update(&ctx, key, 32);
+	MD5Final((unsigned char *)hash, &ctx);
+
+	return (hash[0]);
+}
+
+uint32_t
+tcp_new_ts_offset(struct in_conninfo *inc)
+{
+	return (tcp_keyed_hash(inc, V_ts_offset_secret));
+}
+
 /*
  * Following is where TCP initial sequence number generation occurs.
  *
@@ -2226,7 +2267,7 @@ out:
  * as reseeding should not be necessary.
  *
  * Locking of the global variables isn_secret, isn_last_reseed, isn_offset,
- * isn_offset_old, and isn_ctx is performed using the TCP pcbinfo lock.  In
+ * isn_offset_old, and isn_ctx is performed using the ISN lock.  In
  * general, this means holding an exclusive (write) lock.
  */
 
@@ -2247,15 +2288,11 @@ static VNET_DEFINE(u_int32_t, isn_offset_old);
 #define	V_isn_offset_old		VNET(isn_offset_old)
 
 tcp_seq
-tcp_new_isn(struct tcpcb *tp)
+tcp_new_isn(struct in_conninfo *inc)
 {
-	MD5_CTX isn_ctx;
-	u_int32_t md5_buffer[4];
 	tcp_seq new_isn;
 	u_int32_t projected_offset;
 
-	INP_WLOCK_ASSERT(tp->t_inpcb);
-
 	ISN_LOCK();
 	/* Seed if this is the first use, reseed if requested. */
 	if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) &&
@@ -2266,26 +2303,7 @@ tcp_new_isn(struct tcpcb *tp)
 	}
 
 	/* Compute the md5 hash and return the ISN. */
-	MD5Init(&isn_ctx);
-	MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short));
-	MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short));
-#ifdef INET6
-	if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) {
-		MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr,
-			  sizeof(struct in6_addr));
-		MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr,
-			  sizeof(struct in6_addr));
-	} else
-#endif
-	{
-		MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr,
-			  sizeof(struct in_addr));
-		MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr,
-			  sizeof(struct in_addr));
-	}
-	MD5Update(&isn_ctx, (u_char *) &V_isn_secret, sizeof(V_isn_secret));
-	MD5Final((u_char *) &md5_buffer, &isn_ctx);
-	new_isn = (tcp_seq) md5_buffer[0];
+	new_isn = (tcp_seq)tcp_keyed_hash(inc, V_isn_secret);
 	V_isn_offset += ISN_STATIC_INCREMENT +
 		(arc4random() & ISN_RANDOM_INCREMENT);
 	if (ticks != V_isn_last) {

Modified: stable/11/sys/netinet/tcp_syncache.c
==============================================================================
--- stable/11/sys/netinet/tcp_syncache.c	Thu May 30 16:11:20 2019	(r348434)
+++ stable/11/sys/netinet/tcp_syncache.c	Thu May 30 16:32:18 2019	(r348435)
@@ -1088,7 +1088,29 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt
 			}
 		}
 #endif /* TCP_SIGNATURE */
+
 		/*
+		 * RFC 7323 PAWS: If we have a timestamp on this segment and
+		 * it's less than ts_recent, drop it.
+		 * XXXMT: RFC 7323 also requires to send an ACK.
+		 *        In tcp_input.c this is only done for TCP segments
+		 *        with user data, so be consistent here and just drop
+		 *        the segment.
+		 */
+		if (sc->sc_flags & SCF_TIMESTAMP && to->to_flags & TOF_TS &&
+		    TSTMP_LT(to->to_tsval, sc->sc_tsreflect)) {
+			SCH_UNLOCK(sch);
+			if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
+				log(LOG_DEBUG,
+				    "%s; %s: SEG.TSval %u < TS.Recent %u, "
+				    "segment dropped\n", s, __func__,
+				    to->to_tsval, sc->sc_tsreflect);
+				free(s, M_TCPLOG);
+			}
+			return (-1);  /* Do not send RST */
+		}
+
+		/*
 		 * Pull out the entry to unlock the bucket row.
 		 * 
 		 * NOTE: We must decrease TCPS_SYN_RECEIVED count here, not
@@ -1494,6 +1516,7 @@ skip_alloc:
 		if (to->to_flags & TOF_TS) {
 			sc->sc_tsreflect = to->to_tsval;
 			sc->sc_flags |= SCF_TIMESTAMP;
+			sc->sc_tsoff = tcp_new_ts_offset(inc);
 		}
 		if (to->to_flags & TOF_SCALE) {
 			int wscale = 0;
@@ -2029,11 +2052,6 @@ syncookie_generate(struct syncache_head *sch, struct s
 	iss = hash & ~0xff;
 	iss |= cookie.cookie ^ (hash >> 24);
 
-	/* Randomize the timestamp. */
-	if (sc->sc_flags & SCF_TIMESTAMP) {
-		sc->sc_tsoff = arc4random() - tcp_ts_getticks();
-	}
-
 	TCPSTAT_INC(tcps_sc_sendcookie);
 	return (iss);
 }
@@ -2120,7 +2138,7 @@ syncookie_lookup(struct in_conninfo *inc, struct synca
 	if (to->to_flags & TOF_TS) {
 		sc->sc_flags |= SCF_TIMESTAMP;
 		sc->sc_tsreflect = to->to_tsval;
-		sc->sc_tsoff = to->to_tsecr - tcp_ts_getticks();
+		sc->sc_tsoff = tcp_new_ts_offset(inc);
 	}
 
 	if (to->to_flags & TOF_SIGNATURE)

Modified: stable/11/sys/netinet/tcp_usrreq.c
==============================================================================
--- stable/11/sys/netinet/tcp_usrreq.c	Thu May 30 16:11:20 2019	(r348434)
+++ stable/11/sys/netinet/tcp_usrreq.c	Thu May 30 16:32:18 2019	(r348435)
@@ -1308,7 +1308,9 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, st
 	soisconnecting(so);
 	TCPSTAT_INC(tcps_connattempt);
 	tcp_state_change(tp, TCPS_SYN_SENT);
-	tp->iss = tcp_new_isn(tp);
+	tp->iss = tcp_new_isn(&inp->inp_inc);
+	if (tp->t_flags & TF_REQ_TSTMP)
+		tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc);
 	tcp_sendseqinit(tp);
 
 	return 0;
@@ -1347,7 +1349,9 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, s
 	soisconnecting(inp->inp_socket);
 	TCPSTAT_INC(tcps_connattempt);
 	tcp_state_change(tp, TCPS_SYN_SENT);
-	tp->iss = tcp_new_isn(tp);
+	tp->iss = tcp_new_isn(&inp->inp_inc);
+	if (tp->t_flags & TF_REQ_TSTMP)
+		tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc);
 	tcp_sendseqinit(tp);
 
 	return 0;

Modified: stable/11/sys/netinet/tcp_var.h
==============================================================================
--- stable/11/sys/netinet/tcp_var.h	Thu May 30 16:11:20 2019	(r348434)
+++ stable/11/sys/netinet/tcp_var.h	Thu May 30 16:32:18 2019	(r348435)
@@ -826,7 +826,9 @@ void	 tcp_hc_updatemtu(struct in_conninfo *, u_long);
 void	 tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
 
 extern	struct pr_usrreqs tcp_usrreqs;
-tcp_seq tcp_new_isn(struct tcpcb *);
+
+uint32_t tcp_new_ts_offset(struct in_conninfo *);
+tcp_seq	 tcp_new_isn(struct in_conninfo *);
 
 int	 tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
 void	 tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905301632.x4UGWJSJ066904>