DF-0755 / fix.diff
diff --git a/sys/netinet/tcp_debug.c b/sys/netinet/tcp_debug.c --- a/sys/netinet/tcp_debug.c +++ b/sys/netinet/tcp_debug.c @@ -47,6 +47,8 @@ #include <sys/systm.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/spinlock.h> +#include <sys/spinlock2.h> #include <net/netisr.h> #include <net/netmsg.h> @@ -67,6 +69,15 @@ static int tcpconsdebug = 0; static struct tcp_debug tcp_debug[TCP_NDEBUG]; +/* + * tcp_debx is a process-global index into tcp_debug[]. It is read/modified + * from concurrent TCP trace events on every CPU (per-tcpcb tokens do not + * serialize it). Take a spinlock around the increment + wrap so the index + * cannot race past TCP_NDEBUG and write struct tcp_debug off the end of the + * array into BSS (DF-0755). This is a cold, debug-only path, so the lock + * cost is irrelevant. + */ +static struct spinlock tcp_debx_spin = SPINLOCK_INITIALIZER(tcp_debx_spin, "tcp_debx"); static int tcp_debx; /* @@ -81,7 +92,15 @@ #endif /* INET6 */ tcp_seq seq, ack; int len, flags; - struct tcp_debug *td = &tcp_debug[tcp_debx++]; + int slot; + struct tcp_debug *td; + + spin_lock(&tcp_debx_spin); + slot = tcp_debx++; + if (tcp_debx == TCP_NDEBUG) + tcp_debx = 0; + spin_unlock(&tcp_debx_spin); + td = &tcp_debug[slot]; #ifdef INET6 isipv6 = (ipgen != NULL && ((struct ip *)ipgen)->ip_v == 6) ? 1 : 0; @@ -91,8 +110,6 @@ (isipv6 != 0) ? AF_INET6 : #endif AF_INET; - if (tcp_debx == TCP_NDEBUG) - tcp_debx = 0; td->td_time = iptime(); td->td_act = act; td->td_ostate = ostate; |