Subject: | SECURITY: Net::DNS::Nameserver - Race Condition - TCP DoS Vulnerability |
Date: | Wed, 19 Oct 2011 17:55:15 -0600 |
To: | bug-Net-DNS [...] rt.cpan.org |
From: | Rob Brown <bbb [...] cpan.org> |
My Net::DNS::Nameserver process has been sporadically locking up so
many times over the past few months. The whole server freezes and
refuses to respond, no matter how many UDP queries come in. But I
found that manually issuing a few TCP queries will wake up the server
and it will begin responding to UDP queries again. But since TCP
queries are extremely rare, the effect is permanent silence!
I will not release any exploit code for this vulnerability at this
time, but here is a patch that actually fixes the problem:
--- /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi/Net/DNS/Nameserver.pm.DoS
2011-10-07 10:01:44.000000000 -0600
+++ /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi/Net/DNS/Nameserver.pm.3
2011-10-19 16:52:13.000000000 -0600
@@ -87,6 +87,7 @@
Listen => 64,
Proto => "tcp",
Reuse => 1,
+ Blocking => 0,
);
if ( $sock_tcp ) {
push @sock_tcp, $sock_tcp;
This solution is safe because the tcp_connection code already handles
the "undef" case gracefully:
my $client = $sock->accept;
if (not defined $client) {
print "TCP connection closed by peer before we
could accept it.\n" if $self->{"Verbose"};
return 0;
}
This is also safe because a server socket that misses the instant
accept() but that somehow very soon afterwards suddenly becomes truly
ready to be accept()ed will show up in the readable bits for select()
and can_read will instantly pick it up on the very next loop.
For example, here is a real live process that quit responding several hours ago:
root 582 1.7 0.0 40972 7576 ? S Oct18 30:36 \_ /usr/bin/perl /bin/park_dns
And here is the strace of what it is choking on:
# strace -tt -s1000 -p 582
Process 582 attached - interrupt to quit
14:53:43.564041 accept(18,
Simply using telnet or netcat to port 53 on the IP of that file
descriptor and closing the connection, immediately frees up the
server, and the strace immediately scrolls by with much more useful
processing.
The reason this is a problem is because select() or
IO::Select->can_read can sometimes yield a listen socket that hasn't
completed the full TCP 3-way hand shake due to the SOMAXCONN being
reached or packet loss or various kernel conditions.
I know you are trying to release a new version of Net::DNS soon, but I
hope this fix can be included.
-- Rob