Convert tcp_now() time counter to 64 bit.
authorbluhm <bluhm@openbsd.org>
Thu, 6 Jul 2023 09:15:23 +0000 (09:15 +0000)
committerbluhm <bluhm@openbsd.org>
Thu, 6 Jul 2023 09:15:23 +0000 (09:15 +0000)
After changing tcp now tick to milliseconds, 32 bits will wrap
around after 49 days of uptime.  That may be a problem in some
places of our stack.  Better use a 64 bit counter.

As timestamp option is 32 bit in TCP protocol, use the lower 32 bit
there.  There are casts to 32 bits that should behave correctly.

Start with random 63 bit offset to avoid uptime leakage.  2^63
milliseconds result in 2.9*10^8 years of possible uptime.

OK yasuoka@

sys/netinet/tcp_input.c
sys/netinet/tcp_output.c
sys/netinet/tcp_subr.c
sys/netinet/tcp_timer.c
sys/netinet/tcp_usrreq.c
sys/netinet/tcp_var.h

index 5986da0..6585978 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_input.c,v 1.388 2023/05/30 19:32:57 bluhm Exp $   */
+/*     $OpenBSD: tcp_input.c,v 1.389 2023/07/06 09:15:23 bluhm Exp $   */
 /*     $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $  */
 
 /*
@@ -130,8 +130,8 @@ struct timeval tcp_ackdrop_ppslim_last;
 #define TCP_PAWS_IDLE  TCP_TIME(24 * 24 * 60 * 60)
 
 /* for modulo comparisons of timestamps */
-#define TSTMP_LT(a,b)  ((int)((a)-(b)) < 0)
-#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
+#define TSTMP_LT(a,b)  ((int32_t)((a)-(b)) < 0)
+#define TSTMP_GEQ(a,b) ((int32_t)((a)-(b)) >= 0)
 
 /* for TCP SACK comparisons */
 #define        SEQ_MIN(a,b)    (SEQ_LT(a,b) ? (a) : (b))
@@ -190,7 +190,7 @@ void         tcp_newreno_partialack(struct tcpcb *, struct tcphdr *);
 
 void    syn_cache_put(struct syn_cache *);
 void    syn_cache_rm(struct syn_cache *);
-int     syn_cache_respond(struct syn_cache *, struct mbuf *, uint32_t);
+int     syn_cache_respond(struct syn_cache *, struct mbuf *, uint64_t);
 void    syn_cache_timer(void *);
 void    syn_cache_reaper(void *);
 void    syn_cache_insert(struct syn_cache *, struct tcpcb *);
@@ -198,10 +198,10 @@ void       syn_cache_reset(struct sockaddr *, struct sockaddr *,
                struct tcphdr *, u_int);
 int     syn_cache_add(struct sockaddr *, struct sockaddr *, struct tcphdr *,
                unsigned int, struct socket *, struct mbuf *, u_char *, int,
-               struct tcp_opt_info *, tcp_seq *, uint32_t);
+               struct tcp_opt_info *, tcp_seq *, uint64_t);
 struct socket *syn_cache_get(struct sockaddr *, struct sockaddr *,
                struct tcphdr *, unsigned int, unsigned int, struct socket *,
-               struct mbuf *, uint32_t);
+               struct mbuf *, uint64_t);
 struct syn_cache *syn_cache_lookup(struct sockaddr *, struct sockaddr *,
                struct syn_cache_head **, u_int);
 
@@ -375,7 +375,7 @@ tcp_input(struct mbuf **mp, int *offp, int proto, int af)
        short ostate;
        caddr_t saveti;
        tcp_seq iss, *reuse = NULL;
-       uint32_t now;
+       uint64_t now;
        u_long tiwin;
        struct tcp_opt_info opti;
        struct tcphdr *th;
