panic: tcp_addoptions: TCP options too long w/ with TCP_SIGNATURE support

Andre Oppermann andre at freebsd.org
Tue Apr 1 13:40:54 PDT 2008


Andre Oppermann wrote:
> Mark Atkinson wrote:
>> Rui Paulo wrote:
>>
>>> Hi,
>>>
>>> On Tue, Apr 01, 2008 at 09:08:35AM -0700, Mark Atkinson wrote:
>>>> I have a 8-CURRENT kernel compiled with the following options, from 
>>>> about
>>>> march 5th.
>>>>
>>>> options        IPSEC
>>>> options        TCP_SIGNATURE           #include support for RFC 2385
>>>> device         crypto
>>>> device         cryptodev
>>>>
>>>> device          pf
>>>> device          pflog
>>>>
>>>> device         vlan
>>>>
>>>> I also have a external server supporting MD5 tcp signatures.  If I give
>>>> the following command:
>>>>
>>>> /usr/src/tools/regression/netinet/tcpconnect/tcpconnect client
>>>> 172.16.1.145 7 1 tcpmd5
>>>>
>>>> panic: tcp_addoptions: TCP options too long
>>> Could you please use gdb or add a printf to find the value of optlen ?
>>>
>>
>> $ kgdb kernel.debug /var/crash/vmcore.2
>> [GDB will not be able to debug user-mode threads: 
>> /usr/lib/libthread_db.so:
>> Undefined symbol "ps_pglobal_lookup"]
>> GNU gdb 6.1.1 [FreeBSD]
>> Copyright 2004 Free Software Foundation, Inc.
>> GDB is free software, covered by the GNU General Public License, and 
>> you are
>> welcome to change it and/or distribute copies of it under certain
>> conditions.
>> Type "show copying" to see the conditions.
>> There is absolutely no warranty for GDB.  Type "show warranty" for 
>> details.
>> This GDB was configured as "i386-marcel-freebsd".
>> Reading symbols from /boot/kernel/acpi.ko...Reading symbols
>> from /boot/kernel/acpi.ko.symbols...done.
>> done.
>> Loaded symbols for /boot/kernel/acpi.ko
>> Reading symbols from /boot/kernel/ipfw.ko...Reading symbols
>> from /boot/kernel/ipfw.ko.symbols...done.
>> done.
>> Loaded symbols for /boot/kernel/ipfw.ko
>>
>> Unread portion of the kernel message buffer:
>> panic: tcp_addoptions: TCP options too long
>> cpuid = 1
>> KDB: enter: panic
>> Physical memory: 2034 MB
>> Dumping 79 MB: 64 48 32 16
>>
>> #0  doadump () at pcpu.h:195
>> 195             __asm __volatile("movl %%fs:0,%0" : "=r" (td));
>> (kgdb) bt
>> #0  doadump () at pcpu.h:195
>> #1  0xc04c7159 in db_fncall (dummy1=1017, dummy2=0, dummy3=1019,
>> dummy4=0xe7b808b0 "ø\003") at /usr/src/sys/ddb/db_command.c:516
>> #2  0xc04c76dc in db_command (last_cmdp=0xc0c5c7b4, cmd_table=0x0,
>> dopager=1) at /usr/src/sys/ddb/db_command.c:413
>> #3  0xc04c77ea in db_command_loop () at /usr/src/sys/ddb/db_command.c:466
>> #4  0xc04c8fec in db_trap (type=3, code=0) at 
>> /usr/src/sys/ddb/db_main.c:228
>> #5  0xc07cf325 in kdb_trap (type=3, code=0, tf=0xe7b80a58)
>> at /usr/src/sys/kern/subr_kdb.c:510
>> #6  0xc0ac8d5f in trap (frame=0xe7b80a58)
>> at /usr/src/sys/i386/i386/trap.c:643
>> #7  0xc0aad7cb in calltrap () at /usr/src/sys/i386/i386/exception.s:146
>> #8  0xc07cf4aa in kdb_enter (why=0xc0b62ce8 "panic", msg=0xc0b62ce8 
>> "panic")
>> at cpufunc.h:60
>> #9  0xc07a67cc in panic (fmt=0xc0b78840 "%s: TCP options too long")
>> at /usr/src/sys/kern/kern_shutdown.c:556
>> #10 0xc08e8207 in tcp_addoptions (to=0xe7b80ba4,
>> optp=0xe7b80bc0 "\002\004\005´\001\003\003\003\001\001\b\n")
>> at /usr/src/sys/netinet/tcp_output.c:1402
>> #11 0xc08e8c79 in tcp_output (tp=0xc576d570)
>> at /usr/src/sys/netinet/tcp_output.c:693
>> #12 0xc08f4f35 in tcp_usr_connect (so=0xc5709794, nam=0xc5260280,
>> td=0xc5729210) at tcp_offload.h:251
>> #13 0xc07ff092 in soconnect (so=0xc5709794, nam=0xc5260280, 
>> td=0xc5729210)
>> at /usr/src/sys/kern/uipc_socket.c:765
>> #14 0xc0805436 in kern_connect (td=0xc5729210, fd=3, sa=0xc5260280)
>> at /usr/src/sys/kern/uipc_syscalls.c:560
>> #15 0xc08055a6 in connect (td=0xc5729210, uap=0xe7b80cfc)
>> at /usr/src/sys/kern/uipc_syscalls.c:524
>> #16 0xc0ac8513 in syscall (frame=0xe7b80d38)
>> at /usr/src/sys/i386/i386/trap.c:1026
>> #17 0xc0aad830 in Xint0x80_syscall ()
>> at /usr/src/sys/i386/i386/exception.s:203
>> #18 0x00000033 in ?? ()
>> Previous frame inner to this frame (corrupt stack?)
>> (kgdb) frame 10
>> #10 0xc08e8207 in tcp_addoptions (to=0xe7b80ba4,
>> optp=0xe7b80bc0 "\002\004\005´\001\003\003\003\001\001\b\n")
>> at /usr/src/sys/netinet/tcp_output.c:1402
>> 1402            KASSERT(optlen <= TCP_MAXOLEN, ("%s: TCP options too 
>> long",
>> __func__));
>> (kgdb) p optlen
>> $1 = 44
>> (kgdb)
> 
> The order of the TCP options was changed recently to fix another problem.
> This has caused sub-optimal padding and this overflow as not all options
> fit.  The tcp_addoptions() loop is not bound internally.

