From 8e02b4e00cc590bdd018b9c7cf08f5f5fd4f0e47 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Sun, 19 Aug 2018 14:56:10 +0000 Subject: [PATCH] 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 --- sys/netinet/tcp_subr.c | 67 +++++++++++++++++++++++--------------- sys/netinet/tcp_syncache.c | 8 ++--- sys/netinet/tcp_usrreq.c | 8 +++-- sys/netinet/tcp_var.h | 4 ++- 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 5a1731321217..5e8aa9bb104d 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -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,6 +2607,40 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) } #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 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) * 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) { diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index d6174221cc7d..6b477d3af9c8 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -1497,6 +1497,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, 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 syncache *sc) 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 syncache_head *sch, 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) diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 12011928a90b..75ffe968858a 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1439,7 +1439,9 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) 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, struct thread *td) 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; diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index c0f870ad6e10..5f8c0ade6700 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -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);