Author: tuexen
Date: Sun Aug 19 14:56:10 2018
New Revision: 338053
URL: https://svnweb.freebsd.org/changeset/base/338053

Log:
  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.
  
  Reviewed by:          rrs@
  MFC after:            1 month
  Sponsored by:         Netflix, Inc.
  Differential Revision:        https://reviews.freebsd.org/D16636

Modified:
  head/sys/netinet/tcp_subr.c
  head/sys/netinet/tcp_syncache.c
  head/sys/netinet/tcp_usrreq.c
  head/sys/netinet/tcp_var.h

Modified: head/sys/netinet/tcp_subr.c
==============================================================================
--- head/sys/netinet/tcp_subr.c Sun Aug 19 14:48:32 2018        (r338052)
+++ head/sys/netinet/tcp_subr.c Sun Aug 19 14:56:10 2018        (r338053)
@@ -233,6 +233,9 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone);
 VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
 #endif
 
+VNET_DEFINE_STATIC(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);
@@ -1092,6 +1095,7 @@ tcp_init(void)
        /* Initialize the TCP logging data. */
        tcp_log_init();
 #endif
+       read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret));
 
        if (tcp_soreceive_stream) {
 #ifdef INET
@@ -2603,7 +2607,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.
  *
@@ -2644,7 +2682,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.
  */
 
@@ -2665,15 +2703,11 @@ VNET_DEFINE_STATIC(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) &&
@@ -2684,26 +2718,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: head/sys/netinet/tcp_syncache.c
==============================================================================
--- head/sys/netinet/tcp_syncache.c     Sun Aug 19 14:48:32 2018        
(r338052)
+++ head/sys/netinet/tcp_syncache.c     Sun Aug 19 14:56:10 2018        
(r338053)
@@ -1497,6 +1497,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;
@@ -2035,11 +2036,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);
 }
@@ -2126,7 +2122,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: head/sys/netinet/tcp_usrreq.c
==============================================================================
--- head/sys/netinet/tcp_usrreq.c       Sun Aug 19 14:48:32 2018        
(r338052)
+++ head/sys/netinet/tcp_usrreq.c       Sun Aug 19 14:56:10 2018        
(r338053)
@@ -1439,7 +1439,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;
@@ -1478,7 +1480,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: head/sys/netinet/tcp_var.h
==============================================================================
--- head/sys/netinet/tcp_var.h  Sun Aug 19 14:48:32 2018        (r338052)
+++ head/sys/netinet/tcp_var.h  Sun Aug 19 14:56:10 2018        (r338053)
@@ -923,7 +923,9 @@ void         tcp_hc_updatemtu(struct in_conninfo *, 
uint32_t)
 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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to