From owner-freebsd-security Fri Jan 21 3:45:15 2000 Delivered-To: freebsd-security@freebsd.org Received: from intranova.net (blacklisted.intranova.net [209.3.31.70]) by hub.freebsd.org (Postfix) with SMTP id 146A214D63 for ; Fri, 21 Jan 2000 03:45:09 -0800 (PST) (envelope-from oogali@intranova.net) Received: (qmail 619 invoked from network); 21 Jan 2000 06:47:23 -0000 Received: from missnglnk.wants.to-fuck.com (HELO hydrant.intranova.net) (user28815@209.201.95.10) by blacklisted.intranova.net with SMTP; 21 Jan 2000 06:47:23 -0000 Date: Fri, 21 Jan 2000 06:43:54 -0500 (EST) From: Omachonu Ogali To: Brett Glass Cc: security@freebsd.org Subject: Re: stream.c worst-case kernel paths In-Reply-To: <4.2.2.20000120182425.01886ec0@localhost> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org Would this work: -- start -- --- tcp_input.c Tue Apr 20 15:09:15 1999 +++ tcp_input.c.new Fri Jan 21 06:30:13 2000 @@ -398,7 +398,27 @@ "Connection attempt to TCP %s:%d from %s:%d\n", buf, ntohs(ti->ti_dport), inet_ntoa(ti->ti_src), ntohs(ti->ti_sport)); + } else if (tiflags & TH_ACK) { + /* + * Alpha code in response to stream.c + * - Omachonu Ogali + */ + + char buf[4*sizeof "123"]; + + strcpy(buf, inet_ntoa(ti->ti_dst)); + log(LOG_INFO, + "received TCP/ACK to non existant connection: %s:%d -> %s:%d\n", + inet_ntoa(ti->ti_src), ntohs(ti->ti_sport), buf, ntohs(ti->ti_dport)); + + /* + * Drop without reset to prevent smurf-like tcp + * attack + */ + + goto drop; } + #ifdef ICMP_BANDLIM if (badport_bandlim(1) < 0) goto drop; -- stop -- Omachonu Ogali Intranova Networking Group On Thu, 20 Jan 2000, Brett Glass wrote: > I've been browsing the code, and have seen two possible places where > the code might be improved to lessen the impact of this DoS. Folks > who know the stack better may know about details and side effects > that I don't, so so if my analysis has holes in it please don't chew > me out TOO badly. > > From /sys/netinet/tcp_input.c: > > The kernel seeks a socket that matches the packet. It fails, of course, > to find an open socket. > > inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, > ti->ti_dst, ti->ti_dport, 1); > > If the system isn't listening on the port, inp is set to NULL. But inside > in_pcblookup_hash, we've had to do two hash table lookups, because > the "wildcard" flag is set to 1. (Suggested improvement: turn off the > wildcard search if the packet is not a SYN. I suppose that if the > packet IS a SYN, we still have to test to see if it was erroneously > sent in the middle of a connection, so we really have to do both tests > in that case. See in_pcb.c.) > > Back to tcp_input.c. We then execute the following: > > if (inp == NULL) { > if (log_in_vain && tiflags & TH_SYN) { > char buf[4*sizeof "123"]; > > strcpy(buf, inet_ntoa(ti->ti_dst)); > log(LOG_INFO, > "Connection attempt to TCP %s:%d from %s:%d\n", > buf, ntohs(ti->ti_dport), inet_ntoa(ti->ti_src), > ntohs(ti->ti_sport)); > } > } > #ifdef ICMP_BANDLIM > if (badport_bandlim(1) < 0) > goto drop; > #endif > goto dropwithreset; > } > > Normally, we'll wind up at the label "dropwithreset", which means we'll send back a RST. > This suggests that restricting RSTs will help with the DoS. (Does anyone know if > not sending an RST violates any RFCs if there was never a connection?) > > Trouble is, a smart attacker will fire the barrage at a port on which the machine is > listening. This makes the code path longer because the hash table lookup will succeed. > We execute: > > tp = intotcpcb(inp); > if (tp == 0) > goto dropwithreset; > if (tp->t_state == TCPS_CLOSED) > goto drop; > > /* Unscale the window into a 32-bit value. */ > if ((tiflags & TH_SYN) == 0) > tiwin = ti->ti_win << tp->snd_scale; > else > tiwin = ti->ti_win; > > so = inp->inp_socket; > if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { > #ifdef TCPDEBUG > if (so->so_options & SO_DEBUG) { > ostate = tp->t_state; > tcp_saveti = *ti; > } > #endif > if (so->so_options & SO_ACCEPTCONN) { > register struct tcpcb *tp0 = tp; > struct socket *so2; > if ((tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { > /* > * Note: dropwithreset makes sure we don't > * send a RST in response to a RST. > */ > if (tiflags & TH_ACK) { > tcpstat.tcps_badsyn++; > goto dropwithreset; > } > goto drop; > > At which point the packet is dropped, since tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN > (that is, it's not a SYN). But we've had to attempt two hash table lookups (we could have done > only one if we'd tested for a SYN) and send the RST unless we've disabled it. Worse still, if > we send the RSTs, we may have to handle an ICMP "unreachable" message from the router if the > source address is spoofed. > > So, the two obvious optimizations are to add a test for SYNs prior to the hash table lookup and > not to send a RST back. > > --Brett > > > > > > To Unsubscribe: send mail to majordomo@FreeBSD.org > with "unsubscribe freebsd-security" in the body of the message > To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message