Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Feb 2002 13:50:33 +0200
From:      Ruslan Ermilov <ru@FreeBSD.org>
To:        "Crist J. Clark" <cjc@FreeBSD.org>
Cc:        net@FreeBSD.org
Subject:   Re: TCP Connections to a Broadcast Address
Message-ID:  <20020223115033.GB47437@sunbay.com>
In-Reply-To: <20020222022626.A83807@blossom.cjclark.org>
References:  <20020222022626.A83807@blossom.cjclark.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Feb 22, 2002 at 02:26:26AM -0800, Crist J. Clark wrote:
> BSD-based TCP/IP code have a bug with respect to creating TCP
> connections to a broadcast address. This bug can potentially be a
> security vulnerability when firewall administrators assume that the
> TCP implementation works correctly and does not block broadcast
> addresses.
> 
> 
> The Standard:
> 
> TCP connections are only valid when the destination address is a
> unicast address. That is, the destination must not be a multicast or
> broadcast address. One place this is clearly specified in the
> Standards is RFC 1122 (everyone's very most favorite RFC),
> 
>          4.2.3.10  Remote Address Validation
> 
>          ...
> 
>             A TCP implementation MUST silently discard an incoming SYN
>             segment that is addressed to a broadcast or multicast
>             address.
> 
> 
> The Bug:
> 
> Uncorrected BSD-based TCP implementations do not actually check if the
> destination IP address is a broadcast address. Rather, the packet's
> link layer address is checked. Here is the code from FreeBSD's
> tcp_input.c,
> 
>                  * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
>                  * in_broadcast() should never return true on a received
>                  * packet with M_BCAST not set.
>                  *
>                  * Packets with a multicast source address should also
>                  * be discarded.
>                  */
>                 if (m->m_flags & (M_BCAST|M_MCAST))
>                         goto drop;
> #ifdef INET6
>                 if (isipv6) {
>                         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
>                             IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
>                                 goto drop;
>                 } else
> #endif
>                 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
>                     IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
>                     ip->ip_src.s_addr == htonl(INADDR_BROADCAST))
>                         goto drop;
> 
> The comment in the code reveals the reason for the mistake. The
> authors assume that no one would accidentally or maliciously break the
> rules. One can easily send packets with a unicast link-layer address,
> but containing an IP broadcast address. No check is made in the above
> code for such a pathological situation.
> 
Nice catch!

> Adding an in_broadcast() check trivially fixes the problem. Here is a
> patch (which fixes the comment too),
> 
> Index: src/sys/netinet/tcp_input.c
> ===================================================================
> RCS file: /export/ncvs/src/sys/netinet/tcp_input.c,v
> retrieving revision 1.146
> diff -u -r1.146 tcp_input.c
> --- src/sys/netinet/tcp_input.c	4 Jan 2002 17:21:27 -0000	1.146
> +++ src/sys/netinet/tcp_input.c	17 Feb 2002 12:54:39 -0000
> @@ -798,11 +798,10 @@
>  		}
>  		/*
>  		 * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
> -		 * in_broadcast() should never return true on a received
> -		 * packet with M_BCAST not set.
> - 		 *
> - 		 * Packets with a multicast source address should also
> - 		 * be discarded.
> +		 *
> +		 * It is possible for a malicious (or misconfigured)
> +		 * attacker to send unicast link-layer packets with a
> +		 * broadcast IP address. Use in_broadcast() to find them.
>  		 */
>  		if (m->m_flags & (M_BCAST|M_MCAST))
>  			goto drop;
> @@ -815,7 +814,8 @@
>  #endif
>  		if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
>  		    IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
> -		    ip->ip_src.s_addr == htonl(INADDR_BROADCAST))
> +		    ip->ip_src.s_addr == htonl(INADDR_BROADCAST) ||
> +		    in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
>  			goto drop;
>  		/*
>  		 * SYN appears to be valid; create compressed TCP state
> 
The patch is incomplete (see dropwithreset below).  Here's the tcp_input.c
part of the original delta that introduced this bug:

: Script started on Sat Feb 23 13:37:18 2002
: $ sccs prs -r7.35 tcp_input.c
: D 7.35 93/04/07 19:28:08 sklower 159 158	00007/00003/01623
: MRs:
: COMMENTS:
: Mostly changes recommended by jch for variable subnets & multiple
: IP addresses per physical interface. May require further work.
: 
: $ sccs sccsdiff -up -r7.34 -r7.35 tcp_input.c
: SCCS/s.tcp_input.c: 7.34 vs. 7.35
: --- /tmp/get.19874.7.34	Sat Feb 23 13:37:41 2002
: +++ /tmp/get.19874.7.35	Sat Feb 23 13:37:41 2002
: @@ -518,9 +518,13 @@ findpcb:
:  			goto dropwithreset;
:  		if ((tiflags & TH_SYN) == 0)
:  			goto drop;
: -		/* RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN */
: +		/*
: +		 * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
: +		 * in_broadcast() should never return true on a received
: +		 * packet with M_BCAST not set.
: +		 */
:  		if (m->m_flags & (M_BCAST|M_MCAST) ||
: -		    in_broadcast(ti->ti_dst) || IN_MULTICAST(ti->ti_dst.s_addr))
: +		    IN_MULTICAST(ti->ti_dst.s_addr))
:  			goto drop;
:  		am = m_get(M_DONTWAIT, MT_SONAME);	/* XXX */
:  		if (am == NULL)
: @@ -1271,7 +1275,7 @@ dropwithreset:
:  	 * Don't bother to respond if destination was broadcast/multicast.
:  	 */
:  	if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) ||
: -	    in_broadcast(ti->ti_dst) || IN_MULTICAST(ti->ti_dst.s_addr))
: +	    IN_MULTICAST(ti->ti_dst.s_addr))
:  		goto drop;
:  	if (tiflags & TH_ACK)
:  		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
: $ 
: Script done on Sat Feb 23 13:37:43 2002

I think you should just back the CSRG revision 7.35 out of tcp_input.c,
mentioning what was wrong with removing in_broadcast() check.

route add -net 192.168.4 192.168.1.1
ping 192.168.4.255

on a directly attached 192.168.1 network isn't a "malicious use".


Cheers,
-- 
Ruslan Ermilov		Sysadmin and DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




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