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
This commit is contained in:
Michael Tuexen 2018-08-19 14:56:10 +00:00
parent 63d8b6ea21
commit 8e02b4e00c
4 changed files with 52 additions and 35 deletions

View File

@ -233,6 +233,9 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone);
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]); VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
#endif #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 int tcp_default_fb_init(struct tcpcb *tp);
static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged); static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged);
static int tcp_default_handoff_ok(struct tcpcb *tp); static int tcp_default_handoff_ok(struct tcpcb *tp);
@ -1092,6 +1095,7 @@ tcp_init(void)
/* Initialize the TCP logging data. */ /* Initialize the TCP logging data. */
tcp_log_init(); tcp_log_init();
#endif #endif
read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret));
if (tcp_soreceive_stream) { if (tcp_soreceive_stream) {
#ifdef INET #ifdef INET
@ -2603,6 +2607,40 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
} }
#endif /* INET6 */ #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. * 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. * as reseeding should not be necessary.
* *
* Locking of the global variables isn_secret, isn_last_reseed, isn_offset, * 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. * 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) #define V_isn_offset_old VNET(isn_offset_old)
tcp_seq 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; tcp_seq new_isn;
u_int32_t projected_offset; u_int32_t projected_offset;
INP_WLOCK_ASSERT(tp->t_inpcb);
ISN_LOCK(); ISN_LOCK();
/* Seed if this is the first use, reseed if requested. */ /* Seed if this is the first use, reseed if requested. */
if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) && 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. */ /* Compute the md5 hash and return the ISN. */
MD5Init(&isn_ctx); new_isn = (tcp_seq)tcp_keyed_hash(inc, V_isn_secret);
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];
V_isn_offset += ISN_STATIC_INCREMENT + V_isn_offset += ISN_STATIC_INCREMENT +
(arc4random() & ISN_RANDOM_INCREMENT); (arc4random() & ISN_RANDOM_INCREMENT);
if (ticks != V_isn_last) { if (ticks != V_isn_last) {

View File

@ -1497,6 +1497,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
if (to->to_flags & TOF_TS) { if (to->to_flags & TOF_TS) {
sc->sc_tsreflect = to->to_tsval; sc->sc_tsreflect = to->to_tsval;
sc->sc_flags |= SCF_TIMESTAMP; sc->sc_flags |= SCF_TIMESTAMP;
sc->sc_tsoff = tcp_new_ts_offset(inc);
} }
if (to->to_flags & TOF_SCALE) { if (to->to_flags & TOF_SCALE) {
int wscale = 0; int wscale = 0;
@ -2035,11 +2036,6 @@ syncookie_generate(struct syncache_head *sch, struct syncache *sc)
iss = hash & ~0xff; iss = hash & ~0xff;
iss |= cookie.cookie ^ (hash >> 24); 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); TCPSTAT_INC(tcps_sc_sendcookie);
return (iss); return (iss);
} }
@ -2126,7 +2122,7 @@ syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
if (to->to_flags & TOF_TS) { if (to->to_flags & TOF_TS) {
sc->sc_flags |= SCF_TIMESTAMP; sc->sc_flags |= SCF_TIMESTAMP;
sc->sc_tsreflect = to->to_tsval; 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) if (to->to_flags & TOF_SIGNATURE)

View File

@ -1439,7 +1439,9 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
soisconnecting(so); soisconnecting(so);
TCPSTAT_INC(tcps_connattempt); TCPSTAT_INC(tcps_connattempt);
tcp_state_change(tp, TCPS_SYN_SENT); 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); tcp_sendseqinit(tp);
return 0; return 0;
@ -1478,7 +1480,9 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
soisconnecting(inp->inp_socket); soisconnecting(inp->inp_socket);
TCPSTAT_INC(tcps_connattempt); TCPSTAT_INC(tcps_connattempt);
tcp_state_change(tp, TCPS_SYN_SENT); 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); tcp_sendseqinit(tp);
return 0; return 0;

View File

@ -923,7 +923,9 @@ void tcp_hc_updatemtu(struct in_conninfo *, uint32_t);
void tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *); void tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
extern struct pr_usrreqs tcp_usrreqs; 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); 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); void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);