Module Name: src Committed By: uwe Date: Mon May 7 23:42:13 UTC 2018
Modified Files: src/sys/netinet: tcp_output.c Log Message: Fix unsigned wraparound on window size calculations. This is another instance where tp->rcv_adv - tp->rcv_nxt can wrap around after successful zero-window probe from the peer. The first one was fixed by chs@ in revision 1.112 on 2004-05-08. While here, CSE and de-obfuscate the code a bit. To generate a diff of this commit: cvs rdiff -u -r1.206 -r1.207 src/sys/netinet/tcp_output.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/tcp_output.c diff -u src/sys/netinet/tcp_output.c:1.206 src/sys/netinet/tcp_output.c:1.207 --- src/sys/netinet/tcp_output.c:1.206 Thu May 3 07:13:48 2018 +++ src/sys/netinet/tcp_output.c Mon May 7 23:42:13 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_output.c,v 1.206 2018/05/03 07:13:48 maxv Exp $ */ +/* $NetBSD: tcp_output.c,v 1.207 2018/05/07 23:42:13 uwe Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -135,7 +135,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.206 2018/05/03 07:13:48 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.207 2018/05/07 23:42:13 uwe Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -987,16 +987,27 @@ again: * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ - long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - - (tp->rcv_adv - tp->rcv_nxt); + long recwin = min(win, (long)TCP_MAXWIN << tp->rcv_scale); + long oldwin, adv; /* - * If the new window size ends up being the same as the old - * size when it is scaled, then don't force a window update. + * rcv_nxt may overtake rcv_adv when we accept a + * zero-window probe. */ - if ((tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale == - (adv + tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale) + if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) + oldwin = tp->rcv_adv - tp->rcv_nxt; + else + oldwin = 0; + + /* + * If the new window size ends up being the same as or + * less than the old size when it is scaled, then + * don't force a window update. + */ + if (recwin >> tp->rcv_scale <= oldwin >> tp->rcv_scale) goto dontupdate; + + adv = recwin - oldwin; if (adv >= (long) (2 * rxsegsize)) goto send; if (2 * adv >= (long) so->so_rcv.sb_hiwat)