Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:Maintenance:405
glibc.openSUSE_13.1_Update
glibc-CVE-2015-7547-patch_1of3_dns_host.c.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File glibc-CVE-2015-7547-patch_1of3_dns_host.c.diff of Package glibc.openSUSE_13.1_Update
diff -rNU 20 ../glibc-2.18-orig/resolv/nss_dns/dns-host.c ./resolv/nss_dns/dns-host.c --- ../glibc-2.18-orig/resolv/nss_dns/dns-host.c 2016-02-17 19:02:50.000000000 +0100 +++ ./resolv/nss_dns/dns-host.c 2016-02-17 19:08:12.000000000 +0100 @@ -1033,41 +1033,44 @@ n = -1; } if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0 && (errno = EBADMSG)), 0)) { *errnop = errno; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } cp += n + QFIXEDSZ; int haveanswer = 0; int had_error = 0; char *canon = NULL; char *h_name = NULL; int h_namelen = 0; if (ancount == 0) - return NSS_STATUS_NOTFOUND; + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } while (ancount-- > 0 && cp < end_of_message && had_error == 0) { n = __ns_name_unpack (answer->buf, end_of_message, cp, packtmp, sizeof packtmp); if (n != -1 && (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1) { if (__builtin_expect (errno, 0) == EMSGSIZE) goto too_small; n = -1; } if (__builtin_expect (n < 0 || res_hnok (buffer) == 0, 0)) { ++had_error; continue; } if (*firstp && canon == NULL) { @@ -1210,60 +1213,164 @@ (*pat)->scopeid = 0; pat = &((*pat)->next); haveanswer = 1; } if (haveanswer) { *patp = pat; *bufferp = buffer; *buflenp = buflen; *h_errnop = NETDB_SUCCESS; return NSS_STATUS_SUCCESS; } /* Special case here: if the resolver sent a result but it only contains a CNAME while we are looking for a T_A or T_AAAA record, we fail with NOTFOUND instead of TRYAGAIN. */ - return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; + if (canon != NULL) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; } static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, int anslen2, const char *qname, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp) { int first = 1; enum nss_status status = NSS_STATUS_NOTFOUND; + /* Combining the NSS status of two distinct queries requires some + compromise and attention to symmetry (A or AAAA queries can be + returned in any order). What follows is a breakdown of how this + code is expected to work and why. We discuss only SUCCESS, + TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns + that apply (though RETURN and MERGE exist). We make a distinction + between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). + A recoverable TRYAGAIN is almost always due to buffer size issues + and returns ERANGE in errno and the caller is expected to retry + with a larger buffer. + + Lastly, you may be tempted to make significant changes to the + conditions in this code to bring about symmetry between responses. + Please don't change anything without due consideration for + expected application behaviour. Some of the synthesized responses + aren't very well thought out and sometimes appear to imply that + IPv4 responses are always answer 1, and IPv6 responses are always + answer 2, but that's not true (see the implementation of send_dg + and send_vc to see response can arrive in any order, particularly + for UDP). However, we expect it holds roughly enough of the time + that this code works, but certainly needs to be fixed to make this + a more robust implementation. + + ---------------------------------------------- + | Answer 1 Status / | Synthesized | Reason | + | Answer 2 Status | Status | | + |--------------------------------------------| + | SUCCESS/SUCCESS | SUCCESS | [1] | + | SUCCESS/TRYAGAIN | TRYAGAIN | [5] | + | SUCCESS/TRYAGAIN' | SUCCESS | [1] | + | SUCCESS/NOTFOUND | SUCCESS | [1] | + | SUCCESS/UNAVAIL | SUCCESS | [1] | + | TRYAGAIN/SUCCESS | TRYAGAIN | [2] | + | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] | + | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] | + | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] | + | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] | + | TRYAGAIN'/SUCCESS | SUCCESS | [3] | + | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] | + | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] | + | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] | + | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] | + | NOTFOUND/SUCCESS | SUCCESS | [3] | + | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] | + | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] | + | NOTFOUND/NOTFOUND | NOTFOUND | [3] | + | NOTFOUND/UNAVAIL | UNAVAIL | [3] | + | UNAVAIL/SUCCESS | UNAVAIL | [4] | + | UNAVAIL/TRYAGAIN | UNAVAIL | [4] | + | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] | + | UNAVAIL/NOTFOUND | UNAVAIL | [4] | + | UNAVAIL/UNAVAIL | UNAVAIL | [4] | + ---------------------------------------------- + + [1] If the first response is a success we return success. + This ignores the state of the second answer and in fact + incorrectly sets errno and h_errno to that of the second + answer. However because the response is a success we ignore + *errnop and *h_errnop (though that means you touched errno on + success). We are being conservative here and returning the + likely IPv4 response in the first answer as a success. + + [2] If the first response is a recoverable TRYAGAIN we return + that instead of looking at the second response. The + expectation here is that we have failed to get an IPv4 response + and should retry both queries. + + [3] If the first response was not a SUCCESS and the second + response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN, + or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the + result from the second response, otherwise the first responses + status is used. Again we have some odd side-effects when the + second response is NOTFOUND because we overwrite *errnop and + *h_errnop that means that a first answer of NOTFOUND might see + its *errnop and *h_errnop values altered. Whether it matters + in practice that a first response NOTFOUND has the wrong + *errnop and *h_errnop is undecided. + + [4] If the first response is UNAVAIL we return that instead of + looking at the second response. The expectation here is that + it will have failed similarly e.g. configuration failure. + + [5] Testing this code is complicated by the fact that truncated + second response buffers might be returned as SUCCESS if the + first answer is a SUCCESS. To fix this we add symmetry to + TRYAGAIN with the second response. If the second response + is a recoverable error we now return TRYAGIN even if the first + response was SUCCESS. */ + if (anslen1 > 0) status = gaih_getanswer_slice(answer1, anslen1, qname, &pat, &buffer, &buflen, errnop, h_errnop, ttlp, &first); + if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND || (status == NSS_STATUS_TRYAGAIN /* We want to look at the second answer in case of an NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e. *h_errnop is NO_RECOVERY. If not, and if the failure was due to an insufficient buffer (ERANGE), then we need to drop the results and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can repeat the query with a larger buffer. */ && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) && answer2 != NULL && anslen2 > 0) { enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, &pat, &buffer, &buflen, errnop, h_errnop, ttlp, &first); + /* Use the second response status in some cases. */ if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) status = status2; + /* Do not return a truncated second response (unless it was + unavoidable e.g. unrecoverable TRYAGAIN). */ + if (status == NSS_STATUS_SUCCESS + && (status2 == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) + status = NSS_STATUS_TRYAGAIN; } return status; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor