Bugzilla – Bug 961721
VUL-0: CVE-2015-7547: glibc getaddrinfo stack-based buffer overflow
Last modified: 2017-10-24 18:07:05 UTC
Summary ======= During upstream review of the public open bug 18665 for glibc, it was discovered that the bug could lead to a stack-based buffer overlow. https://sourceware.org/bugzilla/show_bug.cgi?id=18665 The buffer overflow occurs in the function send_dg (UDP) and send_vc (TCP) for the NSS module libnss_dns.so.2 when calling getaddrinfo with AF_UNSPEC family. The use of AF_UNSPEC triggers the low-level resolver code to send out two parallel queries for A and AAAA. A mismanagement of the buffers used for those queries could result in the response of a query writing beyond the alloca allocated buffer created by __res_nquery. Main conclusions: - Via getaddrinfo with family AF_UNSPEC the overflowed buffer is located on the stack via alloca (a 2048 byte fixed size buffer for DNS responses). - At most 65535 bytes (MAX_PACKET) may be written to the alloca buffer of 2048 bytes. Overflowing bytes are entirely under the control of the attacker and are the result of a crafted DNS response. - Local testing shows that we have been able to control at least the execution of one free() call with the buffer overflow and gained control of EIP. Further exploitation was not attempted, only this single attempt to show that it is very likely that execution control can be gained without much more effort. We know of no known attacks that use this specific vulnerability. - Mitigating factors for UDP include: - A firewall that drops UDP DNS packets > 512 bytes. - A local validating resolver. - No IPv6 AAAA queries (avoids buffer management error). e.g. Do not use AF_UNSPEC. - No use of `options edns0` in /etc/resolv.conf since EDNS0 allows responses larger than 512 bytes and can lead to valid DNS responses that overflow. - No use of `RES_USE_EDNS0` or `RES_USE_DNSSEC` since they can both lead to valid large EDNS0-based DNS responses that can overflow. - Mitigating factors for TCP include: - Nothing. - Mitigations that don't work: - Setting `options single-request` does not change buffer management and does not prevent the exploit. - Setting `options single-request-reopen` does not change buffer management and does not prevent the exploit. - Disabling IPv6 does not disable AAAA queries. The use of AF_UNSPEC unconditionally enables the dual query. - The use of `sysctl -w net.ipv6.conf.all.disable_ipv6=1` will not protect your system from the exploit. - The code is only present in glibc's copy of libresolv which has enhancements to carry out parallel A and AAAA queries. A quick review shows Fedora 10 with bind-9.5.2 was the last bind in Fedora to have common code in lib/bind/reolv/res_send.c, but the bind implementation is much simpler and does not suffer from the buffer overflow. Therefore only programs using glibc's copy of the code have this problem. The code in question was introduced in May 2008 as part of glibc 2.9, which means it is present in RHEL6, and RHEL7 but not RHEL5 (verified not present in RHEL5, and verified present in RHEL6 and RHEL7). High-level Analysis: ==================== The defect is located in the glibc package in the following file: - resolv/res_send.c as part of the send_dg and send_vc functions which are part of the __libc_res_nsend (res_nsend) interface which is used by many of the higher level interfaces including getaddrinfo indirectly via the DNS NSS module. The easiest way to trigger the buffer mismanagement is like this: * Have the target attempt a DNS resolution for a domain you control. - Need to get A and AAAA queries. * First response is 2048 bytes. - Fills the alloca buffer entirely with 0 left over. - send_dg attemps to reuse the user buffer but can't. - New buffer created but due to bug old alloca buffer is used with new size of 65535. - Response should be valid. * Send second response. - This response should be flawed in such a way that it forces __libc_res_nsend to retry the query. It is sufficient for example to pick any of the listed failure modes in the code which return 0 as a way to create a malformed response. * Send third response. - The third response can contain 2048 bytes of valid response. - The remaining 63487 bytes of the response are the attack payload and the recvfrom smashes the stack with it. The real work required is to craft a payload that won't crash the target, but control one function, like our example free() where the stack contents allow control flow modification. Please note that there are other ways to trigger the buffer management flaw, but they require slightly more control over the timing of the responses and use poll timeout to carry out the exploit with just two responses from the attacker (as opposed to three). A similar exploit is possible with TCP, but requires resetting the TCP connection to force send_vc to exit and be retried with the wrong buffer size, similar to the send_dg failure. Detailed Analysis: ================== >From getaddrinfo we call into the NSS DNS module. First in resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname4_r): 307 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ... 315 int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC, 316 host_buffer.buf->buf, 2048, &host_buffer.ptr, 317 &ans2p, &nans2p, &resplen2, &ans2p_malloced); We have the alloca which is the root cause of the stack smash. Then in resolv/res_send.c (send_dg): We are in POLLIN reading the server response to our request: 1151 } else if (pfd[0].revents & POLLIN) { 1152 int *thisanssizp; 1153 u_char **thisansp; 1154 int *thisresplenp; 1155 1156 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { 1157 thisanssizp = anssizp; 1158 thisansp = anscp ?: ansp; 1159 assert (anscp != NULL || ansp2 == NULL); 1160 thisresplenp = &resplen; Neither reply is received yet so thisanssizp is anssizp e.g. 2048, matching the user supplied buffer (from _nss_dns_gethostbyname4_r). 1189 if (*thisanssizp < MAXPACKET 1190 /* Yes, we test ANSCP here. If we have two buffers 1191 both will be allocatable. */ 1192 && anscp 1193 #ifdef FIONREAD 1194 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 1195 || *thisanssizp < *thisresplenp) 1196 #endif The buffer is sufficient and `thisresplenp` is 2048 and that fits in the user buffer. 1357 /* Mark which reply we received. */ 1358 if (recvresp1 == 0 && hp->id == anhp->id) 1359 recvresp1 = 1; We mark the first response as received, and go back to `wait:` 1362 /* Repeat waiting if we have a second answer to arrive. */ 1363 if ((recvresp1 & recvresp2) == 0) { ... 1374 goto wait; This time around though we have already received one reply, and buf2 is non-NULL so we trigger this: 1162 if (*anssizp != MAXPACKET) { 1163 /* No buffer allocated for the first 1164 reply. We can try to use the rest 1165 of the user-provided buffer. */ 1166 #if _STRING_ARCH_unaligned 1167 *anssizp2 = orig_anssizp - resplen; 1168 *ansp2 = *ansp + resplen; The use of MAXPACKET is a value/boolean-style check. The send_dg internal logic uses a value of *anssizp of MAXPACKET to indicate an internal buffer was allocated for the response. It does not contemplate a user might pass in a buffer that big, but let us ignore that for now. The above code, noting it has not allocated an malloc'd buffer, attempts to use the remainder of the user buffer to store the second response to avoid malloc. However, the user buffer of 2048 was fully used by the 2048 response, and the value of `orig_anssizp - resplen` is zero, so `*anssizp2` is zero. None of this is important really, but it sets the stage for the next failures. 1169 #else ... 1184 thisanssizp = anssizp2; 1185 thisansp = ansp2; 1186 thisresplenp = resplen2; Then `thisansp` points also just beyond the stack, but because the size is zero we'll never use this pointer. 1189 if (*thisanssizp < MAXPACKET 1190 /* Yes, we test ANSCP here. If we have two buffers 1191 both will be allocatable. */ 1192 && anscp 1193 #ifdef FIONREAD 1194 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 1195 || *thisanssizp < *thisresplenp) This is all true. We are reusing the user buffer so it's size is less than MAXPACKET, yes we have `anscp` non-NULL pointer (allowed to modify callers storage pointers), and the ioctl shows we have 10000 bytes arriving. 1196 #endif 1197 ) { 1198 u_char *newp = malloc (MAXPACKET); 1199 if (newp != NULL) { 1200 *anssizp = MAXPACKET; 1201 *thisansp = ans = newp; 1202 if (thisansp == ansp2) 1203 *ansp2_malloced = 1; 1204 } 1205 } So we allocate a new buffer, set *anssizp to MAXPACKET, but fail to set *ansp to the new buffer, and fail to update *thisanssizp to the new size. 1209 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp, 1210 *thisanssizp, 0, 1211 (struct sockaddr *)&from, &fromlen); Then in recvfrom we read zero bytes because *thisanssizp is zero. Which means we error out: 1212 if (__glibc_unlikely (*thisresplenp <= 0)) { ... 1218 goto err_out; However, we return to __libc_res_nsend, and we have manipulated the callers state (they are all pointers-to-pointers) incorrectly. Firstly: 1167 *anssizp2 = orig_anssizp - resplen; ... this sets the size of answer buffer #2 to 0. 1185 thisansp = ansp2; ... 1201 *thisansp = ans = newp; ... but then we set the answer buffer #2 pointer to the malloced block. So now in __libc_res_nsend the second answer buffer has size 0, but is malloced and points to a valid block of MAXPACKET bytes of memory. Secondly: 1200 *anssizp = MAXPACKET; ... this sets the size of the answer buffer #1 to MAXPACKET bytes, but does nothing else to change *ansp to the new malloc'd buffer. So now in __libc_res_nsend the first answer buffer has size MAXPACKET, but is still the same alloca'd 2048 byte space. The send_dg function exits, and we loop in __libc_res_nsend looking for an answer with the next resolver. The buffers are reused and send_dg is called again and this time it results in `MAXPACKET - 2048` bytes being overflowed from the response directly onto the stack. Playing with the attack buffer slightly and the timing gives another way to trigger the stack smash. Set the response buffer to 2049 or larger to trigger malloc buffer reallocation right away. 1182 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { 1183 thisanssizp = anssizp; 1184 thisansp = anscp ?: ansp; 1185 assert (anscp != NULL || ansp2 == NULL); 1186 thisresplenp = &resplen; this executes and we assign `thisansp` to `anscp` which is a pointer that is non-null if the caller intends to allow us to change the allocation of the answer buffer. At this point the astute reader realizes that: In __libc_res_nsend the variable `&ans` has distinct storage from `ansp`, but that `ans` and `*ansp` point to the same location. The res_nquery caller intends this because they want the underlying res_nsend to be able to change the buffer if the size is insufficient. Then we go on to allocate the new buffer: 1224 u_char *newp = malloc (MAXPACKET); 1225 if (newp != NULL) { 1226 *thisanssizp = MAXPACKET; 1227 *thisansp = ans = newp; 1228 if (thisansp == ansp2) 1229 *ansp2_malloced = 1; We update `ans` (our cached copy of `ansp` or `&ans` in res_nsend), and we update `*thisansp` which is `anscp` (`ansp` in res_nsend), but nowhere do we update `ansp` which means that in res_nsend the two pointers `&ans` and `ansp` point to two different buffers, but only have one size `*anssizp` which is now MAXPACKET, but the original `ansp` is still pointing at the 2048 alloca buffer. Everything is OK for now since this works: 1235 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp, 1236 *thisanssizp, 0, 1237 (struct sockaddr *)&from, &fromlen); We point at the new buffer, and read the new length at most. But if you delay the application enough to timeout the retry loop (perhaps load induced in real life) and that causes us to exit send_dg with 0 to indicate we should retry. When we restart send_dg, we now have `&ans` pointing at the 2048 alloca buffer but `&anssiz` is MAXPACKET now and doesn't match. This is OK for the first answer because: 1184 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { 1185 thisanssizp = anssizp; 1186 thisansp = anscp ?: ansp; 1187 assert (anscp != NULL || ansp2 == NULL); 1188 thisresplenp = &resplen; ... this again selects anscp (malloc'd storage) over ansp (alloca). However, if we are quick this time and don't timeout, we flip over to trying to make the second query and setup an ansp2 buffer: 1204 } else { 1205 /* The first reply did not fit into the 1206 user-provided buffer. Maybe the second 1207 answer will. */ 1208 *anssizp2 = orig_anssizp; 1209 *ansp2 = *ansp; 1210 } Here we assign ansp2 to ansp (alloca) with an orig_anssizp size which is wrong (MAXPACKET). The next time we do a recvfrom we will smash the stack again. The same problems exist in send_vc. Prototype patch to fix glibc master attached (lots of comments). Prototype self-contained test cases attached for UDP and TCP. These are rough and would need more cleanup for inclusion in glibc. Cheers, Carlos. P.S. The test cases showed 2 uninitialized uses in getaddrinfo under valgrind: ==4917== Conditional jump or move depends on uninitialised value(s) ==4917== at 0x512674E: gaih_inet (getaddrinfo.c:870) ==4917== by 0x512866D: getaddrinfo (getaddrinfo.c:2417) ==4917== by 0x400D0B: main (bug18665.c:166) ==4917== Uninitialised value was created by a stack allocation ==4917== at 0x5125850: gaih_inet (getaddrinfo.c:275) ==4917== ==4917== Conditional jump or move depends on uninitialised value(s) ==4917== at 0x5126584: gaih_inet (getaddrinfo.c:1079) ==4917== by 0x512866D: getaddrinfo (getaddrinfo.c:2417) ==4917== by 0x400D0B: main (bug18665.c:166) ==4917== Uninitialised value was created by a stack allocation ==4917== at 0x5125850: gaih_inet (getaddrinfo.c:275) Which are caused by failure to set *h_errnop in resolv/nss_dns/dns-host.c (gaih_getanswer_slice) which results in gaih_inet jump/move depends on uninitialized value here: 862 status = DL_CALL_FCT (fct4, (name, pat, tmpbuf, 863 tmpbuflen, &rc, &herrno, 864 NULL)); 865 if (status == NSS_STATUS_SUCCESS) 866 break; 867 if (status != NSS_STATUS_TRYAGAIN 868 || rc != ERANGE || herrno != NETDB_INTERNAL) 869 { 870 if (herrno == TRY_AGAIN) ^^^^^^ 871 no_data = EAI_AGAIN; 872 else 873 no_data = herrno == NO_DATA; 874 break; All paths through _nss_dns_gethostbyname4_r and called functions must correctly set *h_errnop or we have an uninitialized use of the stack allocated herrno variable. Fix attached as valgrind-uninit.patch. P.P.S Analysis by Florian indicates also that send_vc suffers from a potential TCP issue. The function sends both A and AAAA queries back-to-back on the same socket and this could result in failure to get any response back from the server. The scenarios is as follows: server receives query, server reads query header and determines query length, server reads full query length, server responds to query and closes socket. The server closing the socket is an implementation detail that is allowed by the server and may be done to switch to another client. The consequence of closing the socket with data still pending (the AAAA query) will result in an RST being sent to the client. That RST is unordered and when it arrives at the client kernel will cause an asynchronous teardown of the entire socket and buffers. Any unread data by the client is lost and the client may see less than the full response (it might see no response). This issue is orthogonal to what we're dealing with, but it should be mentioned because in the event it impacts your analysis.
Created attachment 661635 [details] Patch for getaddrinfo stack-based buffer overflow
CRD: unknown
bugbot adjusting priority
Created attachment 661760 [details] Patch for getaddrinfo stack-based buffer overflow
CRD: 2016-02-08
Created attachment 662028 [details] Patch for getaddrinfo stack-based buffer overflow
Created attachment 664035 [details] Tests from Florian Weimer
Public now.
Crasher PoC: https://github.com/fjserna/CVE-2015-7547
Andreas, we would now like to process the openSUSE submission.
SUSE-SU-2016:0470-1: An update that solves 10 vulnerabilities and has four fixes is now available. Category: security (important) Bug References: 830257,847227,863499,892065,918187,920338,927080,945779,950944,961721,962736,962737,962738,962739 CVE References: CVE-2013-2207,CVE-2013-4458,CVE-2014-8121,CVE-2014-9761,CVE-2015-1781,CVE-2015-7547,CVE-2015-8776,CVE-2015-8777,CVE-2015-8778,CVE-2015-8779 Sources used: SUSE Linux Enterprise Server 11-SP2-LTSS (src): glibc-2.11.3-17.45.66.1 SUSE Linux Enterprise Debuginfo 11-SP2 (src): glibc-2.11.3-17.45.66.1
SUSE-SU-2016:0471-1: An update that solves 6 vulnerabilities and has three fixes is now available. Category: security (important) Bug References: 950944,955647,956716,958315,961721,962736,962737,962738,962739 CVE References: CVE-2014-9761,CVE-2015-7547,CVE-2015-8776,CVE-2015-8777,CVE-2015-8778,CVE-2015-8779 Sources used: SUSE Linux Enterprise Software Development Kit 12-SP1 (src): glibc-2.19-35.1 SUSE Linux Enterprise Server 12-SP1 (src): glibc-2.19-35.1 SUSE Linux Enterprise Desktop 12-SP1 (src): glibc-2.19-35.1
SUSE-SU-2016:0472-1: An update that solves 6 vulnerabilities and has three fixes is now available. Category: security (important) Bug References: 930721,942317,950944,956988,961721,962736,962737,962738,962739 CVE References: CVE-2014-9761,CVE-2015-7547,CVE-2015-8776,CVE-2015-8777,CVE-2015-8778,CVE-2015-8779 Sources used: SUSE Linux Enterprise Software Development Kit 11-SP4 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Software Development Kit 11-SP3 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Server for VMWare 11-SP3 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Server 11-SP4 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Server 11-SP3 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Desktop 11-SP4 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Desktop 11-SP3 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Debuginfo 11-SP4 (src): glibc-2.11.3-17.95.2 SUSE Linux Enterprise Debuginfo 11-SP3 (src): glibc-2.11.3-17.95.2
SUSE-SU-2016:0473-1: An update that solves 6 vulnerabilities and has three fixes is now available. Category: security (important) Bug References: 950944,955647,956716,958315,961721,962736,962737,962738,962739 CVE References: CVE-2014-9761,CVE-2015-7547,CVE-2015-8776,CVE-2015-8777,CVE-2015-8778,CVE-2015-8779 Sources used: SUSE Linux Enterprise Software Development Kit 12 (src): glibc-2.19-22.13.1 SUSE Linux Enterprise Server 12 (src): glibc-2.19-22.13.1 SUSE Linux Enterprise Desktop 12 (src): glibc-2.19-22.13.1
Another question. I can see that patches for SLES/D 11 SP3 have been released but it does not say LTSS. But both products are only available in LTSS now. Or has this patch been released to the regular Updates channel?
This update was started before the LTSS of 11-SP3, so it was still released into the regular SP3 channels. So it was "late", but only 1 or 2 more will be coming there.
As per Michal Koutny I have requested the SLES 11 SP1 Mass-PTF on internal Bug#967023. L3 has been created there.
Also, TID has been created here: https://www.suse.com/support/kb/doc.php?id=7017265 ^^ It is marked as INTERNAL for now until I get a go either here or on the HIV Mailinglist.
openSUSE-SU-2016:0490-1: An update that solves 6 vulnerabilities and has three fixes is now available. Category: security (important) Bug References: 950944,955647,956716,958315,961721,962736,962737,962738,962739 CVE References: CVE-2014-9761,CVE-2015-7547,CVE-2015-8776,CVE-2015-8777,CVE-2015-8778,CVE-2015-8779 Sources used: openSUSE Leap 42.1 (src): glibc-2.19-19.1, glibc-testsuite-2.19-19.2, glibc-utils-2.19-19.1
Please note that SLES 10 all service packs have an older version of glibc which is NOT affected.
Do we have an update for rhel expanded support planned ?
any ETA for tumbleweed? or even the older opensuse releases still receiving updates?
(In reply to Matthias Subik from comment #38) > any ETA for tumbleweed? or even the older opensuse releases still receiving > updates? openSUSE Tumbleweed was submitted right now. https://build.opensuse.org/request/show/359990 openSUSE Leap 42.1 is patched openSUSE 13.2 update is building openSUSE 13.1 update... it's EOL/evergreen: community effort
Sorry to dump this here as is but one of my customer has the following question. --- Whether a SLES11SP4 bind – configured as caching proxy – will a) forward the maliciously forged DNS replies from DNS servers in the internet 1:1 to out DNS clients behind the DNS proxies, or b) drop / rewrite the DNS information, rendering the potential attack impossible. --- I guess it will make a difference to which machines they need to update and when. Can someone help answer it please
Richard's question (comment #43) is exactly what I would like to understand also. The discussions I have seen of this bug so far don't explain this point but it's rather crucial for people trying to understand how exposed they are.
(In reply to Andreas Stieger from comment #39) > openSUSE Leap 42.1 is patched > openSUSE 13.2 update is building > openSUSE 13.1 update... it's EOL/evergreen: community effort I do not see that the package is built for 13.2 anywhere. Could you check if building for this platform is enabled? It's marked as "disabled" here for example: https://build.opensuse.org/request/show/359990 and there is no open request for it here: https://build.opensuse.org/package/show/openSUSE:13.2:Update/glibc Am I looking in the wrong place?
yes, you are. it is building in a staging incident: openSUSE:Maintenance:4693
openSUSE Factory is released via the Tumbleweed Update repository.
openSUSE-SU-2016:0510-1: An update that solves 5 vulnerabilities and has two fixes is now available. Category: security (important) Bug References: 956716,958315,961721,962736,962737,962738,962739 CVE References: CVE-2014-9761,CVE-2015-7547,CVE-2015-8776,CVE-2015-8778,CVE-2015-8779 Sources used: openSUSE 13.2 (src): glibc-2.19-16.22.2, glibc-testsuite-2.19-16.22.4, glibc-utils-2.19-16.22.2
Hi all, Could you tell me if a reboot of the server is needed after the Patch has been applied ? Thanks Regards,
Hi, Florian. (In reply to Florian BONIN from comment #49) > Could you tell me if a reboot of the server is needed after the Patch has > been applied ? The problem is not in kernel, so the reboot is theoretically not needed. However, the fixed code is in libc, which is linked to... like everything? So you'd need to restart most of the userspace anyway (`zypper ps` might help), i.e. solution is either to reboot or restart ("only") all daemons that use the libc resolver. This is my theoretical POV, someone more experienced can add more.
(In reply to Florian BONIN from comment #49) ldd /bin/systemd clearly shows ... ... libc.so.6 => /lib64/libc.so.6 (0x00007f19fb594000) ... So your PID 1 is affected, you need to reboot.
(In reply to Matthias Subik from comment #51) > ldd /bin/systemd clearly shows ... systemctl daemon-reexec ;-)
Today a patch for 13.1 has been released. Can we also expect patches for older versions like 11.1, 12.1?
(In reply to dsgn dsgn from comment #54) > Today a patch for 13.1 has been released. Can we also expect patches for > older versions like 11.1, 12.1? No. The 13.1 patch was provided through Evergreen: https://en.opensuse.org/openSUSE:Evergreen There is no Evergreen effort underway for 11.1, 12.1. The patch is open source so you could build it. https://en.opensuse.org/Lifetime
(In reply to Michal Koutny from comment #52) > (In reply to Matthias Subik from comment #51) > > ldd /bin/systemd clearly shows ... > systemctl daemon-reexec ;-) I stand corrected, thank you.
The patch only changes libresolv and libnss_dns, so only processes using these libraries are affected.
(In reply to Andreas Schwab from comment #60) > The patch only changes libresolv and libnss_dns, so only processes using > these libraries are affected. The problem is that the vuln code is reachable via getaddrinfo(), which is a symbol of glibc. You dont immediately see via ldd if a program is affected. Missing libresolv/libnss_dns libs in ldd output dont mean anything. You'd need to dump /proc/pid/maps at runtime to find libnss_dns dynamically loaded. However, in most scenarios, you probably only need to restart nscd, as in nscd setups (which should be default for most of our dists?) the getaddrinfo() calls are routed to nscd which is turn is doing the real 'vulnerable' lookup.
> The problem is that the vuln code is reachable via getaddrinfo(), > which is a symbol of glibc. No, this is not the problem. The code of getaddrinfo (or any other part of libc.so) didn't change due to that patch in any way whatsoever. > You'd need to dump /proc/pid/maps at runtime > to find libnss_dns dynamically loaded. That is exactly what "using a library" is all about.
(In reply to Andreas Schwab from comment #64) > > The problem is that the vuln code is reachable via getaddrinfo(), > > which is a symbol of glibc. > > No, this is not the problem. The code of getaddrinfo (or any other part of > libc.so) didn't change due to that patch in any way whatsoever. I didnt say the opposite. The problem remains. Your program may still needs to be restarted, even if it "just" links to libc.so, as its the case with nscd.
> I didnt say the opposite. The problem remains. Your program may > still needs to be restarted, even if it "just" links to libc.so, Only once it has used libresolv or libnss_dns. ldd isn't the answer to that question. > as its the case with nscd Of course, nscd is using libnss_dns as soon as it tries to do a DNS lookup.
(In reply to Andreas Schwab from comment #66) > > I didnt say the opposite. The problem remains. Your program may > > still needs to be restarted, even if it "just" links to libc.so, > > Only once it has used libresolv or libnss_dns. ldd isn't the answer to that > question. That was my whole point, that "ldd systemd" and alike dont tell you anything :)
I currently can not add more than already written. A lot of mitigations are there, like stack is usually randomized, our services facing the network are built with ASLR. I general dont handle this as PANIC! update, but more as important for next possible maintenance window. We have currently not heard of working exploits in the wild. Updates were released, tumbleweed glibc is in final integration.