Correction: It is bound but not for all options (only SACK and Signature).

> http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet/tcp_output.c?rev=1.146 

Before:

   MSS (4) + NOP (1) + Window scale (3) + SACK permitted (2) +
   Timestamp (10) + Signature (18) = 38 bytes out of a maximum of 40.

After:

  MSS (4) + NOP (1) + Window scale (3) + NOP (2) + Timestamp (10) +
  NOP (2) + Signature (18) + SACK permitted (2) + EOL (1) + PAD (1) =
  44 bytes out of a maximum of 40.

With the attached patch it will omit the SACK permitted option (disabling
SACK) and limiting it to 40 bytes.

-- 
Andre

==== //depot/projects/tcp_reass/netinet/tcp_output.c#5 (text+ko) ====

@@ -1279,12 +1279,16 @@
  	for (mask = 1; mask < TOF_MAXOPT; mask <<= 1) {
  		if ((to->to_flags & mask) != mask)
  			continue;
+		if (optlen == TCP_MAXOLEN)
+			break;
  		switch (to->to_flags & mask) {
  		case TOF_MSS:
  			while (optlen % 4) {
  				optlen += TCPOLEN_NOP;
  				*optp++ = TCPOPT_NOP;
  			}
+			if (TCP_MAXOLEN - optlen < TCPOLEN_MAXSEG)
+				continue;
  			optlen += TCPOLEN_MAXSEG;
  			*optp++ = TCPOPT_MAXSEG;
  			*optp++ = TCPOLEN_MAXSEG;
@@ -1297,6 +1301,8 @@
  				optlen += TCPOLEN_NOP;
  				*optp++ = TCPOPT_NOP;
  			}
+			if (TCP_MAXOLEN - optlen < TCPOLEN_WINDOW)
+				continue;
  			optlen += TCPOLEN_WINDOW;
  			*optp++ = TCPOPT_WINDOW;
  			*optp++ = TCPOLEN_WINDOW;
@@ -1307,6 +1313,8 @@
  				optlen += TCPOLEN_NOP;
  				*optp++ = TCPOPT_NOP;
  			}
+			if (TCP_MAXOLEN - optlen < TCPOLEN_SACK_PERMITTED)
+				continue;
  			optlen += TCPOLEN_SACK_PERMITTED;
  			*optp++ = TCPOPT_SACK_PERMITTED;
  			*optp++ = TCPOLEN_SACK_PERMITTED;
@@ -1316,6 +1324,8 @@
  				optlen += TCPOLEN_NOP;
  				*optp++ = TCPOPT_NOP;
  			}
+			if (TCP_MAXOLEN - optlen < TCPOLEN_TIMESTAMP)
+				continue;
  			optlen += TCPOLEN_TIMESTAMP;
  			*optp++ = TCPOPT_TIMESTAMP;
  			*optp++ = TCPOLEN_TIMESTAMP;
@@ -1352,7 +1362,7 @@
  				optlen += TCPOLEN_NOP;
  				*optp++ = TCPOPT_NOP;
  			}
-			if (TCP_MAXOLEN - optlen < 2 + TCPOLEN_SACK)
+			if (TCP_MAXOLEN - optlen < TCPOLEN_SACKHDR + TCPOLEN_SACK)
  				continue;
  			optlen += TCPOLEN_SACKHDR;
  			*optp++ = TCPOPT_SACK;


More information about the freebsd-net mailing list