Mitigate the stream.c attacks

o Drop all broadcast and multicast source addresses in tcp_input.
o Enable ICMP_BANDLIM in GENERIC.
o Change default to 200/s from 100/s.  This will still stop the attack, but
  is conservative enough to do this close to code freeze.

This is not the optimal patch for the problem, but is likely the least
intrusive patch that can be made for this.

Obtained from: Don Lewis and Matt Dillon.
Reviewed by: freebsd-security
This commit is contained in:
imp 2000-01-28 06:13:09 +00:00
parent f8e48f511e
commit 9d11326d86
7 changed files with 69 additions and 33 deletions

View File

@ -59,6 +59,7 @@ options KTRACE #ktrace(1) syscall trace support
options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options ICMP_BANDLIM # Rate limit bad replies
# Standard busses
device isa

View File

@ -59,6 +59,7 @@ options KTRACE #ktrace(1) syscall trace support
options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options ICMP_BANDLIM # Rate limit bad replies
# Standard busses
device isa

View File

@ -51,6 +51,7 @@ options SYSVSEM #SYSV-style semaphores
options P1003_1B #Posix P1003_1B real-time extentions
options _KPOSIX_PRIORITY_SCHEDULING
options _KPOSIX_VERSION=199309L
options ICMP_BANDLIM # Rate limit bad replies
# To make an SMP kernel, the next two are needed
#options SMP # Symmetric MultiProcessor Kernel

View File

@ -51,6 +51,7 @@ options SYSVSEM #SYSV-style semaphores
options P1003_1B #Posix P1003_1B real-time extentions
options _KPOSIX_PRIORITY_SCHEDULING
options _KPOSIX_VERSION=199309L
options ICMP_BANDLIM # Rate limit bad replies
# To make an SMP kernel, the next two are needed
#options SMP # Symmetric MultiProcessor Kernel

View File

@ -96,7 +96,7 @@ SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW,
* variable content is -1 and read-only.
*/
static int icmplim = 100;
static int icmplim = 200;
SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
&icmplim, 0, "");
#else

View File

@ -615,10 +615,6 @@ tcp_input(m, off0, proto)
break;
}
}
#ifdef ICMP_BANDLIM
if (badport_bandlim(1) < 0)
goto drop;
#endif
if (blackhole) {
switch (blackhole) {
case 1:
@ -631,11 +627,11 @@ tcp_input(m, off0, proto)
goto drop;
}
}
goto dropwithreset;
goto maybedropwithreset;
}
tp = intotcpcb(inp);
if (tp == 0)
goto dropwithreset;
goto maybedropwithreset;
if (tp->t_state == TCPS_CLOSED)
goto drop;
@ -695,7 +691,7 @@ tcp_input(m, off0, proto)
*/
if (thflags & TH_ACK) {
tcpstat.tcps_badsyn++;
goto dropwithreset;
goto maybedropwithreset;
}
goto drop;
}
@ -772,7 +768,7 @@ tcp_input(m, off0, proto)
*/
if (thflags & TH_ACK) {
tcpstat.tcps_badsyn++;
goto dropwithreset;
goto maybedropwithreset;
}
goto drop;
}
@ -999,7 +995,7 @@ tcp_input(m, off0, proto)
if (thflags & TH_RST)
goto drop;
if (thflags & TH_ACK)
goto dropwithreset;
goto maybedropwithreset;
if ((thflags & TH_SYN) == 0)
goto drop;
if (th->th_dport == th->th_sport) {
@ -1017,16 +1013,22 @@ tcp_input(m, off0, proto)
* 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))
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)))
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;
#ifdef INET6
if (isipv6) {
@ -1187,7 +1189,7 @@ tcp_input(m, off0, proto)
if ((thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max)))
goto dropwithreset;
goto maybedropwithreset;
break;
/*
@ -1529,7 +1531,7 @@ tcp_input(m, off0, proto)
* for the "LAND" DoS attack.
*/
if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs))
goto dropwithreset;
goto maybedropwithreset;
todrop = tp->rcv_nxt - th->th_seq;
if (todrop > 0) {
@ -2192,7 +2194,7 @@ tcp_input(m, off0, proto)
if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) &&
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max)) )
goto dropwithreset;
goto maybedropwithreset;
#ifdef TCPDEBUG
if (so->so_options & SO_DEBUG)
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
@ -2203,6 +2205,17 @@ tcp_input(m, off0, proto)
(void) tcp_output(tp);
return;
/*
* Conditionally drop with reset or just drop depending on whether
* we think we are under attack or not.
*/
maybedropwithreset:
#ifdef ICMP_BANDLIM
if (badport_bandlim(1) < 0)
goto drop;
#endif
/* fall through */
dropwithreset:
#ifdef TCP_RESTRICT_RST
if (restrict_rst)
@ -2217,11 +2230,14 @@ tcp_input(m, off0, proto)
goto drop;
#ifdef INET6
if (isipv6) {
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
goto drop;
} else
#endif /* INET6 */
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)))
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;
/* IPv6 anycast check is done at tcp6_input() */
#ifdef TCPDEBUG

