From owner-freebsd-hackers Sat Dec 2 14:28:30 1995 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.6.12/8.6.6) id OAA03962 for hackers-outgoing; Sat, 2 Dec 1995 14:28:30 -0800 Received: from parody.tecc.co.uk (parody.tecc.co.uk [193.128.6.83]) by freefall.freebsd.org (8.6.12/8.6.6) with ESMTP id OAA03866 for ; Sat, 2 Dec 1995 14:28:10 -0800 Received: (from james@localhost) by parody.tecc.co.uk (8.6.12/8.6.12) id VAA00454; Sat, 2 Dec 1995 21:12:06 GMT Date: Sat, 2 Dec 1995 21:12:06 GMT From: James Raynard Message-Id: <199512022112.VAA00454@parody.tecc.co.uk> To: freebsd-hackers@freebsd.org Subject: Bug in TCP's urgent data mechanism (fwd) Organization: A FreeBSD box Sender: owner-hackers@freebsd.org Precedence: bulk This was posted to comp.protocols.tcp-ip a few days ago and I thought I'd forward it here as 2.1.0-RELEASE contains the (alleged) bug. Any comments? James ------- start of forwarded message ------- Path: parody.tecc.co.uk!handbag.tecc.co.uk!plug.news.pipex.net!pipex!tube.news.pipex.net!pipex!tank.news.pipex.net!pipex!usenet.eel.ufl.edu!news-feed-1.peachnet.edu!pirates!cssun.mathcs.emory.edu!swrinde!newsfeed.internetmci.com!in1.uu.net!news.biu.ac.il!news.huji.ac.il!shum.cc.huji.ac.il!pretzel.cs.huji.ac.il!pita.cs.huji.ac.il!orenl Newsgroups: comp.protocols.tcp-ip Subject: Bug in TCP's urgent data mechanism Message-ID: <49bpdr$d41@pretzel.cs.huji.ac.il> From: orenl@pita.cs.huji.ac.il (Oren Laden) Date: 27 Nov 1995 07:30:03 GMT Distribution: world Organization: The Hebrew U. of Jerusalem, Computer Science Dept. NNTP-Posting-Host: pita.cs.huji.ac.il Lines: 118 Description: ----------- Under certain circumstances (see below) TCP's output code does not set the URG flag on an outgoing packet holding urgent data. As a consequence this data becomes available to the consumer process as part of the regular stream. Consider the following scenario (with two processes, A and B): (assume at side A: snd_nxt == snd_una == snd_up == 573) A issues a write() syscall for 28 bytes. Before TCP actually delivers this data (OR the packet with the data got lost), A sends one OOB to B (seq#601). Now TCP's output function (tcp_output()) sends this urgent byte to the receiving side. At the other side, tcp_input() detects the urgent data and pulls it out. It also sends ACK for 573 (because the next packet was lost). tcp_output() (on A) retransmits 573-602 (the 28 bytes + the OOB). However, at the point where the code decides to set (or unset) the URG flag on the outgoing packet, the test compares snd_up to snd_nxt (which has advanced since !), resulting in a packet holding urgent data, without the URG flag set !This byte propagates later to process B's input stream, leading to unexpected behaviour. For example, watch the following TCP trace (filtered output of tcpdump): 1. A > b: P 557:573(16) ack 705 win 18980 2. b > A: P 705:737(32) ack 573 win 18432 3. A > b: P 601:602(1) ack 737 win 18980 urg 1 4. b > A: . ack 573 win 18432 5. A > b: . ack 737 win 18980 6. b > A: P 737:745(8) ack 573 win 18432 7. A > b: . ack 745 win 18980 8. A > b: P 573:602(29) ack 745 win 18980 9. b > A: . ack 602 win 18403 10. b > A: P 745:769(24) ack 602 win 18431 11. A > b: P 602:618(16) ack 769 win 18980 Note lines 3 (OOB delivering), 4 (ACK stays behind) and 8 (urgent data without URG flag). Release: ------- BSD/OS 1.0, 1.1, 2.0, 2.0.1 as well as: 4.4BSD networking code (and derivatives). Repeat-By: --------- It isn't simple to make the bug show itself... especially at the user level. Here is the proposed method (not deterministic, of course): Creat process A and B on different machines. Use INET sockets (TCP) to connect A and B, and then fork() A into two processes. Use the parent to write data to B, and the child to write OOB data (one byte) from time to time. If the network is congested enough, and you are lucky - process B will receive one extra byte of data. Fix: --- The fix is very simple - a small patch to netinet/tcp_output.c : Replace the lines surrounded by ifdef's (in tcp_output() subroutine...): tcp_output(tp) register struct tcpcb *tp; { ... ... ... /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg) win = 0; if (win > (long)TCP_MAXWIN << tp->rcv_scale) win = (long)TCP_MAXWIN << tp->rcv_scale; if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) win = (long)(tp->rcv_adv - tp->rcv_nxt); ti->ti_win = htons((u_short) (win>>tp->rcv_scale)); #ifdef FIX_OOB_BUG if (SEQ_GT(tp->snd_up, tp->snd_una)) { ti->ti_urp = htons((u_short)(tp->snd_up - ntohl(ti->ti_seq))); #else /* THE CODE BELOW IS WRONG ! */ if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt)); #endif /* BUG SHOULD BE FIXED :-) */ ti->ti_flags |= TH_URG; } else /* * If no urgent pointer to send, then we pull * the urgent pointer to the left edge of the send window * so that it doesn't drift into the send window on sequence * number wraparound. */ ... ... ... } That's it folks. Oren. ___ **************************************** |\/\/\/|| \ ** Oren Laden (orenl@cs.huji.ac.il) ** | | |___/ /\ ___ ** ---------------------------------- ** | | | \ / \ | \ _____ ** Distributed Operating Systems lab. ** | (0)(0)|___/ /----\ |___/ | ** Computer Science Institute ** c _) / \ | \ | ** The Hebrew University of Jerusalem **| ,___| | \ | ** Jerusalem, Israel 91904 ** | / | **************************************** /____\ S I M P S O N " Ouch .... Quit It ! " / \ ------- end of forwarded message -------