Prevent idnsVCClosed segfaults during shutdown or reconfiguration.
idnsShutdown() schedules comm_close and then frees nameservers[] by
calling idnsFreeNameservers. The closing handler tried to access freed
nameservers[]. The patch prevents access to the freed nameservers[]
array in idnsVCClosed and other functions.
TODO: Nameservers[] array management should be rewritten. The array
should not be freed while there are nameservers using it. It should be
freed when the last entry is gone.
The segfault was observed in Squid v3.1-based code:
> Program terminated with signal 6, Aborted.
> #0 0x0000003258230155 in raise () from /lib64/libc.so.6
> (gdb) where
> #0 0x0000003258230155 in raise () from /lib64/libc.so.6
> #1 0x0000003258231bf0 in abort () from /lib64/libc.so.6
> #2 0x00000000004f8838 in death (sig=11) at tools.cc:390
> #3 <signal handler called>
> #4 0x0000000000459d8b in idnsVCClosed (fd=1179, data=0x19c03958) at
> dns_internal.cc:724
> #5 0x00000000005159e9 in CommCloseCbPtrFun::dial (this=0x1b426870) at
> CommCalls.cc:207
> #6 0x0000000000513e05 in CommCbFunPtrCallT<CommCloseCbPtrFun>::fire
> (this=0x1b426840) at CommCalls.h:329
> #7 0x00000000005065c2 in AsyncCall::make (this=0x1b426840) at AsyncCall.cc:34
> #8 0x00000000005094d5 in AsyncCallQueue::fireNext (this=0x19277370) at
> AsyncCallQueue.cc:53
> #9 0x00000000005095ab in AsyncCallQueue::fire (this=0x19277370) at
> AsyncCallQueue.cc:39
> #10 0x00000000004622fd in EventLoop::dispatchCalls (this=0x7fffc82d92e0) at
> EventLoop.cc:154
> #11 0x000000000046254e in EventLoop::runOnce (this=0x7fffc82d92e0) at
> EventLoop.cc:119
> #12 0x0000000000462692 in EventLoop::run (this=0x7fffc82d92e0) at
> EventLoop.cc:95
> #13 0x00000000004b3e9c in SquidMain (argc=1, argv=0x7fffc82d94d8) at
> main.cc:1385
> #14 0x00000000004b3fc8 in SquidMainSafe (argc=1, argv=0x7fffc82d94d8) at
> main.cc:1146
> #15 0x00000000004b40e9 in main (argc=1, argv=0x7fffc82d94d8) at main.cc:1139
Alex.
Prevent idnsVCClosed segfaults during shutdown or reconfiguration.
idnsShutdown() schedules comm_close and then frees nameservers[] by calling
idnsFreeNameservers. The closing handler tried to access freed nameservers[].
The patch prevents access to the freed nameservers[] array in idnsVCClosed and
other functions.
TODO: Nameservers[] array management should be rewritten. The array should not
be freed while there are nameservers using it. It should be freed when the
last entry is gone.
=== modified file 'src/dns_internal.cc'
--- src/dns_internal.cc 2009-12-14 18:53:50 +0000
+++ src/dns_internal.cc 2010-01-08 17:46:12 +0000
@@ -699,13 +699,15 @@
}
static void
-idnsInitVCConnected(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data)
+idnsInitVCConnected(int fd, const DnsLookupDetails &details, comm_err_t status, int xerrno, void *data)
{
nsvc * vc = (nsvc *)data;
if (status != COMM_OK) {
- char buf[MAX_IPSTRLEN];
- debugs(78, 1, "idnsInitVCConnected: Failed to connect to nameserver " << nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN) << " using TCP!");
+ char buf[MAX_IPSTRLEN] = "";
+ if (vc->ns < nns)
+ nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN);
+ debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP: " << details);
comm_close(fd);
return;
}
@@ -721,7 +723,8 @@
nsvc * vc = (nsvc *)data;
delete vc->queue;
delete vc->msg;
- nameservers[vc->ns].vc = NULL;
+ if (vc->ns < nns) // XXX: idnsShutdown may have freed nameservers[]
+ nameservers[vc->ns].vc = NULL;
cbdataFree(vc);
}
@@ -731,6 +734,7 @@
char buf[MAX_IPSTRLEN];
nsvc *vc = cbdataAlloc(nsvc);
+ assert(ns < nns);
nameservers[ns].vc = vc;
vc->ns = ns;
@@ -764,6 +768,7 @@
static void
idnsSendQueryVC(idns_query * q, int ns)
{
+ assert(ns < nns);
if (nameservers[ns].vc == NULL)
idnsInitVC(ns);
@@ -1254,6 +1259,7 @@
return;
}
+ assert(vc->ns < nns);
debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
(int) vc->msg->contentSize() << " bytes via tcp from " <<
nameservers[vc->ns].S << ".");
@@ -1410,6 +1416,7 @@
}
}
+ // XXX: vcs are not closed/freed yet and may try to access nameservers[]
idnsFreeNameservers();
idnsFreeSearchpath();