@@ -885,7 +885,7 @@ findpcb:
                        goto drop;
 
        if (opti.ts_present && opti.ts_ecr) {
-               int rtt_test;
+               int32_t rtt_test;
 
                /* subtract out the tcp timestamp modulator */
                opti.ts_ecr -= tp->ts_modulate;
@@ -1272,7 +1272,7 @@ trimthenstep6:
            TSTMP_LT(opti.ts_val, tp->ts_recent)) {
 
                /* Check to see if ts_recent is over 24 days old.  */
-               if ((int)(now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
+               if (now - tp->ts_recent_age > TCP_PAWS_IDLE) {
                        /*
                         * Invalidate ts_recent.  If this segment updates
                         * ts_recent, the age will be reset later and ts_recent
@@ -2120,7 +2120,7 @@ drop:
 int
 tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcphdr *th,
     struct mbuf *m, int iphlen, struct tcp_opt_info *oi,
-    u_int rtableid, uint32_t now)
+    u_int rtableid, uint64_t now)
 {
        u_int16_t mss = 0;
        int opt, optlen;
@@ -2686,7 +2686,7 @@ tcp_pulloutofband(struct socket *so, u_int urgent, struct mbuf *m, int off)
  * and update averages and current timeout.
  */
 void
-tcp_xmit_timer(struct tcpcb *tp, int rtt)
+tcp_xmit_timer(struct tcpcb *tp, int32_t rtt)
 {
        int delta, rttmin;
 
@@ -3335,7 +3335,7 @@ void
 syn_cache_timer(void *arg)
 {
        struct syn_cache *sc = arg;
-       uint32_t now;
+       uint64_t now;
 
        NET_LOCK();
        if (sc->sc_flags & SCF_DEAD)
@@ -3469,7 +3469,7 @@ syn_cache_lookup(struct sockaddr *src, struct sockaddr *dst,
  */
 struct socket *
 syn_cache_get(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
-    u_int hlen, u_int tlen, struct socket *so, struct mbuf *m, uint32_t now)
+    u_int hlen, u_int tlen, struct socket *so, struct mbuf *m, uint64_t now)
 {
        struct syn_cache *sc;
        struct syn_cache_head *scp;
@@ -3744,7 +3744,7 @@ syn_cache_unreach(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
 int
 syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
     u_int iphlen, struct socket *so, struct mbuf *m, u_char *optp, int optlen,
-    struct tcp_opt_info *oi, tcp_seq *issp, uint32_t now)
+    struct tcp_opt_info *oi, tcp_seq *issp, uint64_t now)
 {
        struct tcpcb tb, *tp;
        long win;
@@ -3911,7 +3911,7 @@ syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
 }
 
 int
-syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint32_t now)
+syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now)
 {
        u_int8_t *optp;
        int optlen, error;
index fabd9d3..8903d42 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_output.c,v 1.139 2023/07/04 10:48:19 bluhm Exp $  */
+/*     $OpenBSD: tcp_output.c,v 1.140 2023/07/06 09:15:24 bluhm Exp $  */
 /*     $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $      */
 
 /*
@@ -204,7 +204,7 @@ tcp_output(struct tcpcb *tp)
        int idle, sendalot = 0;
        int i, sack_rxmit = 0;
        struct sackhole *p;
-       uint32_t now;
+       uint64_t now;
 #ifdef TCP_SIGNATURE
        unsigned int sigoff;
 #endif /* TCP_SIGNATURE */
index ad8f7ea..7c68c48 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_subr.c,v 1.191 2023/05/10 12:07:16 bluhm Exp $    */
+/*     $OpenBSD: tcp_subr.c,v 1.192 2023/07/06 09:15:24 bluhm Exp $    */
 /*     $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $   */
 
 /*
@@ -137,6 +137,7 @@ struct cpumem *tcpcounters;         /* tcp statistics */
 u_char         tcp_secret[16]; /* [I] */
 SHA2_CTX       tcp_secret_ctx; /* [I] */
 tcp_seq                tcp_iss;        /* [T] updated by timer and connection */
+uint64_t       tcp_starttime;  /* [I] random offset for tcp_now() */
 
 /*
  * Tcp initialization
@@ -145,6 +146,9 @@ void
 tcp_init(void)
 {
        tcp_iss = 1;            /* wrong */
+       /* 0 is treated special so add 1, 63 bits to count is enough */
+       arc4random_buf(&tcp_starttime, sizeof(tcp_starttime));
+       tcp_starttime = 1ULL + (tcp_starttime / 2);
        pool_init(&tcpcb_pool, sizeof(struct tcpcb), 0, IPL_SOFTNET, 0,
            "tcpcb", NULL);
        pool_init(&tcpqe_pool, sizeof(struct tcpqent), 0, IPL_SOFTNET, 0,
@@ -289,7 +293,7 @@ tcp_template(struct tcpcb *tp)
  */
 void
 tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0,
-    tcp_seq ack, tcp_seq seq, int flags, u_int rtableid, uint32_t now)
+    tcp_seq ack, tcp_seq seq, int flags, u_int rtableid, uint64_t now)
 {
        int tlen;
        int win = 0;
index d1dbc8f..4f241bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_timer.c,v 1.72 2023/03/14 00:24:05 yasuoka Exp $  */
+/*     $OpenBSD: tcp_timer.c,v 1.73 2023/07/06 09:15:24 bluhm Exp $    */
 /*     $NetBSD: tcp_timer.c,v 1.14 1996/02/13 23:44:09 christos Exp $  */
 
 /*
@@ -394,7 +394,7 @@ tcp_timer_persist(void *arg)
        struct tcpcb *otp = NULL, *tp = arg;
        uint32_t rto;
        short ostate;
-       uint32_t now;
+       uint64_t now;
 
        NET_LOCK();
        /* Ignore canceled timeouts or timeouts that have been rescheduled. */
@@ -463,7 +463,7 @@ tcp_timer_keep(void *arg)
            tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) &&
            tp->t_state <= TCPS_CLOSING) {
                int maxidle;
-               uint32_t now;
+               uint64_t now;
 
                maxidle = READ_ONCE(tcp_maxidle);
                now = tcp_now();
@@ -506,7 +506,7 @@ tcp_timer_2msl(void *arg)
        struct tcpcb *otp = NULL, *tp = arg;
        short ostate;
        int maxidle;
-       uint32_t now;
+       uint64_t now;
 
        NET_LOCK();
        /* Ignore canceled timeouts or timeouts that have been rescheduled. */
index 7a92879..75d69a1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_usrreq.c,v 1.220 2023/07/02 19:59:15 bluhm Exp $  */
+/*     $OpenBSD: tcp_usrreq.c,v 1.221 2023/07/06 09:15:24 bluhm Exp $  */
 /*     $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
 
 /*
@@ -211,7 +211,7 @@ tcp_fill_info(struct tcpcb *tp, struct socket *so, struct mbuf *m)
        struct proc *p = curproc;
        struct tcp_info *ti;
        u_int t = 1000;         /* msec => usec */
-       uint32_t now;
+       uint64_t now;
 
        if (sizeof(*ti) > MLEN) {
                MCLGETL(m, M_WAITOK, sizeof(*ti));
index e071961..284f2b6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tcp_var.h,v 1.168 2023/07/02 19:59:15 bluhm Exp $     */
+/*     $OpenBSD: tcp_var.h,v 1.169 2023/07/06 09:15:24 bluhm Exp $     */
 /*     $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $    */
 
 /*
@@ -150,8 +150,8 @@ struct tcpcb {
                                         */
 
 /* auto-sizing variables */
+       uint64_t rfbuf_ts;      /* recv buffer autoscaling time stamp */
        u_int   rfbuf_cnt;      /* recv buffer autoscaling byte count */
-       u_int32_t rfbuf_ts;     /* recv buffer autoscaling time stamp */
 
        u_short t_maxopd;               /* mss plus options */
        u_short t_peermss;              /* peer's maximum segment size */
@@ -160,11 +160,11 @@ struct tcpcb {
  * transmit timing stuff.  See below for scale of srtt and rttvar.
  * "Variance" is actually smoothed difference.
  */
-       uint32_t t_rcvtime;             /* time last segment received */
-       uint32_t t_rcvacktime;          /* time last ack received */
-       uint32_t t_sndtime;             /* time last segment sent */
-       uint32_t t_sndacktime;          /* time last ack sent */
-       uint32_t t_rtttime;             /* time we started measuring rtt */
+       uint64_t t_rcvtime;             /* time last segment received */
+       uint64_t t_rcvacktime;          /* time last ack received */
+       uint64_t t_sndtime;             /* time last segment sent */
+       uint64_t t_sndacktime;          /* time last ack sent */
+       uint64_t t_rtttime;             /* time we started measuring rtt */
        tcp_seq t_rtseq;                /* sequence number being timed */
        int     t_srtt;                 /* smoothed round-trip time */
        int     t_rttvar;               /* variance in round-trip time */
@@ -183,9 +183,9 @@ struct tcpcb {
        u_char  rcv_scale;              /* window scaling for recv window */
        u_char  request_r_scale;        /* pending window scaling */
        u_char  requested_s_scale;
-       u_int32_t ts_recent;            /* timestamp echo data */
-       u_int32_t ts_modulate;          /* modulation on timestamp */
-       u_int32_t ts_recent_age;        /* when last updated */
+       uint32_t ts_recent;             /* timestamp echo data */
+       uint32_t ts_modulate;           /* modulation on timestamp */
+       uint64_t ts_recent_age;         /* when last updated */
        tcp_seq last_ack_sent;
 
 /* pointer for syn cache entries*/
@@ -250,12 +250,9 @@ struct syn_cache {
        long sc_win;                            /* advertised window */
        struct syn_cache_head *sc_buckethead;   /* our bucket index */
        struct syn_cache_set *sc_set;           /* our syn cache set */
+       u_int64_t sc_timestamp;                 /* timestamp from SYN */
        u_int32_t sc_hash;
-       u_int32_t sc_timestamp;                 /* timestamp from SYN */
        u_int32_t sc_modulate;                  /* our timestamp modulator */
-#if 0
-       u_int32_t sc_timebase;                  /* our local timebase */
-#endif
        union syn_cache_sa sc_src;
        union syn_cache_sa sc_dst;
        tcp_seq sc_irs;
@@ -657,10 +654,13 @@ tcpstat_pkt(enum tcpstat_counters pcounter, enum tcpstat_counters bcounter,
        counters_pkt(tcpcounters, pcounter, bcounter, v);
 }
 
-static inline uint32_t
+extern uint64_t tcp_starttime;
+
+static inline uint64_t
 tcp_now(void)
 {
-       return (getnsecruntime() / 1000000);
+       /* TCP time ticks in 63 bit milliseconds with 63 bit random offset. */
+       return tcp_starttime + (getnsecruntime() / 1000000ULL);
 }
 
 #define TCP_TIME(_sec) ((_sec) * 1000) /* tcp_now() is in milliseconds */
@@ -712,7 +712,7 @@ struct tcpcb *
 struct tcpcb *
         tcp_drop(struct tcpcb *, int);
 int     tcp_dooptions(struct tcpcb *, u_char *, int, struct tcphdr *,
-               struct mbuf *, int, struct tcp_opt_info *, u_int, uint32_t);
+               struct mbuf *, int, struct tcp_opt_info *, u_int, uint64_t);
 void    tcp_init(void);
 int     tcp_input(struct mbuf **, int *, int, int);
 int     tcp_mss(struct tcpcb *, int);
@@ -735,7 +735,7 @@ void         tcp_pulloutofband(struct socket *, u_int, struct mbuf *, int);
 int     tcp_reass(struct tcpcb *, struct tcphdr *, struct mbuf *, int *);
 void    tcp_rscale(struct tcpcb *, u_long);
 void    tcp_respond(struct tcpcb *, caddr_t, struct tcphdr *, tcp_seq,
-               tcp_seq, int, u_int, uint32_t);
+               tcp_seq, int, u_int, uint64_t);
 void    tcp_setpersist(struct tcpcb *);
 void    tcp_update_sndspace(struct tcpcb *);
 void    tcp_update_rcvspace(struct tcpcb *);
@@ -767,7 +767,7 @@ int  tcp_sense(struct socket *, struct stat *);
 int     tcp_rcvoob(struct socket *, struct mbuf *, int);
 int     tcp_sendoob(struct socket *, struct mbuf *, struct mbuf *,
             struct mbuf *);
-void    tcp_xmit_timer(struct tcpcb *, int);
+void    tcp_xmit_timer(struct tcpcb *, int32_t);
 void    tcpdropoldhalfopen(struct tcpcb *, u_int16_t);
 void    tcp_sack_option(struct tcpcb *,struct tcphdr *,u_char *,int);
 void    tcp_update_sack_list(struct tcpcb *tp, tcp_seq, tcp_seq);