kern/60889: 5.2RC2 - zero IP id change not effective for TCP, detrimental to security/privacy and maybe interoperation

Richard Wendland richard at wendland.org.uk
Sun Jan 4 04:10:28 PST 2004


>Number:         60889
>Category:       kern
>Synopsis:       5.2RC2 - zero IP id change not effective for TCP, detrimental to security/privacy and maybe interoperation
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jan 04 04:10:21 PST 2004
>Closed-Date:
>Last-Modified:
>Originator:     Richard Wendland
>Release:        5.2-RC2
>Organization:
>Environment:
FreeBSD dva.in-berlin.de 5.2-RC FreeBSD 5.2-RC #0: Thu Jan  1 21:30:04 CET 2004     root at dva.in-berlin.de:/usr/src/sys/i386/compile/DVA  i386    
>Description:
The src/sys/netinet/ip_output.c Revision 1.189 change to IP to generate a
zero ip_id field when DF is used only partly achieves its objectives for
TCP, and is (arguably) a detriment to security/privacy.  There is also
a risk of TCP interoperation problems with some Windows95/2000 systems
using VJ header compression from this change.  This change seems to have
taken place after release 5.1, so is new to 5.2 RC1 and RC2.

TCP emits FIN-ACK without DF, so now just one segment per TCP connection
goes out with a non-zero ip_id.  This means the change's objectives are
not really met for TCP; it just means FIN-ACK must be observed.

Worse, for many systems the ip_id now becomes a close approximate count
of the number of TCP connections it has made, so external observers
can fairly easily count the number of TCP connections a system makes,
which was not possible before this change.  To me this seems more of
a privacy issue for all FreeBSD users than the NAT-only issue in Steve
Bellovin's paper this change seeks to solve.

Another consideration is that Linux made exactly this change some time
ago, around Linux 2.4.4, but was forced to backout the change because
(I think) of practical connectivity issues related to the comment in
include/net/ip.h ip_select_ident() where it now implements an incrementing
ip_id for DF:

    /* This is only to work around buggy Windows95/2000
     * VJ compression implementations.  If the ID field
     * does not change, they drop every other packet in
     * a TCP stream using header compression.
     */

Has anyone checked that this buggy Windows95/2000 VJ compression problem
is no longer an issue in practice?  I doubt that the large web hosters
who use FreeBSD would be best-pleased if they ran into this for even
just a few users - especially as there is no config option to disable
this change.

I suggest this change is backed out of 5.2, to give more time for these
issues to be considered and tested.

NB I've read the source and I can't see why the FIN-ACK goes out without
a DF, it's emitted as TCP moves from FIN_WAIT_x state to TIME_WAIT
probably at line 3091 of tcp_input.c with a call to tcp_output().
tcp_output() always appears to set IP_DF at line 998 of tcp_output.c,
if path_mtu_discovery is enabled.  A puzzle.

Here's tcpdump output from a HTTP HEAD request showing the issue,
the last segment is the FIN-ACK with the only non-zero id (and no DF)
from fbsd-5_2RC2.80:

17:10:26.566423 fbsd-4_3.3700 > fbsd-5_2RC2.80: S 3955049829:3955049829(0) win 16384 <mss 1460,nop,wscale 0,nop,nop,timestamp 1986916345 0> (DF) (ttl 64, id 36227)
17:10:26.604219 fbsd-5_2RC2.80 > fbsd-4_3.3700: S 2579960593:2579960593(0) ack 3955049830 win 65535 <mss 1452,nop,wscale 1,nop,nop,timestamp 16007425 1986916345> (DF) (ttl 53, id 0)
17:10:26.604259 fbsd-4_3.3700 > fbsd-5_2RC2.80: . ack 1 win 17280 <nop,nop,timestamp 1986916349 16007425> (DF) (ttl 64, id 36228)
17:10:26.604426 fbsd-4_3.3700 > fbsd-5_2RC2.80: P 1:61(60) ack 1 win 17280 <nop,nop,timestamp 1986916349 16007425> (DF) (ttl 64, id 36229)
17:10:26.655004 fbsd-5_2RC2.80 > fbsd-4_3.3700: P 1:278(277) ack 61 win 33120 <nop,nop,timestamp 16007429 1986916349> (DF) (ttl 53, id 0)
17:10:26.659403 fbsd-5_2RC2.80 > fbsd-4_3.3700: F 278:278(0) ack 61 win 33120 <nop,nop,timestamp 16007429 1986916349> (DF) (ttl 53, id 0)
17:10:26.659430 fbsd-4_3.3700 > fbsd-5_2RC2.80: . ack 279 win 17280 <nop,nop,timestamp 1986916354 16007429> (DF) (ttl 64, id 36231)
17:10:26.659468 fbsd-4_3.3700 > fbsd-5_2RC2.80: F 61:61(0) ack 279 win 17280 <nop,nop,timestamp 1986916354 16007429> (DF) (ttl 64, id 36232)
17:10:26.694533 fbsd-5_2RC2.80 > fbsd-4_3.3700: . ack 62 win 33119 <nop,nop,timestamp 16007434 1986916354> (ttl 53, id 25945)

Note that with this change ip_id is no longer in network byte order,
so id appears to increase in steps of 256 from i386 systems; you need
to be aware of this if you are using this to count TCP connections.

Incidentally this is also a new information leak from this change, you
can remotely identify the endian-ness of FreeBSD systems, in practice
currently if it runs on i386; whether this really matters for security
is debatable.

Thanks to Boris Staeblow <bs at dva.in-berlin.de> and Tim Rylance
<tkr at puffball.demon.co.uk> for highlighting this change and helping me
diagnose the issues.

>How-To-Repeat:
Make TCP connections to a 5.2-RC2 system.  Use tcpdump to
see the issue, observe the final FIN-ACK of a connection.
>Fix:
Back out the src/sys/netinet/ip_output.c Revision 1.189 change:

wollman     2003/05/31 10:55:21 PDT

FreeBSD src repository

Modified files:
  sys/netinet          ip_output.c
Log:
Don't generate an ip_id for packets with the DF bit set; ip_id is
only meaningful for fragments.  Also don't bother to byte-swap the
ip_id when we do generate it; it is only used at the receiver as a 
nonce.  I tried several different permutations of this code with no
measurable difference to each other or to the unmodified version, so
I've settled on the one for which gcc seems to generate the best code.
(If anyone cares to microoptimize this differently for an architecture
where it actually matters, feel free.)

Suggested by:   Steve Bellovin's paper in IMW'02

Revision  Changes    Path
1.189     +17 -4     src/sys/netinet/ip_output.c

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list