Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 Jan 2000 20:17:30 -0700
From:      Brett Glass <brett@lariat.org>
To:        security@freebsd.org
Subject:   stream.c worst-case kernel paths
Message-ID:  <4.2.2.20000120182425.01886ec0@localhost>

next in thread | raw e-mail | index | archive | help
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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4.2.2.20000120182425.01886ec0>