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)

Reply via email to