Subject: kern/34674: Panic in tcp_input() by integer division fault
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Christian Biere <christianbiere@gmx.de>
List: netbsd-bugs
Date: 09/30/2006 14:50:00
>Number:         34674
>Category:       kern
>Synopsis:       Panic in tcp_input() by integer division fault
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Sep 30 14:50:00 +0000 2006
>Originator:     Christian Biere
>Release:        NetBSD 4.99.3
>Environment:
System: NetBSD cyclonus 4.99.3 NetBSD 4.99.3 (STARSCREAM) #2: Sat Sep 30 16:12:53 CEST 2006 src@cyclonus:/o/NetBSD/obj/sys/arch/i386/compile/STARSCREAM i386
Architecture: i386
Machine: i386
>Description:
NetBSD as of today crashes instantly with a "integer division fault" in tcp_input()
when I start gtk-gnutella. This bug must have been added within the last few days
(up to a week maybe). The first patch shows the place at I suspect the divison-by-zero
occurs. savecore is currently broken for me, so I had to look at the assemble code
at "eip" with gdb.

Adding a check against zero helped against this panic but lead to another
in m_copydata() due to a negative length of "-12".

I reverted the last modification to tcp_output.c and this seems to have fixed
the latter panic. I presume this last change introduced an underflow or off-by-one
bug.

>How-To-Repeat:
Any TCP-heavy application with many connections should trigger this panic.

>Fix:

Index: tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.244
diff -u -p -u -r1.244 tcp_input.c
--- tcp_input.c	5 Sep 2006 00:29:36 -0000	1.244
+++ tcp_input.c	30 Sep 2006 13:37:28 -0000
@@ -2386,7 +2386,7 @@ after_listen:
 		 * NewReno and we have only received partial acks), do not
 		 * inflate the window yet.
 		 */
-		if (tp->t_partialacks < 0) {
+		if (tp->t_partialacks < 0 && tp->snd_cwnd > 0) {
 			u_int cw = tp->snd_cwnd;
 			u_int incr = tp->t_segsz;

Index: tcp_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_output.c,v
retrieving revision 1.144
retrieving revision 1.143
diff -u -r1.144 -r1.143
--- tcp_output.c	28 Sep 2006 04:32:47 -0000	1.144
+++ tcp_output.c	5 Sep 2006 00:29:36 -0000	1.143
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_output.c,v 1.144 2006/09/28 04:32:47 dbj Exp $	*/
+/*	$NetBSD: tcp_output.c,v 1.143 2006/09/05 00:29:36 rpaulo Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -142,7 +142,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.144 2006/09/28 04:32:47 dbj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.143 2006/09/05 00:29:36 rpaulo Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -397,8 +397,7 @@
 	 * transmit.
 	 */
 	if (so)
-		*txsegsizep = min((so->so_snd.sb_hiwat - 
-			so->so_snd.sb_lowat + 1) >> 1, *txsegsizep);
+		*txsegsizep = min(so->so_snd.sb_hiwat >> 1, *txsegsizep);
 	*rxsegsizep = min(tp->t_ourmss - optlen, size);
 
 	if (*txsegsizep != tp->t_segsz) {