View File

@ -615,10 +615,6 @@ tcp_input(m, off0, proto)
break;
}
}
#ifdef ICMP_BANDLIM
if (badport_bandlim(1) < 0)
goto drop;
#endif
if (blackhole) {
switch (blackhole) {
case 1:
@ -631,11 +627,11 @@ tcp_input(m, off0, proto)
goto drop;
}
}
goto dropwithreset;
goto maybedropwithreset;
}
tp = intotcpcb(inp);
if (tp == 0)
goto dropwithreset;
goto maybedropwithreset;
if (tp->t_state == TCPS_CLOSED)
goto drop;
@ -695,7 +691,7 @@ tcp_input(m, off0, proto)
*/
if (thflags & TH_ACK) {
tcpstat.tcps_badsyn++;
goto dropwithreset;
goto maybedropwithreset;
}
goto drop;
}
@ -772,7 +768,7 @@ tcp_input(m, off0, proto)
*/
if (thflags & TH_ACK) {
tcpstat.tcps_badsyn++;
goto dropwithreset;
goto maybedropwithreset;
}
goto drop;
}
@ -999,7 +995,7 @@ tcp_input(m, off0, proto)
if (thflags & TH_RST)
goto drop;
if (thflags & TH_ACK)
goto dropwithreset;
goto maybedropwithreset;
if ((thflags & TH_SYN) == 0)
goto drop;
if (th->th_dport == th->th_sport) {
@ -1017,16 +1013,22 @@ tcp_input(m, off0, proto)
* 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))
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)))
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;
#ifdef INET6
if (isipv6) {
@ -1187,7 +1189,7 @@ tcp_input(m, off0, proto)
if ((thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max)))
goto dropwithreset;
goto maybedropwithreset;
break;
/*
@ -1529,7 +1531,7 @@ tcp_input(m, off0, proto)
* for the "LAND" DoS attack.
*/
if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs))
goto dropwithreset;
goto maybedropwithreset;
todrop = tp->rcv_nxt - th->th_seq;
if (todrop > 0) {
@ -2192,7 +2194,7 @@ tcp_input(m, off0, proto)
if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) &&
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max)) )
goto dropwithreset;
goto maybedropwithreset;
#ifdef TCPDEBUG
if (so->so_options & SO_DEBUG)
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
@ -2203,6 +2205,17 @@ tcp_input(m, off0, proto)
(void) tcp_output(tp);
return;
/*
* Conditionally drop with reset or just drop depending on whether
* we think we are under attack or not.
*/
maybedropwithreset:
#ifdef ICMP_BANDLIM
if (badport_bandlim(1) < 0)
goto drop;
#endif
/* fall through */
dropwithreset:
#ifdef TCP_RESTRICT_RST
if (restrict_rst)
@ -2217,11 +2230,14 @@ tcp_input(m, off0, proto)
goto drop;
#ifdef INET6
if (isipv6) {
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
goto drop;
} else
#endif /* INET6 */
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)))
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;
/* IPv6 anycast check is done at tcp6_input() */
#ifdef TCPDEBUG