diff --git a/glibc-rh2129005.patch b/glibc-rh2129005.patch new file mode 100644 index 0000000..10d7801 --- /dev/null +++ b/glibc-rh2129005.patch @@ -0,0 +1,589 @@ +commit 1d495912a746e2a1ffb780c9a81fd234ec2464e8 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces + + Introduce struct alloc_buffer to this function, and use it and + struct ns_rr_cursor in gaih_getanswer_slice. Adjust gaih_getanswer + and gaih_getanswer_noaaaa accordingly. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 1cb3be71f04d98eb..36789965c06757d0 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -101,13 +101,6 @@ + #endif + #define MAXHOSTNAMELEN 256 + +-/* We need this time later. */ +-typedef union querybuf +-{ +- HEADER hdr; +- u_char buf[MAXPACKET]; +-} querybuf; +- + /* For historic reasons, pointers to IP addresses are char *, so use a + single list type for addresses and host names. */ + #define DYNARRAY_STRUCT ptrlist +@@ -126,18 +119,18 @@ static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, + char **hnamep, int *errnop, + int *h_errnop, int32_t *ttlp); + +-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, +- const querybuf *answer2, int anslen2, +- const char *qname, ++static enum nss_status gaih_getanswer (unsigned char *packet1, ++ size_t packet1len, ++ unsigned char *packet2, ++ size_t packet2len, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); +-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, +- int anslen1, +- const char *qname, ++static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet, ++ size_t packetlen, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + +@@ -409,17 +402,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + name = cp; + } + +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ++ unsigned char dns_packet_buffer[2048]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + u_char *ans2p = NULL; + int nans2p = 0; + int resplen2 = 0; + int ans2p_malloced = 0; ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + + + int olderr = errno; +@@ -428,22 +417,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + if ((ctx->resp->options & RES_NOAAAA) == 0) + { + n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, +- host_buffer.buf->buf, 2048, &host_buffer.ptr, +- &ans2p, &nans2p, &resplen2, &ans2p_malloced); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, &ans2p, &nans2p, ++ &resplen2, &ans2p_malloced); + if (n >= 0) +- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, +- resplen2, name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2, ++ &abuf, pat, errnop, herrnop, ttlp); + } + else + { + n = __res_context_search (ctx, name, C_IN, T_A, +- host_buffer.buf->buf, 2048, NULL, +- NULL, NULL, NULL, NULL); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ NULL, NULL, NULL, NULL, NULL); + if (n >= 0) +- status = gaih_getanswer_noaaaa (host_buffer.buf, n, +- name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, ++ &abuf, pat, errnop, herrnop, ttlp); + } + if (n < 0) + { +@@ -474,12 +462,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + __set_errno (olderr); + } + ++ /* Implement the buffer resizing protocol. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *herrnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ + /* Check whether ans2p was separately allocated. */ + if (ans2p_malloced) + free (ans2p); + +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + + __resolv_context_put (ctx); + return status; +@@ -893,259 +889,152 @@ getanswer_ptr (unsigned char *packet, size_t packetlen, + return NSS_STATUS_TRYAGAIN; + } + ++/* Parses DNS data found in PACKETLEN bytes at PACKET in struct ++ gaih_addrtuple address tuples. The new address tuples are linked ++ from **TAILP, with backing store allocated from ABUF, and *TAILP is ++ updated to point where the next tuple pointer should be stored. If ++ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If ++ STORE_CANON is true, the canonical name is stored as part of the ++ first address tuple being written. */ + static enum nss_status +-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, +- struct gaih_addrtuple ***patp, +- char **bufferp, size_t *buflenp, +- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp) ++gaih_getanswer_slice (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ struct gaih_addrtuple ***tailp, ++ int *errnop, int *h_errnop, int32_t *ttlp, ++ bool store_canon) + { +- char *buffer = *bufferp; +- size_t buflen = *buflenp; +- +- struct gaih_addrtuple **pat = *patp; +- const HEADER *hp = &answer->hdr; +- int ancount = ntohs (hp->ancount); +- int qdcount = ntohs (hp->qdcount); +- const u_char *cp = answer->buf + HFIXEDSZ; +- const u_char *end_of_message = answer->buf + anslen; +- if (__glibc_unlikely (qdcount != 1)) +- { +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- +- u_char packtmp[NS_MAXCDNAME]; +- int n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- /* We unpack the name to check it for validity. But we do not need +- it later. */ +- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- { +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) +- { +- *errnop = errno; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0)) ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { +- errno = EBADMSG; +- *errnop = EBADMSG; ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- cp += n + QFIXEDSZ; ++ bool haveanswer = false; /* Set to true if at least one address. */ ++ uint16_t qtype = ns_rr_cursor_qtype (&c); ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; + +- int haveanswer = 0; +- int had_error = 0; +- char *canon = NULL; +- char *h_name = NULL; +- int h_namelen = 0; ++ /* This is a pointer to a possibly-compressed name in the packet. ++ Eventually it is equivalent to the canonical name. If needed, it ++ is uncompressed and translated to text form when the first ++ address tuple is encountered. */ ++ const unsigned char *compressed_alias_name = expected_name; + +- if (ancount == 0) ++ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name)) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ for (; ancount > -0; --ancount) + { +- 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 (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- if (__glibc_unlikely (n < 0)) +- { +- ++had_error; +- continue; +- } +- if (*firstp && canon == NULL && __libc_res_hnok (buffer)) +- { +- h_name = buffer; +- buffer += h_namelen; +- buflen -= h_namelen; +- } +- +- cp += n; /* name */ +- +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; +- } +- +- uint16_t type; +- NS_GET16 (type, cp); +- uint16_t class; +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ +- +- if (end_of_message - cp < n) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- if (class != C_IN) +- { +- cp += n; +- continue; +- } ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- if (type == T_CNAME) ++ if (rr.rtype == T_CNAME) + { +- char tbuf[MAXDNAME]; +- +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- +- if (*firstp && __libc_res_hnok (tbuf)) ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- /* Reclaim buffer space. */ +- if (h_name + h_namelen == buffer) +- { +- buffer = h_name; +- buflen += h_namelen; +- } +- +- n = strlen (tbuf) + 1; +- if (__glibc_unlikely (n > buflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- +- canon = buffer; +- buffer = __mempcpy (buffer, tbuf, n); +- buflen -= n; +- h_namelen = 0; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- continue; ++ expected_name = name_buffer; ++ if (store_canon && __res_binary_hnok (name_buffer)) ++ /* This name can be used as a canonical name. Do not ++ translate to text form here to conserve buffer space. ++ Point to the compressed name because name_buffer can be ++ overwritten with an unusable name later. */ ++ compressed_alias_name = rr.rdata; + } +- +- /* Stop parsing if we encounter a record with incorrect RDATA +- length. */ +- if (type == T_A || type == T_AAAA) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- if (n != rrtype_to_rdata_length (type)) ++ struct gaih_addrtuple *ntup ++ = alloc_buffer_alloc (abuf, struct gaih_addrtuple); ++ /* Delay error reporting to the callers (they implement the ++ ERANGE buffer resizing handshake). */ ++ if (ntup != NULL) + { +- ++had_error; +- continue; ++ ntup->next = NULL; ++ if (store_canon && compressed_alias_name != NULL) ++ { ++ /* This assumes that all the CNAME records come ++ first. Use MAXHOSTNAMELEN instead of ++ NS_MAXCDNAME for additional length checking. ++ However, these checks are not expected to fail ++ because all size NS_MAXCDNAME names should into ++ the hname buffer because no escaping is ++ needed. */ ++ char unsigned nbuf[NS_MAXCDNAME]; ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, ++ compressed_alias_name, ++ nbuf, sizeof (nbuf)) >= 0 ++ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0) ++ /* Space checking is performed by the callers. */ ++ ntup->name = alloc_buffer_copy_string (abuf, hname); ++ store_canon = false; ++ } ++ else ++ ntup->name = NULL; ++ if (rr.rdlength == 4) ++ ntup->family = AF_INET; ++ else ++ ntup->family = AF_INET6; ++ memcpy (ntup->addr, rr.rdata, rr.rdlength); ++ ntup->scopeid = 0; ++ ++ /* Link in the new tuple, and update the tail pointer to ++ point to its next field. */ ++ **tailp = ntup; ++ *tailp = &ntup->next; ++ ++ haveanswer = true; + } + } +- else +- { +- /* Skip unknown records. */ +- cp += n; +- continue; +- } +- +- assert (type == T_A || type == T_AAAA); +- if (*pat == NULL) +- { +- uintptr_t pad = (-(uintptr_t) buffer +- % __alignof__ (struct gaih_addrtuple)); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) +- goto too_small; +- +- *pat = (struct gaih_addrtuple *) buffer; +- buffer += sizeof (struct gaih_addrtuple); +- buflen -= sizeof (struct gaih_addrtuple); +- } +- +- (*pat)->name = NULL; +- (*pat)->next = NULL; +- +- if (*firstp) +- { +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- (*pat)->name = canon ?: h_name; +- +- *firstp = 0; +- } +- +- (*pat)->family = type == T_A ? AF_INET : AF_INET6; +- memcpy ((*pat)->addr, cp, n); +- cp += n; +- (*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. */ +- if (canon != NULL) ++ else + { ++ /* 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. */ + *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, ++gaih_getanswer (unsigned char *packet1, size_t packet1len, ++ unsigned char *packet2, size_t packet2len, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + 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 +@@ -1157,7 +1046,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + 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. ++ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r, ++ ignores the return status if it detects that the result buffer ++ has been exhausted and generates a TRYAGAIN failure with an ++ ERANGE code.) + + Lastly, you may be tempted to make significant changes to the + conditions in this code to bring about symmetry between responses. +@@ -1237,36 +1129,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + 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) ++ if (packet1len > 0) + { +- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ status = gaih_getanswer_slice (packet1, packet1len, ++ abuf, &pat, errnop, h_errnop, ttlp, true); ++ if (alloc_buffer_has_failed (abuf)) ++ /* Do not try parsing the second packet if a larger result ++ buffer is needed. The caller implements the resizing ++ protocol because *abuf has been exhausted. */ ++ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */ ++ } ++ ++ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) ++ && packet2 != NULL && packet2len > 0) ++ { ++ enum nss_status status2 ++ = gaih_getanswer_slice (packet2, packet2len, ++ abuf, &pat, errnop, h_errnop, ttlp, ++ /* Success means that data with a ++ canonical name has already been ++ stored. Do not store the name again. */ ++ status != NSS_STATUS_SUCCESS); + /* 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; +@@ -1274,18 +1160,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + + /* Variant of gaih_getanswer without a second (AAAA) response. */ + static enum nss_status +-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, +- struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, ++gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- int first = 1; +- + enum nss_status status = NSS_STATUS_NOTFOUND; +- if (anslen1 > 0) +- status = gaih_getanswer_slice (answer1, anslen1, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ if (packetlen > 0) ++ status = gaih_getanswer_slice (packet, packetlen, ++ abuf, &pat, errnop, h_errnop, ttlp, true); + return status; + } diff --git a/glibc-upstream-2.34-309.patch b/glibc-upstream-2.34-309.patch new file mode 100644 index 0000000..1c34dc0 --- /dev/null +++ b/glibc-upstream-2.34-309.patch @@ -0,0 +1,212 @@ +commit 536ddc5c02f1ee82483319863a893ccb381beece +Author: Florian Weimer +Date: Fri Aug 26 21:15:43 2022 +0200 + + elf: Call __libc_early_init for reused namespaces (bug 29528) + + libc_map is never reset to NULL, neither during dlclose nor on a + dlopen call which reuses the namespace structure. As a result, if a + namespace is reused, its libc is not initialized properly. The most + visible result is a crash in the functions. + + To prevent similar bugs on namespace reuse from surfacing, + unconditionally initialize the chosen namespace to zero using memset. + + (cherry picked from commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe) + +Conflicts: + elf/Makefile + (usual test differences) + +diff --git a/elf/Makefile b/elf/Makefile +index 2b547d5b58f1759b..feec365e4e5fe9b3 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -399,6 +399,7 @@ tests += \ + tst-dlmopen3 \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-dlmopen-twice \ + tst-dlopenfail \ + tst-dlopenfail-2 \ + tst-dlopenrpath \ +@@ -744,6 +745,8 @@ modules-names = \ + tst-dlmopen1mod \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-twice-mod1 \ ++ tst-dlmopen-twice-mod2 \ + tst-dlopenfaillinkmod \ + tst-dlopenfailmod1 \ + tst-dlopenfailmod2 \ +@@ -2665,3 +2668,7 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so + tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so + $(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so + tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++ ++$(objpfx)tst-dlmopen-twice.out: \ ++ $(objpfx)tst-dlmopen-twice-mod1.so \ ++ $(objpfx)tst-dlmopen-twice-mod2.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index bc6872632880634e..1ab3c7b5ac2fbc45 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -839,11 +839,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, + _dl_signal_error (EINVAL, file, NULL, N_("\ + no more namespaces available for dlmopen()")); + } +- else if (nsid == GL(dl_nns)) +- { +- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); +- ++GL(dl_nns); +- } ++ ++ if (nsid == GL(dl_nns)) ++ ++GL(dl_nns); ++ ++ /* Initialize the new namespace. Most members are ++ zero-initialized, only the lock needs special treatment. */ ++ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid])); ++ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock); + + _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT; + } +diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c +new file mode 100644 +index 0000000000000000..0eaf04948ce5263e +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod1.c +@@ -0,0 +1,37 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++/* Large allocation. The second module does not have this, so it ++ should load libc at a different address. */ ++char large_allocate[16 * 1024 * 1024]; +diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c +new file mode 100644 +index 0000000000000000..40c6c01f9625e188 +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod2.c +@@ -0,0 +1,50 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++int ++run_check (void) ++{ ++ puts ("info: about to call isalpha"); ++ fflush (stdout); ++ ++ volatile char ch = 'a'; ++ if (!isalpha (ch)) ++ { ++ puts ("error: isalpha ('a') is not true"); ++ fflush (stdout); ++ return 1; ++ } ++ return 0; ++} +diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c +new file mode 100644 +index 0000000000000000..449f3c8fa9f2aa01 +--- /dev/null ++++ b/elf/tst-dlmopen-twice.c +@@ -0,0 +1,34 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW); ++ xdlclose (handle); ++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); ++ int (*run_check) (void) = xdlsym (handle, "run_check"); ++ TEST_COMPARE (run_check (), 0); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-310.patch b/glibc-upstream-2.34-310.patch new file mode 100644 index 0000000..7f949a0 --- /dev/null +++ b/glibc-upstream-2.34-310.patch @@ -0,0 +1,334 @@ +commit 2a44960cbc78713c6a2721683a4319d50e71a01f +Author: Tulio Magno Quites Machado Filho +Date: Thu Jul 7 18:12:58 2022 -0300 + + Apply asm redirections in stdio.h before first use [BZ #27087] + + Compilers may not be able to apply asm redirections to functions after + these functions are used for the first time, e.g. clang 13. + Fix [BZ #27087] by applying all long double-related asm redirections + before using functions in bits/stdio.h. + However, as these asm redirections depend on the declarations provided + by libio/bits/stdio2.h, this header was split in 2: + + - libio/bits/stdio2-decl.h contains all function declarations; + - libio/bits/stdio2.h remains with the remaining contents, including + redirections. + + This also adds the access attribute to __vsnprintf_chk that was missing. + + Tested with build-many-glibcs.py. + + Reviewed-by: Paul E. Murphy + (cherry picked from commit d0fa09a7701956036ff36f8ca188e9fff81553d8) + +diff --git a/include/bits/stdio2-decl.h b/include/bits/stdio2-decl.h +new file mode 100644 +index 0000000000000000..bbb052f192218219 +--- /dev/null ++++ b/include/bits/stdio2-decl.h +@@ -0,0 +1 @@ ++#include +diff --git a/libio/Makefile b/libio/Makefile +index 5336b7d59584927f..981c876940f67fbf 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -23,7 +23,7 @@ subdir := libio + include ../Makeconfig + + headers := stdio.h \ +- bits/stdio.h bits/stdio2.h bits/stdio-ldbl.h \ ++ bits/stdio.h bits/stdio2.h bits/stdio2-decl.h bits/stdio-ldbl.h \ + bits/types/FILE.h bits/types/__FILE.h bits/types/struct_FILE.h \ + bits/types/__fpos_t.h bits/types/__fpos64_t.h \ + bits/types/cookie_io_functions_t.h +diff --git a/libio/bits/stdio2-decl.h b/libio/bits/stdio2-decl.h +new file mode 100644 +index 0000000000000000..e398f7182b98e4d7 +--- /dev/null ++++ b/libio/bits/stdio2-decl.h +@@ -0,0 +1,111 @@ ++/* Checking macros for stdio functions. Declarations only. ++ Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _BITS_STDIO2_DEC_H ++#define _BITS_STDIO2_DEC_H 1 ++ ++#ifndef _STDIO_H ++# error "Never include directly; use instead." ++#endif ++ ++extern int __sprintf_chk (char *__restrict __s, int __flag, size_t __slen, ++ const char *__restrict __format, ...) __THROW ++ __attr_access ((__write_only__, 1, 3)); ++extern int __vsprintf_chk (char *__restrict __s, int __flag, size_t __slen, ++ const char *__restrict __format, ++ __gnuc_va_list __ap) __THROW ++ __attr_access ((__write_only__, 1, 3)); ++ ++#if defined __USE_ISOC99 || defined __USE_UNIX98 ++ ++extern int __snprintf_chk (char *__restrict __s, size_t __n, int __flag, ++ size_t __slen, const char *__restrict __format, ++ ...) __THROW ++ __attr_access ((__write_only__, 1, 2)); ++extern int __vsnprintf_chk (char *__restrict __s, size_t __n, int __flag, ++ size_t __slen, const char *__restrict __format, ++ __gnuc_va_list __ap) __THROW ++ __attr_access ((__write_only__, 1, 2)); ++ ++#endif ++ ++#if __USE_FORTIFY_LEVEL > 1 ++ ++extern int __fprintf_chk (FILE *__restrict __stream, int __flag, ++ const char *__restrict __format, ...); ++extern int __printf_chk (int __flag, const char *__restrict __format, ...); ++extern int __vfprintf_chk (FILE *__restrict __stream, int __flag, ++ const char *__restrict __format, __gnuc_va_list __ap); ++extern int __vprintf_chk (int __flag, const char *__restrict __format, ++ __gnuc_va_list __ap); ++ ++# ifdef __USE_XOPEN2K8 ++extern int __dprintf_chk (int __fd, int __flag, const char *__restrict __fmt, ++ ...) __attribute__ ((__format__ (__printf__, 3, 4))); ++extern int __vdprintf_chk (int __fd, int __flag, ++ const char *__restrict __fmt, __gnuc_va_list __arg) ++ __attribute__ ((__format__ (__printf__, 3, 0))); ++# endif ++ ++# ifdef __USE_GNU ++ ++extern int __asprintf_chk (char **__restrict __ptr, int __flag, ++ const char *__restrict __fmt, ...) ++ __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur; ++extern int __vasprintf_chk (char **__restrict __ptr, int __flag, ++ const char *__restrict __fmt, __gnuc_va_list __arg) ++ __THROW __attribute__ ((__format__ (__printf__, 3, 0))) __wur; ++extern int __obstack_printf_chk (struct obstack *__restrict __obstack, ++ int __flag, const char *__restrict __format, ++ ...) ++ __THROW __attribute__ ((__format__ (__printf__, 3, 4))); ++extern int __obstack_vprintf_chk (struct obstack *__restrict __obstack, ++ int __flag, ++ const char *__restrict __format, ++ __gnuc_va_list __args) ++ __THROW __attribute__ ((__format__ (__printf__, 3, 0))); ++ ++# endif ++#endif ++ ++#if __GLIBC_USE (DEPRECATED_GETS) ++extern char *__gets_chk (char *__str, size_t) __wur; ++#endif ++ ++extern char *__fgets_chk (char *__restrict __s, size_t __size, int __n, ++ FILE *__restrict __stream) ++ __wur __attr_access ((__write_only__, 1, 3)); ++ ++extern size_t __fread_chk (void *__restrict __ptr, size_t __ptrlen, ++ size_t __size, size_t __n, ++ FILE *__restrict __stream) __wur; ++ ++#ifdef __USE_GNU ++extern char *__fgets_unlocked_chk (char *__restrict __s, size_t __size, ++ int __n, FILE *__restrict __stream) ++ __wur __attr_access ((__write_only__, 1, 3)); ++#endif ++ ++#ifdef __USE_MISC ++# undef fread_unlocked ++extern size_t __fread_unlocked_chk (void *__restrict __ptr, size_t __ptrlen, ++ size_t __size, size_t __n, ++ FILE *__restrict __stream) __wur; ++#endif ++ ++#endif /* bits/stdio2-decl.h. */ +diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h +index 40ff16b01b4f4876..4570f86a4496c1ee 100644 +--- a/libio/bits/stdio2.h ++++ b/libio/bits/stdio2.h +@@ -23,14 +23,6 @@ + # error "Never include directly; use instead." + #endif + +-extern int __sprintf_chk (char *__restrict __s, int __flag, size_t __slen, +- const char *__restrict __format, ...) __THROW +- __attr_access ((__write_only__, 1, 3)); +-extern int __vsprintf_chk (char *__restrict __s, int __flag, size_t __slen, +- const char *__restrict __format, +- __gnuc_va_list __ap) __THROW +- __attr_access ((__write_only__, 1, 3)); +- + #ifdef __va_arg_pack + __fortify_function int + __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...)) +@@ -54,15 +46,6 @@ __NTH (vsprintf (char *__restrict __s, const char *__restrict __fmt, + } + + #if defined __USE_ISOC99 || defined __USE_UNIX98 +- +-extern int __snprintf_chk (char *__restrict __s, size_t __n, int __flag, +- size_t __slen, const char *__restrict __format, +- ...) __THROW +- __attr_access ((__write_only__, 1, 2)); +-extern int __vsnprintf_chk (char *__restrict __s, size_t __n, int __flag, +- size_t __slen, const char *__restrict __format, +- __gnuc_va_list __ap) __THROW; +- + # ifdef __va_arg_pack + __fortify_function int + __NTH (snprintf (char *__restrict __s, size_t __n, +@@ -89,15 +72,6 @@ __NTH (vsnprintf (char *__restrict __s, size_t __n, + #endif + + #if __USE_FORTIFY_LEVEL > 1 +- +-extern int __fprintf_chk (FILE *__restrict __stream, int __flag, +- const char *__restrict __format, ...); +-extern int __printf_chk (int __flag, const char *__restrict __format, ...); +-extern int __vfprintf_chk (FILE *__restrict __stream, int __flag, +- const char *__restrict __format, __gnuc_va_list __ap); +-extern int __vprintf_chk (int __flag, const char *__restrict __format, +- __gnuc_va_list __ap); +- + # ifdef __va_arg_pack + __fortify_function int + fprintf (FILE *__restrict __stream, const char *__restrict __fmt, ...) +@@ -136,12 +110,6 @@ vfprintf (FILE *__restrict __stream, + } + + # ifdef __USE_XOPEN2K8 +-extern int __dprintf_chk (int __fd, int __flag, const char *__restrict __fmt, +- ...) __attribute__ ((__format__ (__printf__, 3, 4))); +-extern int __vdprintf_chk (int __fd, int __flag, +- const char *__restrict __fmt, __gnuc_va_list __arg) +- __attribute__ ((__format__ (__printf__, 3, 0))); +- + # ifdef __va_arg_pack + __fortify_function int + dprintf (int __fd, const char *__restrict __fmt, ...) +@@ -162,23 +130,6 @@ vdprintf (int __fd, const char *__restrict __fmt, __gnuc_va_list __ap) + # endif + + # ifdef __USE_GNU +- +-extern int __asprintf_chk (char **__restrict __ptr, int __flag, +- const char *__restrict __fmt, ...) +- __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur; +-extern int __vasprintf_chk (char **__restrict __ptr, int __flag, +- const char *__restrict __fmt, __gnuc_va_list __arg) +- __THROW __attribute__ ((__format__ (__printf__, 3, 0))) __wur; +-extern int __obstack_printf_chk (struct obstack *__restrict __obstack, +- int __flag, const char *__restrict __format, +- ...) +- __THROW __attribute__ ((__format__ (__printf__, 3, 4))); +-extern int __obstack_vprintf_chk (struct obstack *__restrict __obstack, +- int __flag, +- const char *__restrict __format, +- __gnuc_va_list __args) +- __THROW __attribute__ ((__format__ (__printf__, 3, 0))); +- + # ifdef __va_arg_pack + __fortify_function int + __NTH (asprintf (char **__restrict __ptr, const char *__restrict __fmt, ...)) +@@ -231,7 +182,6 @@ __NTH (obstack_vprintf (struct obstack *__restrict __obstack, + #endif + + #if __GLIBC_USE (DEPRECATED_GETS) +-extern char *__gets_chk (char *__str, size_t) __wur; + extern char *__REDIRECT (__gets_warn, (char *__str), gets) + __wur __warnattr ("please use fgets or getline instead, gets can't " + "specify buffer size"); +@@ -245,9 +195,6 @@ gets (char *__str) + } + #endif + +-extern char *__fgets_chk (char *__restrict __s, size_t __size, int __n, +- FILE *__restrict __stream) +- __wur __attr_access ((__write_only__, 1, 3)); + extern char *__REDIRECT (__fgets_alias, + (char *__restrict __s, int __n, + FILE *__restrict __stream), fgets) +@@ -269,9 +216,6 @@ fgets (char *__restrict __s, int __n, FILE *__restrict __stream) + return __fgets_chk (__s, sz, __n, __stream); + } + +-extern size_t __fread_chk (void *__restrict __ptr, size_t __ptrlen, +- size_t __size, size_t __n, +- FILE *__restrict __stream) __wur; + extern size_t __REDIRECT (__fread_alias, + (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream), +@@ -297,9 +241,6 @@ fread (void *__restrict __ptr, size_t __size, size_t __n, + } + + #ifdef __USE_GNU +-extern char *__fgets_unlocked_chk (char *__restrict __s, size_t __size, +- int __n, FILE *__restrict __stream) +- __wur __attr_access ((__write_only__, 1, 3)); + extern char *__REDIRECT (__fgets_unlocked_alias, + (char *__restrict __s, int __n, + FILE *__restrict __stream), fgets_unlocked) +@@ -324,9 +265,6 @@ fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream) + + #ifdef __USE_MISC + # undef fread_unlocked +-extern size_t __fread_unlocked_chk (void *__restrict __ptr, size_t __ptrlen, +- size_t __size, size_t __n, +- FILE *__restrict __stream) __wur; + extern size_t __REDIRECT (__fread_unlocked_alias, + (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream), +diff --git a/libio/stdio.h b/libio/stdio.h +index abefe640e52d18d5..d36e61c56bbb3117 100644 +--- a/libio/stdio.h ++++ b/libio/stdio.h +@@ -879,20 +879,27 @@ extern void funlockfile (FILE *__stream) __THROW; + extern int __uflow (FILE *); + extern int __overflow (FILE *, int); + ++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function ++/* Declare all functions from bits/stdio2-decl.h first. */ ++# include ++#endif ++ ++/* The following headers provide asm redirections. These redirections must ++ appear before the first usage of these functions, e.g. in bits/stdio.h. */ ++#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 ++# include ++#endif ++ + /* If we are compiling with optimizing read this file. It contains + several optimizing inline functions and macros. */ + #ifdef __USE_EXTERN_INLINES + # include + #endif + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function ++/* Now include the function definitions and redirects too. */ + # include + #endif + +-#include +-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +-# include +-#endif +- + __END_DECLS + + #endif /* included. */ diff --git a/glibc-upstream-2.34-311.patch b/glibc-upstream-2.34-311.patch new file mode 100644 index 0000000..2307c0c --- /dev/null +++ b/glibc-upstream-2.34-311.patch @@ -0,0 +1,414 @@ +commit b41c535f46e7e7bbd8ff2ac68b94c2348e2f66e4 +Author: Raphael Moreira Zinsly +Date: Wed Aug 24 11:43:37 2022 -0300 + + Apply asm redirections in wchar.h before first use + + Similar to d0fa09a770, but for wchar.h. Fixes [BZ #27087] by applying + all long double related asm redirections before using functions in + bits/wchar2.h. + Moves the function declarations from wcsmbs/bits/wchar2.h to a new file + wcsmbs/bits/wchar2-decl.h that will be included first in wcsmbs/wchar.h. + + Tested with build-many-glibcs.py. + Reviewed-by: Adhemerval Zanella + + (cherry picked from commit c7509d49c4e8fa494120c5ead21338559dad16f5) + +diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h +new file mode 100644 +index 0000000000000000..00b1b93342ef28ff +--- /dev/null ++++ b/include/bits/wchar2-decl.h +@@ -0,0 +1 @@ ++#include +diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile +index f38eb5cfe16fd3d7..5fe755e65df6c621 100644 +--- a/wcsmbs/Makefile ++++ b/wcsmbs/Makefile +@@ -22,8 +22,9 @@ subdir := wcsmbs + + include ../Makeconfig + +-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \ +- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h ++headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \ ++ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \ ++ bits/types/mbstate_t.h bits/types/wint_t.h + + routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ + wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ +diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h +new file mode 100644 +index 0000000000000000..8e1735c33b7f7e78 +--- /dev/null ++++ b/wcsmbs/bits/wchar2-decl.h +@@ -0,0 +1,124 @@ ++/* Checking macros for wchar functions. Declarations only. ++ Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _BITS_WCHAR2_DECL_H ++#define _BITS_WCHAR2_DECL_H 1 ++ ++#ifndef _WCHAR_H ++# error "Never include directly; use instead." ++#endif ++ ++ ++extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, ++ size_t __n, size_t __ns1) __THROW; ++ ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++ ++#endif ++ ++ ++extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, ++ size_t __ns) __THROW; ++extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n) __THROW; ++extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n, size_t __destlen) __THROW; ++extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ...) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; ++extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __arg) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; ++ ++#if __USE_FORTIFY_LEVEL > 1 ++ ++extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ...); ++extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, ++ ...); ++extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++ ++#endif ++ ++extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, ++ __FILE *__restrict __stream) __wur; ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, ++ int __n, __FILE *__restrict __stream) ++ __wur; ++ ++#endif ++ ++extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, ++ mbstate_t *__restrict __p, ++ size_t __buflen) __THROW __wur; ++extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++ ++#ifdef __USE_XOPEN2K8 ++ ++extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, size_t __nmc, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsnrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __nwc, size_t __len, ++ mbstate_t *__restrict __ps, size_t __dstlen) ++ __THROW; ++ ++#endif ++ ++#endif /* bits/wchar2-decl.h. */ +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index 88c1fdfcd34292f4..50151b424d85a032 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -21,9 +21,6 @@ + #endif + + +-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, size_t __n), +@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + } + + +-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, +- size_t __n, size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1, + const wchar_t *__s2, + size_t __n), wmemmove); +@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) + + + #ifdef __USE_GNU +-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, +@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + #endif + + +-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, +- size_t __ns) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c, + size_t __n), wmemset); + extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, +@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) + } + + +-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscpy); +@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcpcpy); +@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscat); +@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n, size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, ...) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; + + extern int __REDIRECT_NTH_LDBL (__swprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n, + : swprintf (s, n, __VA_ARGS__)) + #endif + +-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, +- __gnuc_va_list __arg) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; + + extern int __REDIRECT_NTH_LDBL (__vswprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, + + #if __USE_FORTIFY_LEVEL > 1 + +-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, ...); +-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, +- ...); +-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +- + # ifdef __va_arg_pack + __fortify_function int + wprintf (const wchar_t *__restrict __fmt, ...) +@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream, + + #endif + +-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, +- __FILE *__restrict __stream) __wur; + extern wchar_t *__REDIRECT (__fgetws_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws) __wur; +@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + } + + #ifdef __USE_GNU +-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, +- int __n, __FILE *__restrict __stream) +- __wur; + extern wchar_t *__REDIRECT (__fgetws_unlocked_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws_unlocked) +@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + #endif + + +-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, +- mbstate_t *__restrict __p, +- size_t __buflen) __THROW __wur; + extern size_t __REDIRECT_NTH (__wcrtomb_alias, + (char *__restrict __s, wchar_t __wchar, + mbstate_t *__restrict __ps), wcrtomb) __wur; +@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, + } + + +-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, +@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__wcsrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + + + #ifdef __USE_XOPEN2K8 +-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, size_t __nmc, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, +@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsnrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __nwc, size_t __len, +- mbstate_t *__restrict __ps, size_t __dstlen) +- __THROW; + extern size_t __REDIRECT_NTH (__wcsnrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h +index 075776890f214842..1c6d4026c46b7306 100644 +--- a/wcsmbs/wchar.h ++++ b/wcsmbs/wchar.h +@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize, + + /* Define some macros helping to catch buffer overflows. */ + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +-# include ++/* Declare all functions from bits/wchar2-decl.h first. */ ++# include + #endif + +-#include ++/* The following headers provide asm redirections. These redirections must ++ appear before the first usage of these functions, e.g. in bits/wchar.h. */ + #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 + # include + #endif + ++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function ++/* Now include the function definitions and redirects too. */ ++# include ++#endif ++ + __END_DECLS + + #endif /* wchar.h */ diff --git a/glibc-upstream-2.34-312.patch b/glibc-upstream-2.34-312.patch new file mode 100644 index 0000000..f8add99 --- /dev/null +++ b/glibc-upstream-2.34-312.patch @@ -0,0 +1,40 @@ +commit 2b3d020055bea4fbbfc0ca2362d46038487c6dfd +Author: Fabian Vogt +Date: Wed Jul 27 11:44:07 2022 +0200 + + nscd: Fix netlink cache invalidation if epoll is used [BZ #29415] + + Processes cache network interface information such as whether IPv4 or IPv6 + are enabled. This is only checked again if the "netlink timestamp" provided + by nscd changed, which is triggered by netlink socket activity. + + However, in the epoll handler for the netlink socket, it was missed to + assign the new timestamp to the nscd database. The handler for plain poll + did that properly, copy that over. + + This bug caused that e.g. processes which started before network + configuration got unusuable addresses from getaddrinfo, like IPv6 only even + though only IPv4 is available: + https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1041 + + It's a bit hard to reproduce, so I verified this by checking the timestamp + on calls to __check_pf manually. Without this patch it's stuck at 1, now + it's increasing on network changes as expected. + + Signed-off-by: Fabian Vogt + (cherry picked from commit 02ca25fef2785974011e9c5beecc99b900b69fd7) + +diff --git a/nscd/connections.c b/nscd/connections.c +index 3f0bda4e97edb9df..bc941715cff47c49 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -2285,7 +2285,8 @@ main_loop_epoll (int efd) + sizeof (buf))) != -1) + ; + +- __bump_nl_timestamp (); ++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] ++ = __bump_nl_timestamp (); + } + # endif + else diff --git a/glibc-upstream-2.34-314.patch b/glibc-upstream-2.34-314.patch new file mode 100644 index 0000000..be02589 --- /dev/null +++ b/glibc-upstream-2.34-314.patch @@ -0,0 +1,55 @@ +commit 2ff6775ad341b10a08e3b27d6e1df1da637747c7 +Author: Javier Pello +Date: Mon Sep 5 20:09:01 2022 +0200 + + elf: Fix hwcaps string size overestimation + + Commit dad90d528259b669342757c37dedefa8577e2636 added glibc-hwcaps + support for LD_LIBRARY_PATH and, for this, it adjusted the total + string size required in _dl_important_hwcaps. However, in doing so + it inadvertently altered the calculation of the size required for + the power set strings, as the computation of the power set string + size depended on the first value assigned to the total variable, + which is later shifted, resulting in overallocation of string + space. Fix this now by using a different variable to hold the + string size required for glibc-hwcaps. + + Signed-off-by: Javier Pello + (cherry picked from commit a23820f6052a740246fdc7dcd9c43ce8eed0c45a) + +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index e3c611e005ffbc0d..045911eb6d5d315a 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ + hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; +- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) ++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + + hwcaps_counts.total_length); + + /* Count the number of bits set in the masked value. */ +@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + assert (m == cnt); + + /* Determine the total size of all strings together. */ ++ size_t total; + if (cnt == 1) +- total += temp[0].len + 1; ++ total = temp[0].len + 1; + else + { +- total += temp[0].len + temp[cnt - 1].len + 2; ++ total = temp[0].len + temp[cnt - 1].len + 2; + if (cnt > 2) + { + total <<= 1; +@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* This is the overall result, including both glibc-hwcaps + subdirectories and the legacy hwcaps subdirectories using the + power set construction. */ ++ total += hwcaps_sz; + struct r_strlenpair *overall_result + = malloc (*sz * sizeof (*result) + total); + if (overall_result == NULL) diff --git a/glibc-upstream-2.34-315.patch b/glibc-upstream-2.34-315.patch new file mode 100644 index 0000000..89512a1 --- /dev/null +++ b/glibc-upstream-2.34-315.patch @@ -0,0 +1,62 @@ +commit f50a6c843a5b5186c0aa73747de033e08ef8246d +Author: Florian Weimer +Date: Tue Sep 20 12:12:43 2022 +0200 + + gconv: Use 64-bit interfaces in gconv_parseconfdir (bug 29583) + + It's possible that inode numbers are outside the 32-bit range. + The existing code only handles the in-libc case correctly, and + still uses the legacy interfaces when building iconv. + + Suggested-by: Helge Deller + (cherry picked from commit f97905f24631097af325d6a231093071c3077a5f) + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index 79398a980cde84e3..741cf7c67e36eccd 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -29,14 +29,14 @@ + # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) + # define asprintf __asprintf + # define opendir __opendir +-# define readdir __readdir ++# define readdir64 __readdir64 + # define closedir __closedir + # define mempcpy __mempcpy +-# define struct_stat struct __stat64_t64 +-# define lstat __lstat64_time64 ++# define struct_stat64 struct __stat64_t64 ++# define lstat64 __lstat64_time64 + # define feof_unlocked __feof_unlocked + #else +-# define struct_stat struct stat ++# define struct_stat64 struct stat64 + #endif + + /* Name of the file containing the module information in the directories +@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + DIR *confdir = opendir (buf); + if (confdir != NULL) + { +- struct dirent *ent; +- while ((ent = readdir (confdir)) != NULL) ++ struct dirent64 *ent; ++ while ((ent = readdir64 (confdir)) != NULL) + { + if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) + continue; +@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { + char *conf; +- struct_stat st; ++ struct_stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; + + if (ent->d_type != DT_UNKNOWN +- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) + found |= read_conf_file (conf, dir, dir_len); + + free (conf); diff --git a/glibc-upstream-2.34-316.patch b/glibc-upstream-2.34-316.patch new file mode 100644 index 0000000..6712840 --- /dev/null +++ b/glibc-upstream-2.34-316.patch @@ -0,0 +1,399 @@ +commit 1a3afdfe319a142228498f7a4ee82ac3917d97e8 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add tst-resolv-byaddr for testing reverse lookup + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 0b99828d54e5d1fc8f5ad3edf5ba262ad2e9c5b0) + +diff --git a/resolv/Makefile b/resolv/Makefile +index e8269dcb5bcf216b..78165eb99e98b525 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -92,6 +92,7 @@ tests += \ + tst-res_hnok \ + tst-resolv-basic \ + tst-resolv-binary \ ++ tst-resolv-byaddr \ + tst-resolv-edns \ + tst-resolv-network \ + tst-resolv-noaaaa \ +@@ -251,6 +252,7 @@ $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ + $(gen-locales) $(objpfx)tst-no-libidn2.so + $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so +diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c +new file mode 100644 +index 0000000000000000..6299e89837da58c6 +--- /dev/null ++++ b/resolv/tst-resolv-byaddr.c +@@ -0,0 +1,326 @@ ++/* Test reverse DNS lookup. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa. ++ CNAMES|ADDRESSES.2.0.192.in-addr-arpa. ++ ++ For the IPv4 reverse lookup, the address count is in the lower ++ bits. ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 15 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int addresses, cnames, bits; ++ char *tail; ++ if (strstr (qname, "ip6.arpa") != NULL ++ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2) ++ { ++ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa"); ++ addresses = bits & 0x0f; ++ cnames = bits >> 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ free (tail); ++ ++ int rcode; ++ if (addresses == 15) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60); ++ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example", ++ unique, cnames, addresses); ++ resolv_response_add_name (b, ptr); ++ free (ptr); ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Used to check that gethostbyaddr_r does not write past the buffer ++ end. */ ++static struct support_next_to_fault ntf; ++ ++/* Perform a gethostbyaddr call and check the result. */ ++static void ++check_gethostbyaddr (const char *address, const char *expected) ++{ ++ unsigned char bytes[16]; ++ unsigned int byteslen; ++ int family; ++ if (strchr (address, ':') != NULL) ++ { ++ family = AF_INET6; ++ byteslen = 16; ++ } ++ else ++ { ++ family = AF_INET; ++ byteslen = 4; ++ } ++ TEST_COMPARE (inet_pton (family, address, bytes), 1); ++ ++ struct hostent *e = gethostbyaddr (bytes, byteslen, family); ++ check_hostent (address, e, expected); ++ ++ if (e == NULL) ++ return; ++ ++ /* Try gethostbyaddr_r with increasing sizes until success. First ++ compute a reasonable minimum buffer size, to avoid many pointless ++ attempts. */ ++ size_t minimum_size = strlen (e->h_name); ++ for (int i = 0; e->h_addr_list[i] != NULL; ++i) ++ minimum_size += e->h_length + sizeof (char *); ++ for (int i = 0; e->h_aliases[i] != NULL; ++i) ++ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *); ++ ++ /* Gradually increase the size until success. */ ++ for (size_t size = minimum_size; size < ntf.length; ++size) ++ { ++ struct hostent result; ++ int herrno; ++ int ret = gethostbyaddr_r (bytes, byteslen, family, &result, ++ ntf.buffer + ntf.length - size, size, ++ &e, &herrno); ++ if (ret == ERANGE) ++ /* Retry with larger size. */ ++ TEST_COMPARE (herrno, NETDB_INTERNAL); ++ else if (ret == 0) ++ { ++ TEST_VERIFY (size > minimum_size); ++ check_hostent (address, e, expected); ++ return; ++ } ++ else ++ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret); ++ } ++ ++ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address); ++} ++ ++/* Perform a getnameinfo call and check the result. */ ++static void ++check_getnameinfo (const char *address, const char *expected) ++{ ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (strchr (address, ':') != NULL) ++ { ++ sin6.sin6_family = AF_INET6; ++ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ else ++ { ++ sin.sin_family = AF_INET; ++ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ switch (ret) ++ { ++ case 0: ++ TEST_COMPARE_STRING (host, expected); ++ TEST_COMPARE_STRING (service, "80"); ++ break; ++ case EAI_SYSTEM: ++ TEST_COMPARE_STRING (strerror (errno), expected); ++ break; ++ default: ++ TEST_COMPARE_STRING (gai_strerror (ret), expected); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Some reasonably upper bound for the maximum response size. */ ++ ntf = support_next_to_fault_allocate (4096); ++ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* No PTR record, RCODE=0. */ ++ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.0", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.16", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.32", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::10", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::20", "Name or service not known"); ++ ++ /* No PTR record, NXDOMAIN. */ ++ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.15", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.31", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.47", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::1f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::2f", "Name or service not known"); ++ ++ /* Actual response data. Only the first PTR record is returned. */ ++ check_gethostbyaddr ("192.0.2.1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 192.0.2.1\n"); ++ check_getnameinfo ("192.0.2.1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.17", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 192.0.2.17\n"); ++ check_getnameinfo ("192.0.2.17", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.18", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 192.0.2.18\n"); ++ check_getnameinfo ("192.0.2.18", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("192.0.2.33", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 192.0.2.33\n"); ++ check_getnameinfo ("192.0.2.33", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.34", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 192.0.2.34\n"); ++ check_getnameinfo ("192.0.2.34", ++ "unique-0.cnames-2.addresses-2.example"); ++ ++ /* Same for IPv6 addresses. */ ++ check_gethostbyaddr ("2001:db8::1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 2001:db8::1\n"); ++ check_getnameinfo ("2001:db8::1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::11", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 2001:db8::11\n"); ++ check_getnameinfo ("2001:db8::11", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::12", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 2001:db8::12\n"); ++ check_getnameinfo ("2001:db8::12", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("2001:db8::21", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 2001:db8::21\n"); ++ check_getnameinfo ("2001:db8::21", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::22", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 2001:db8::22\n"); ++ check_getnameinfo ("2001:db8::22", ++ "unique-0.cnames-2.addresses-2.example"); ++ } ++ ++ resolv_test_end (obj); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h +new file mode 100644 +index 0000000000000000..05725225af0818cb +--- /dev/null ++++ b/resolv/tst-resolv-maybe_insert_sig.h +@@ -0,0 +1,32 @@ ++/* Code snippet for optionally inserting ignored SIG records in resolver tests. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Set to true for an alternative pass that inserts (ignored) SIG ++ records. This does not alter the response, so this property is not ++ encoded in the QNAME. The variable needs to be volatile because ++ leaf attributes tell GCC that the response function is not ++ called. */ ++static volatile bool insert_sig; ++ ++static void ++maybe_insert_sig (struct resolv_response_builder *b, const char *owner) ++{ ++ resolv_response_open_record (b, owner, C_IN, T_SIG, 60); ++ resolv_response_add_data (b, "", 1); ++ resolv_response_close_record (b); ++} diff --git a/glibc-upstream-2.34-317.patch b/glibc-upstream-2.34-317.patch new file mode 100644 index 0000000..b99be70 --- /dev/null +++ b/glibc-upstream-2.34-317.patch @@ -0,0 +1,289 @@ +commit 6a833d798e87536587cd4cc14fe8d078f80b14a0 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add tst-resolv-aliases + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 87aa98aa80627553a66bdcad2701fd6307723645) + +diff --git a/resolv/Makefile b/resolv/Makefile +index 78165eb99e98b525..567f4c2dcf5749df 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -90,6 +90,7 @@ tests += \ + tst-ns_name_pton \ + tst-res_hconf_reorder \ + tst-res_hnok \ ++ tst-resolv-aliases \ + tst-resolv-basic \ + tst-resolv-binary \ + tst-resolv-byaddr \ +@@ -250,6 +251,7 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ + $(gen-locales) $(objpfx)tst-no-libidn2.so ++$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c +new file mode 100644 +index 0000000000000000..b212823aa07ceb21 +--- /dev/null ++++ b/resolv/tst-resolv-aliases.c +@@ -0,0 +1,254 @@ ++/* Test alias handling (mainly for gethostbyname). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ aADDRESSES-cCNAMES.example.net ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 255 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ if (qtype != T_A) ++ TEST_COMPARE (qtype, T_AAAA); ++ ++ unsigned int addresses, cnames; ++ char *tail; ++ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3) ++ { ++ if (strcmp (tail, ".example.com") == 0 ++ || strcmp (tail, ".example.net.example.net") == 0 ++ || strcmp (tail, ".example.net.example.com") == 0) ++ /* These only happen after NXDOMAIN. */ ++ TEST_VERIFY (addresses == 255); ++ else if (strcmp (tail, ".example.net") != 0) ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ } ++ free (tail); ++ ++ int rcode; ++ if (addresses == 255) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ ++ if (qtype == T_A) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + unique}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ else if (qtype == T_AAAA) ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 1 + unique ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++static char * ++make_qname (bool do_search, int cnames, int addresses) ++{ ++ return xasprintf ("a%d-c%d%s", ++ addresses, cnames, do_search ? "" : ".example.net"); ++} ++ ++static void ++check_cnames_failure (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ ++ if (addresses == 0) ++ check_hostent (qname, e, "error: NO_RECOVERY\n"); ++ else ++ check_hostent (qname, e, "error: HOST_NOT_FOUND\n"); ++ ++ free (qname); ++} ++ ++static void ++check (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ char *fqdn = make_qname (false, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ if (e == NULL) ++ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses); ++ ++ if (af == AF_UNSPEC || af == AF_INET) ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET); ++ TEST_COMPARE (e->h_length, 4); ++ } ++ else ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET6); ++ TEST_COMPARE (e->h_length, 16); ++ } ++ ++ for (int i = 0; i < addresses; ++i) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + i}; ++ char ipv6[16] = ++ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i }; ++ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6; ++ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length, ++ expected, e->h_length); ++ } ++ TEST_VERIFY (e->h_addr_list[addresses] == NULL); ++ ++ ++ if (cnames == 0) ++ { ++ /* QNAME is fully qualified. */ ++ TEST_COMPARE_STRING (e->h_name, fqdn); ++ TEST_VERIFY (e->h_aliases[0] == NULL); ++ } ++ else ++ { ++ /* Fully-qualified QNAME is demoted to an aliases. */ ++ TEST_COMPARE_STRING (e->h_aliases[0], fqdn); ++ ++ for (int i = 1; i <= cnames; ++i) ++ { ++ char *expected = xasprintf ("%d.alias.example", i - 1); ++ if (i == cnames) ++ TEST_COMPARE_STRING (e->h_name, expected); ++ else ++ TEST_COMPARE_STRING (e->h_aliases[i], expected); ++ free (expected); ++ } ++ TEST_VERIFY (e->h_aliases[cnames] == NULL); ++ } ++ ++ free (fqdn); ++ free (qname); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ .search = { "example.net", "example.com" }, ++ }); ++ ++ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 }; ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* If do_search is true, a bare host name (for example, a1-c1) ++ is used. This exercises search path processing and FQDN ++ qualification. */ ++ for (int do_search = 0; do_search < 2; ++do_search) ++ for (const int *paf = families; paf != array_end (families); ++paf) ++ { ++ for (int cnames = 0; cnames <= 100; ++cnames) ++ { ++ check_cnames_failure (*paf, do_search, cnames, 0); ++ /* Now with NXDOMAIN responses. */ ++ check_cnames_failure (*paf, do_search, cnames, 255); ++ } ++ ++ for (int cnames = 0; cnames <= 10; ++cnames) ++ for (int addresses = 1; addresses <= 10; ++addresses) ++ check (*paf, do_search, cnames, addresses); ++ ++ /* The current implementation is limited to 47 aliases. ++ Addresses do not have such a limit. */ ++ check (*paf, do_search, 47, 60); ++ } ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-318.patch b/glibc-upstream-2.34-318.patch new file mode 100644 index 0000000..0dd08c0 --- /dev/null +++ b/glibc-upstream-2.34-318.patch @@ -0,0 +1,58 @@ +commit 4d2e67d6e5c910114dbccd17d9b93f06552c0024 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add internal __res_binary_hnok function + + During package parsing, only the binary representation is available, + and it is convenient to check that directly for conformance with host + name requirements. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit c79327bf00a4be6d60259227acc78ef80ead3622) + +diff --git a/include/resolv.h b/include/resolv.h +index 3590b6f496d47710..4dbbac3800b7ef30 100644 +--- a/include/resolv.h ++++ b/include/resolv.h +@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery) + extern __typeof (__res_queriesmatch) __libc_res_queriesmatch; + libc_hidden_proto (__libc_res_queriesmatch) + ++/* Variant of res_hnok which operates on binary (but uncompressed) names. */ ++bool __res_binary_hnok (const unsigned char *dn) attribute_hidden; ++ + # endif /* _RESOLV_H_ && !_ISOMAC */ + #endif +diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c +index 2c603494fa3ca992..513ddb5f6b12ccb0 100644 +--- a/resolv/res-name-checking.c ++++ b/resolv/res-name-checking.c +@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn) + return dn[0] > 0 && dn[1] == '-'; + } + ++bool ++__res_binary_hnok (const unsigned char *dn) ++{ ++ return !binary_leading_dash (dn) && binary_hnok (dn); ++} ++ + /* Return 1 if res_hnok is a valid host name. Labels must only + contain [0-9a-zA-Z_-] characters, and the name must not start with + a '-'. The latter is to avoid confusion with program options. */ +@@ -145,11 +151,9 @@ int + ___res_hnok (const char *dn) + { + unsigned char buf[NS_MAXCDNAME]; +- if (!printable_string (dn) +- || __ns_name_pton (dn, buf, sizeof (buf)) < 0 +- || binary_leading_dash (buf)) +- return 0; +- return binary_hnok (buf); ++ return (printable_string (dn) ++ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0 ++ && __res_binary_hnok (buf)); + } + versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34); + versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE); diff --git a/glibc-upstream-2.34-319.patch b/glibc-upstream-2.34-319.patch new file mode 100644 index 0000000..e00dfbe --- /dev/null +++ b/glibc-upstream-2.34-319.patch @@ -0,0 +1,182 @@ +commit bb8adbba4f5d9237a144786ba8e504039beff161 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add the __ns_samebinaryname function + + During packet parsing, only the binary name is available. If the name + equality check is performed before conversion to text, we can sometimes + skip the last step. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 394085a34d25a51513019a4dc411acd3527fbd33) + +diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h +index 53f1dbc7c3f659e9..bb1dede187cf1500 100644 +--- a/include/arpa/nameser.h ++++ b/include/arpa/nameser.h +@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW; + int __ns_name_unpack (const unsigned char *, const unsigned char *, + const unsigned char *, unsigned char *, size_t) __THROW; + ++/* Like ns_samename, but for uncompressed binary names. Return true ++ if the two arguments compare are equal as case-insensitive domain ++ names. */ ++_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *) ++ attribute_hidden; ++ + #define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) + +diff --git a/resolv/Makefile b/resolv/Makefile +index 567f4c2dcf5749df..0b4fa30716af3b8a 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -46,6 +46,7 @@ routines := \ + ns_name_skip \ + ns_name_uncompress \ + ns_name_unpack \ ++ ns_samebinaryname \ + ns_samename \ + nsap_addr \ + nss_dns_functions \ +@@ -107,6 +108,10 @@ tests += \ + tests-internal += tst-resolv-txnid-collision + tests-static += tst-resolv-txnid-collision + ++# Likewise for __ns_samebinaryname. ++tests-internal += tst-ns_samebinaryname ++tests-static += tst-ns_samebinaryname ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c +new file mode 100644 +index 0000000000000000..9a47d8e97a84c759 +--- /dev/null ++++ b/resolv/ns_samebinaryname.c +@@ -0,0 +1,55 @@ ++/* Compare two binary domain names for quality. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Convert ASCII letters to upper case. */ ++static inline int ++ascii_toupper (unsigned char ch) ++{ ++ if (ch >= 'a' && ch <= 'z') ++ return ch - 'a' + 'A'; ++ else ++ return ch; ++} ++ ++bool ++__ns_samebinaryname (const unsigned char *a, const unsigned char *b) ++{ ++ while (*a != 0 && *b != 0) ++ { ++ if (*a != *b) ++ /* Different label length. */ ++ return false; ++ int labellen = *a; ++ ++a; ++ ++b; ++ for (int i = 0; i < labellen; ++i) ++ { ++ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b)) ++ /* Different character in label. */ ++ return false; ++ ++a; ++ ++b; ++ } ++ } ++ ++ /* Match if both names are at the root label. */ ++ return *a == 0 && *b == 0; ++} +diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c +new file mode 100644 +index 0000000000000000..b06ac610b4cde8be +--- /dev/null ++++ b/resolv/tst-ns_samebinaryname.c +@@ -0,0 +1,62 @@ ++/* Test the __ns_samebinaryname function. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* First character denotes the comparison group: All names with the ++ same first character are expected to compare equal. */ ++static const char *const cases[] = ++ { ++ " ", ++ "1\001a", "1\001A", ++ "2\002ab", "2\002aB", "2\002Ab", "2\002AB", ++ "3\001a\002ab", "3\001A\002ab", ++ "w\003www\007example\003com", "w\003Www\007Example\003Com", ++ "w\003WWW\007EXAMPLE\003COM", ++ "W\003WWW", "W\003www", ++ }; ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < array_length (cases); ++i) ++ for (int j = 0; j < array_length (cases); ++j) ++ { ++ unsigned char *a = (unsigned char *) &cases[i][1]; ++ unsigned char *b = (unsigned char *) &cases[j][1]; ++ bool actual = __ns_samebinaryname (a, b); ++ bool expected = cases[i][0] == cases[j][0]; ++ if (actual != expected) ++ { ++ char a1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0); ++ char b1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0); ++ printf ("error: \"%s\" \"%s\": expected %s\n", ++ a1, b1, expected ? "equal" : "unqueal"); ++ support_record_failure (); ++ } ++ } ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-320.patch b/glibc-upstream-2.34-320.patch new file mode 100644 index 0000000..617e31c --- /dev/null +++ b/glibc-upstream-2.34-320.patch @@ -0,0 +1,272 @@ +commit c288e032ae107c48679ef3c46fb84af6de0a6baf +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add internal __ns_name_length_uncompressed function + + This function is useful for checking that the question name is + uncompressed (as it should be). + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 78b1a4f0e49064e5dfb686c7cd87bd4df2640b29) + +diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h +index bb1dede187cf1500..6e4808f00d60caf9 100644 +--- a/include/arpa/nameser.h ++++ b/include/arpa/nameser.h +@@ -95,5 +95,13 @@ libc_hidden_proto (__ns_name_unpack) + extern __typeof (ns_samename) __libc_ns_samename; + libc_hidden_proto (__libc_ns_samename) + ++/* Packet parser helper functions. */ ++ ++/* Verify that P points to an uncompressed domain name in wire format. ++ On success, return the length of the encoded name, including the ++ terminating null byte. On failure, return -1 and set errno. EOM ++ must point one past the last byte in the packet. */ ++int __ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) attribute_hidden; + # endif /* !_ISOMAC */ + #endif +diff --git a/resolv/Makefile b/resolv/Makefile +index 0b4fa30716af3b8a..308f18622a04965a 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -40,6 +40,7 @@ routines := \ + inet_pton \ + ns_makecanon \ + ns_name_compress \ ++ ns_name_length_uncompressed \ + ns_name_ntop \ + ns_name_pack \ + ns_name_pton \ +@@ -112,6 +113,10 @@ tests-static += tst-resolv-txnid-collision + tests-internal += tst-ns_samebinaryname + tests-static += tst-ns_samebinaryname + ++# Likewise for __ns_name_length_uncompressed. ++tests-internal += tst-ns_name_length_uncompressed ++tests-static += tst-ns_name_length_uncompressed ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000000000..51296b47efbf1849 +--- /dev/null ++++ b/resolv/ns_name_length_uncompressed.c +@@ -0,0 +1,72 @@ ++/* Skip over an uncompressed name in wire format. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++int ++__ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) ++{ ++ const unsigned char *start = p; ++ ++ while (true) ++ { ++ if (p == eom) ++ { ++ /* Truncated packet: no room for label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ ++ unsigned char b = *p; ++ ++p; ++ if (b == 0) ++ { ++ /* Root label. */ ++ size_t length = p - start; ++ if (length > NS_MAXCDNAME) ++ { ++ /* Domain name too long. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ return length; ++ } ++ ++ if (b <= 63) ++ { ++ /* Regular label. */ ++ if (b <= eom - p) ++ p += b; ++ else ++ { ++ /* Truncated packet: label incomplete. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++ else ++ { ++ /* Compression reference or corrupted label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++} +diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000000000..c4a2904db75d1221 +--- /dev/null ++++ b/resolv/tst-ns_name_length_uncompressed.c +@@ -0,0 +1,135 @@ ++/* Test __ns_name_length_uncompressed. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Reference implementation based on other building blocks. */ ++static int ++reference_length (const unsigned char *p, const unsigned char *eom) ++{ ++ unsigned char buf[NS_MAXCDNAME]; ++ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf)); ++ if (n < 0) ++ return n; ++ const unsigned char *q = buf; ++ if (__ns_name_skip (&q, array_end (buf)) < 0) ++ return -1; ++ if (q - buf != n) ++ /* Compressed name. */ ++ return -1; ++ return n; ++} ++ ++static int ++do_test (void) ++{ ++ { ++ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 }; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), ++ sizeof (buf) - 2); ++ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1); ++ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1, ++ array_end (buf)), 1); ++ buf[4] = 0xc0; /* Forward compression reference. */ ++ buf[5] = 0x06; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), -1); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1); ++ } ++ ++ struct support_next_to_fault ntf = support_next_to_fault_allocate (300); ++ ++ /* Buffer region with all possible bytes at start and end. */ ++ for (int length = 1; length <= 300; ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memset (start, 'X', length); ++ for (int first = 0; first <= 255; ++first) ++ { ++ *start = first; ++ for (int last = 0; last <= 255; ++last) ++ { ++ start[length - 1] = last; ++ TEST_COMPARE (reference_length (start, end), ++ __ns_name_length_uncompressed (start, end)); ++ } ++ } ++ } ++ ++ /* Poor man's fuzz testing: patch two bytes. */ ++ { ++ unsigned char ref[] = ++ { ++ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0 ++ }; ++ TEST_COMPARE (reference_length (ref, array_end (ref)), 13); ++ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13); ++ ++ int good = 0; ++ int bad = 0; ++ for (int length = 1; length <= sizeof (ref); ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memcpy (start, ref, length); ++ ++ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos) ++ { ++ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value) ++ { ++ start[patch1_pos] = patch1_value; ++ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos) ++ { ++ for (int patch2_value = 0; patch2_value <= 255; ++ ++patch2_value) ++ { ++ start[patch2_pos] = patch2_value; ++ int expected = reference_length (start, end); ++ errno = EINVAL; ++ int actual ++ = __ns_name_length_uncompressed (start, end); ++ if (actual > 0) ++ ++good; ++ else ++ { ++ TEST_COMPARE (errno, EMSGSIZE); ++ ++bad; ++ } ++ TEST_COMPARE (expected, actual); ++ } ++ start[patch2_pos] = ref[patch2_pos]; ++ } ++ } ++ start[patch1_pos] = ref[patch1_pos]; ++ } ++ } ++ printf ("info: patched inputs with success: %d\n", good); ++ printf ("info: patched inputs with failure: %d\n", bad); ++ } ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-321.patch b/glibc-upstream-2.34-321.patch new file mode 100644 index 0000000..c32e7ce --- /dev/null +++ b/glibc-upstream-2.34-321.patch @@ -0,0 +1,532 @@ +commit e7c03f47651bd451ebf2c3c65899491d0bf7167e +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add DNS packet parsing helpers geared towards wire format + + The public parser functions around the ns_rr record type produce + textual domain names, but usually, this is not what we need while + parsing DNS packets within glibc. This commit adds two new helper + functions, __ns_rr_cursor_init and __ns_rr_cursor_next, for writing + packet parsers, and struct ns_rr_cursor, struct ns_rr_wire as + supporting types. + + In theory, it is possible to avoid copying the owner name + into the rname field in __ns_rr_cursor_next, but this would need + more functions that work on compressed names. + + Eventually, __res_context_send could be enhanced to preserve the + result of the packet parsing that is necessary for matching the + incoming UDP packets, so that this works does not have to be done + twice. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 857c890d9b42c50c8a94b76d47d4a61ab6d2f49c) + +diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h +index 6e4808f00d60caf9..c27e7886b7891997 100644 +--- a/include/arpa/nameser.h ++++ b/include/arpa/nameser.h +@@ -103,5 +103,97 @@ libc_hidden_proto (__libc_ns_samename) + must point one past the last byte in the packet. */ + int __ns_name_length_uncompressed (const unsigned char *p, + const unsigned char *eom) attribute_hidden; ++ ++/* Iterator over the resource records in a DNS packet. */ ++struct ns_rr_cursor ++{ ++ /* These members are not changed after initialization. */ ++ const unsigned char *begin; /* First byte of packet. */ ++ const unsigned char *end; /* One past the last byte of the packet. */ ++ const unsigned char *first_rr; /* First resource record (or packet end). */ ++ ++ /* Advanced towards the end while reading the packet. */ ++ const unsigned char *current; ++}; ++ ++/* Returns the RCODE field from the DNS header. */ ++static inline int ++ns_rr_cursor_rcode (const struct ns_rr_cursor *c) ++{ ++ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */ ++} ++ ++/* Returns the length of the answer section according to the DNS header. */ ++static inline int ++ns_rr_cursor_ancount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */ ++} ++ ++/* Returns the length of the authority (name server) section according ++ to the DNS header. */ ++static inline int ++ns_rr_cursor_nscount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */ ++} ++ ++/* Returns the length of the additional data section according to the ++ DNS header. */ ++static inline int ++ns_rr_cursor_adcount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */ ++} ++ ++/* Returns a pointer to the uncompressed question name in wire ++ format. */ ++static inline const unsigned char * ++ns_rr_cursor_qname (const struct ns_rr_cursor *c) ++{ ++ return c->begin + 12; /* QNAME starts right after the header. */ ++} ++ ++/* Returns the question type of the first and only question. */ ++static inline const int ++ns_rr_cursor_qtype (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 4 bytes back from the first RR header start. */ ++ return c->first_rr[-4] * 256 + c->first_rr[-3]; ++} ++ ++/* Returns the clss of the first and only question (usally C_IN). */ ++static inline const int ++ns_rr_cursor_qclass (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 2 bytes back from the first RR header start. */ ++ return c->first_rr[-2] * 256 + c->first_rr[-1]; ++} ++ ++/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false ++ if LEN is less than sizeof (*HD), if the packet does not contain a ++ full (uncompressed) question, or if the question count is not 1. */ ++_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++ attribute_hidden; ++ ++/* Like ns_rr, but the record owner name is not decoded into text format. */ ++struct ns_rr_wire ++{ ++ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */ ++ uint16_t rtype; /* Resource record type (T_*). */ ++ uint16_t rclass; /* Resource record class (C_*). */ ++ uint32_t ttl; /* Time-to-live field. */ ++ const unsigned char *rdata; /* Start of resource record data. */ ++ uint16_t rdlength; /* Length of the data at rdata, in bytes. */ ++}; ++ ++/* Attempts to parse the record at C into *RR. On success, return ++ true, and C is advanced past the record, and RR->rdata points to ++ the record data. On failure, errno is set to EMSGSIZE, and false ++ is returned. */ ++_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++ attribute_hidden; ++ + # endif /* !_ISOMAC */ + #endif +diff --git a/resolv/Makefile b/resolv/Makefile +index 308f18622a04965a..fded244d61068060 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -47,6 +47,8 @@ routines := \ + ns_name_skip \ + ns_name_uncompress \ + ns_name_unpack \ ++ ns_rr_cursor_init \ ++ ns_rr_cursor_next \ + ns_samebinaryname \ + ns_samename \ + nsap_addr \ +@@ -117,6 +119,10 @@ tests-static += tst-ns_samebinaryname + tests-internal += tst-ns_name_length_uncompressed + tests-static += tst-ns_name_length_uncompressed + ++# Likewise for struct ns_rr_cursor and its functions. ++tests-internal += tst-ns_rr_cursor ++tests-static += tst-ns_rr_cursor ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c +new file mode 100644 +index 0000000000000000..6ee80b30e927ecb7 +--- /dev/null ++++ b/resolv/ns_rr_cursor_init.c +@@ -0,0 +1,62 @@ ++/* Initialize a simple DNS packet parser. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++{ ++ c->begin = buf; ++ c->end = buf + len; ++ ++ /* Check for header size and 16-bit question count value (it must be 1). */ ++ if (len < 12 || buf[4] != 0 || buf[5] != 1) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ return false; ++ } ++ c->current = buf + 12; ++ ++ int consumed = __ns_name_length_uncompressed (c->current, c->end); ++ if (consumed < 0) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Ensure there is room for question type and class. */ ++ if (c->end - c->current < 4) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += 4; ++ c->first_rr = c->current; ++ ++ return true; ++} +diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c +new file mode 100644 +index 0000000000000000..33652fc5da322d69 +--- /dev/null ++++ b/resolv/ns_rr_cursor_next.c +@@ -0,0 +1,74 @@ ++/* Simple DNS record parser without textual name decoding. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++{ ++ rr->rdata = NULL; ++ ++ /* Extract the record owner name. */ ++ int consumed = __ns_name_unpack (c->begin, c->end, c->current, ++ rr->rname, sizeof (rr->rname)); ++ if (consumed < 0) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Extract the metadata. */ ++ struct ++ { ++ uint16_t rtype; ++ uint16_t rclass; ++ uint32_t ttl; ++ uint16_t rdlength; ++ } __attribute__ ((packed)) metadata; ++ _Static_assert (sizeof (metadata) == 10, "sizeof metadata"); ++ if (c->end - c->current < sizeof (metadata)) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ memcpy (&metadata, c->current, sizeof (metadata)); ++ c->current += sizeof (metadata); ++ /* Endianess conversion. */ ++ rr->rtype = ntohs (metadata.rtype); ++ rr->rclass = ntohs (metadata.rclass); ++ rr->ttl = ntohl (metadata.ttl); ++ rr->rdlength = ntohs (metadata.rdlength); ++ ++ /* Extract record data. */ ++ if (c->end - c->current < rr->rdlength) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ rr->rdata = c->current; ++ c->current += rr->rdlength; ++ ++ return true; ++} +diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c +new file mode 100644 +index 0000000000000000..c3c09089053d0c40 +--- /dev/null ++++ b/resolv/tst-ns_rr_cursor.c +@@ -0,0 +1,227 @@ ++/* Tests for resource record parsing. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Reference packet for packet parsing. */ ++static const unsigned char valid_packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x02, /* Answer count. */ ++ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */ ++ }; ++ ++/* Special offsets in valid_packet. */ ++enum ++ { ++ offset_of_first_record = 29, ++ offset_of_second_record = 57, ++ }; ++ ++/* Check that parsing valid_packet succeeds. */ ++static void ++test_valid (void) ++{ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet, ++ sizeof (valid_packet))); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - valid_packet, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - valid_packet, offset_of_second_record); ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x11335577); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" ++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16); ++ TEST_VERIFY (c.current == c.end); ++} ++ ++/* Check that trying to parse a packet with a compressed QNAME fails. */ ++static void ++test_compressed_qname (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Check that trying to parse a packet with two questions fails. */ ++static void ++test_two_questions (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x02, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Used to check that parsing truncated packets does not over-read. */ ++static struct support_next_to_fault ntf; ++ ++/* Truncated packet in the second resource record. */ ++static void ++test_truncated_one_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - start, offset_of_second_record); ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet in the first resource record. */ ++static void ++test_truncated_no_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet before first resource record. */ ++static void ++test_truncated_before_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length)); ++} ++ ++static int ++do_test (void) ++{ ++ ntf = support_next_to_fault_allocate (sizeof (valid_packet)); ++ ++ test_valid (); ++ test_compressed_qname (); ++ test_two_questions (); ++ ++ for (int length = offset_of_second_record; length < sizeof (valid_packet); ++ ++length) ++ test_truncated_one_rr (length); ++ for (int length = offset_of_first_record; length < offset_of_second_record; ++ ++length) ++ test_truncated_no_rr (length); ++ for (int length = 0; length < offset_of_first_record; ++length) ++ test_truncated_before_rr (length); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-322.patch b/glibc-upstream-2.34-322.patch new file mode 100644 index 0000000..f590d8e --- /dev/null +++ b/glibc-upstream-2.34-322.patch @@ -0,0 +1,447 @@ +commit d9c979abf9307ef3e27dbe65317430977bb322c7 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: Split getanswer_ptr from getanswer_r + + And expand the use of name_ok and qtype in getanswer_ptr (the + former also in getanswer_r). + + After further cleanups, not much code will be shared between the + two functions. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 0dcc43e9981005540bf39dc7bf33fbab62cf9e84) + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 6e83fca1c5b1f98c..a6bf73a091968358 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -117,6 +117,11 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, + struct hostent *result, char *buffer, + size_t buflen, int *errnop, int *h_errnop, + int map, int32_t *ttlp, char **canonp); ++static enum nss_status getanswer_ptr (const querybuf *answer, int anslen, ++ const char *qname, ++ struct hostent *result, char *buffer, ++ size_t buflen, int *errnop, ++ int *h_errnop, int32_t *ttlp); + + static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, + const querybuf *answer2, int anslen2, +@@ -562,9 +567,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + +- status = getanswer_r +- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, +- errnop, h_errnop, 0 /* XXX */, ttlp, NULL); ++ status = getanswer_ptr (host_buffer.buf, n, qbuf, result, ++ buffer, buflen, errnop, h_errnop, ttlp); + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + if (status != NSS_STATUS_SUCCESS) +@@ -660,8 +664,6 @@ getanswer_r (struct resolv_context *ctx, + int haveanswer, had_error; + char *bp, **ap, **hap; + char tbuf[MAXDNAME]; +- const char *tname; +- int (*name_ok) (const char *); + u_char packtmp[NS_MAXCDNAME]; + int have_to_map = 0; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +@@ -680,22 +682,8 @@ getanswer_r (struct resolv_context *ctx, + if (buflen - sizeof (struct host_data) != linebuflen) + linebuflen = INT_MAX; + +- tname = qname; + result->h_name = NULL; + end_of_message = answer->buf + anslen; +- switch (qtype) +- { +- case T_A: +- case T_AAAA: +- name_ok = __libc_res_hnok; +- break; +- case T_PTR: +- name_ok = __libc_res_dnok; +- break; +- default: +- *errnop = ENOENT; +- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ +- } + + /* + * find first satisfactory answer +@@ -730,7 +718,7 @@ getanswer_r (struct resolv_context *ctx, + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- if (__glibc_unlikely (name_ok (bp) == 0)) ++ if (__glibc_unlikely (__libc_res_hnok (bp) == 0)) + { + errno = EBADMSG; + *errnop = EBADMSG; +@@ -784,7 +772,7 @@ getanswer_r (struct resolv_context *ctx, + n = -1; + } + +- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0)) ++ if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) + { + ++had_error; + continue; +@@ -817,7 +805,7 @@ getanswer_r (struct resolv_context *ctx, + continue; /* XXX - had_error++ ? */ + } + +- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) ++ if (type == T_CNAME) + { + /* A CNAME could also have a TTL entry. */ + if (ttlp != NULL && ttl < *ttlp) +@@ -827,7 +815,7 @@ getanswer_r (struct resolv_context *ctx, + continue; + n = __libc_dn_expand (answer->buf, end_of_message, cp, + tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0)) ++ if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) + { + ++had_error; + continue; +@@ -858,7 +846,260 @@ getanswer_r (struct resolv_context *ctx, + continue; + } + +- if (qtype == T_PTR && type == T_CNAME) ++ if (type == T_A && qtype == T_AAAA && map) ++ have_to_map = 1; ++ else if (__glibc_unlikely (type != qtype)) ++ { ++ cp += n; ++ continue; /* XXX - had_error++ ? */ ++ } ++ ++ switch (type) ++ { ++ case T_A: ++ case T_AAAA: ++ if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) ++ { ++ cp += n; ++ continue; /* XXX - had_error++ ? */ ++ } ++ ++ /* Stop parsing at a record whose length is incorrect. */ ++ if (n != rrtype_to_rdata_length (type)) ++ { ++ ++had_error; ++ break; ++ } ++ ++ /* Skip records of the wrong type. */ ++ if (n != result->h_length) ++ { ++ cp += n; ++ continue; ++ } ++ if (!haveanswer) ++ { ++ int nn; ++ ++ /* We compose a single hostent out of the entire chain of ++ entries, so the TTL of the hostent is essentially the lowest ++ TTL in the chain. */ ++ if (ttlp != NULL && ttl < *ttlp) ++ *ttlp = ttl; ++ if (canonp != NULL) ++ *canonp = bp; ++ result->h_name = bp; ++ nn = strlen (bp) + 1; /* for the \0 */ ++ bp += nn; ++ linebuflen -= nn; ++ } ++ ++ /* Provide sufficient alignment for both address ++ families. */ ++ enum { align = 4 }; ++ _Static_assert ((align % __alignof__ (struct in_addr)) == 0, ++ "struct in_addr alignment"); ++ _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, ++ "struct in6_addr alignment"); ++ { ++ char *new_bp = PTR_ALIGN_UP (bp, align); ++ linebuflen -= new_bp - bp; ++ bp = new_bp; ++ } ++ ++ if (__glibc_unlikely (n > linebuflen)) ++ goto too_small; ++ bp = __mempcpy (*hap++ = bp, cp, n); ++ cp += n; ++ linebuflen -= n; ++ break; ++ default: ++ abort (); ++ } ++ if (had_error == 0) ++ ++haveanswer; ++ } ++ ++ if (haveanswer > 0) ++ { ++ *ap = NULL; ++ *hap = NULL; ++ /* ++ * Note: we sort even if host can take only one address ++ * in its return structures - should give it the "best" ++ * address in that case, not some random one ++ */ ++ if (haveanswer > 1 && qtype == T_A ++ && __resolv_context_sort_count (ctx) > 0) ++ addrsort (ctx, host_data->h_addr_ptrs, haveanswer); ++ ++ if (result->h_name == NULL) ++ { ++ n = strlen (qname) + 1; /* For the \0. */ ++ if (n > linebuflen) ++ goto too_small; ++ if (n >= MAXHOSTNAMELEN) ++ goto no_recovery; ++ result->h_name = bp; ++ bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ ++ linebuflen -= n; ++ } ++ ++ if (have_to_map) ++ if (map_v4v6_hostent (result, &bp, &linebuflen)) ++ goto too_small; ++ *h_errnop = NETDB_SUCCESS; ++ return NSS_STATUS_SUCCESS; ++ } ++ no_recovery: ++ *h_errnop = NO_RECOVERY; ++ *errnop = ENOENT; ++ /* 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 ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases ++ ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); ++} ++ ++static enum nss_status ++getanswer_ptr (const querybuf *answer, int anslen, const char *qname, ++ struct hostent *result, char *buffer, size_t buflen, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct host_data ++ { ++ char *aliases[MAX_NR_ALIASES]; ++ unsigned char host_addr[16]; /* IPv4 or IPv6 */ ++ char *h_addr_ptrs[0]; ++ } *host_data; ++ int linebuflen; ++ const HEADER *hp; ++ const u_char *end_of_message, *cp; ++ int n, ancount, qdcount; ++ int haveanswer, had_error; ++ char *bp, **ap, **hap; ++ char tbuf[MAXDNAME]; ++ const char *tname; ++ u_char packtmp[NS_MAXCDNAME]; ++ uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); ++ buffer += pad; ++ buflen = buflen > pad ? buflen - pad : 0; ++ if (__glibc_unlikely (buflen < sizeof (struct host_data))) ++ { ++ /* The buffer is too small. */ ++ too_small: ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ host_data = (struct host_data *) buffer; ++ linebuflen = buflen - sizeof (struct host_data); ++ if (buflen - sizeof (struct host_data) != linebuflen) ++ linebuflen = INT_MAX; ++ ++ tname = qname; ++ result->h_name = NULL; ++ end_of_message = answer->buf + anslen; ++ ++ /* ++ * find first satisfactory answer ++ */ ++ hp = &answer->hdr; ++ ancount = ntohs (hp->ancount); ++ qdcount = ntohs (hp->qdcount); ++ cp = answer->buf + HFIXEDSZ; ++ if (__glibc_unlikely (qdcount != 1)) ++ { ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) ++ goto too_small; ++ bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; ++ linebuflen -= (ancount + 1) * sizeof (char *); ++ ++ n = __ns_name_unpack (answer->buf, end_of_message, cp, ++ packtmp, sizeof packtmp); ++ if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ { ++ if (__glibc_unlikely (errno == EMSGSIZE)) ++ goto too_small; ++ ++ n = -1; ++ } ++ ++ if (__glibc_unlikely (n < 0)) ++ { ++ *errnop = errno; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ if (__glibc_unlikely (__libc_res_dnok (bp) == 0)) ++ { ++ errno = EBADMSG; ++ *errnop = EBADMSG; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ cp += n + QFIXEDSZ; ++ ++ ap = host_data->aliases; ++ *ap = NULL; ++ result->h_aliases = host_data->aliases; ++ hap = host_data->h_addr_ptrs; ++ *hap = NULL; ++ result->h_addr_list = host_data->h_addr_ptrs; ++ haveanswer = 0; ++ had_error = 0; ++ ++ while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ { ++ int type, class; ++ ++ n = __ns_name_unpack (answer->buf, end_of_message, cp, ++ packtmp, sizeof packtmp); ++ if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ { ++ if (__glibc_unlikely (errno == EMSGSIZE)) ++ goto too_small; ++ ++ n = -1; ++ } ++ ++ if (__glibc_unlikely (n < 0 || __libc_res_dnok (bp) == 0)) ++ { ++ ++had_error; ++ continue; ++ } ++ cp += n; /* name */ ++ ++ if (__glibc_unlikely (cp + 10 > end_of_message)) ++ { ++ ++had_error; ++ continue; ++ } ++ ++ NS_GET16 (type, cp); ++ NS_GET16 (class, cp); ++ int32_t ttl; ++ NS_GET32 (ttl, cp); ++ NS_GET16 (n, cp); /* RDATA length. */ ++ ++ if (end_of_message - cp < n) ++ { ++ /* RDATA extends beyond the end of the packet. */ ++ ++had_error; ++ continue; ++ } ++ ++ if (__glibc_unlikely (class != C_IN)) ++ { ++ /* XXX - debug? syslog? */ ++ cp += n; ++ continue; /* XXX - had_error++ ? */ ++ } ++ ++ if (type == T_CNAME) + { + /* A CNAME could also have a TTL entry. */ + if (ttlp != NULL && ttl < *ttlp) +@@ -887,14 +1128,6 @@ getanswer_r (struct resolv_context *ctx, + continue; + } + +- if (type == T_A && qtype == T_AAAA && map) +- have_to_map = 1; +- else if (__glibc_unlikely (type != qtype)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- + switch (type) + { + case T_PTR: +@@ -956,8 +1189,6 @@ getanswer_r (struct resolv_context *ctx, + TTL in the chain. */ + if (ttlp != NULL && ttl < *ttlp) + *ttlp = ttl; +- if (canonp != NULL) +- *canonp = bp; + result->h_name = bp; + nn = strlen (bp) + 1; /* for the \0 */ + bp += nn; +@@ -984,7 +1215,8 @@ getanswer_r (struct resolv_context *ctx, + linebuflen -= n; + break; + default: +- abort (); ++ cp += n; ++ continue; /* XXX - had_error++ ? */ + } + if (had_error == 0) + ++haveanswer; +@@ -994,14 +1226,6 @@ getanswer_r (struct resolv_context *ctx, + { + *ap = NULL; + *hap = NULL; +- /* +- * Note: we sort even if host can take only one address +- * in its return structures - should give it the "best" +- * address in that case, not some random one +- */ +- if (haveanswer > 1 && qtype == T_A +- && __resolv_context_sort_count (ctx) > 0) +- addrsort (ctx, host_data->h_addr_ptrs, haveanswer); + + if (result->h_name == NULL) + { +@@ -1015,23 +1239,15 @@ getanswer_r (struct resolv_context *ctx, + linebuflen -= n; + } + +- if (have_to_map) +- if (map_v4v6_hostent (result, &bp, &linebuflen)) +- goto too_small; + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } + no_recovery: + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; +- /* 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 ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases +- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); ++ return NSS_STATUS_TRYAGAIN; + } + +- + static enum nss_status + gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + struct gaih_addrtuple ***patp, diff --git a/glibc-upstream-2.34-323.patch b/glibc-upstream-2.34-323.patch new file mode 100644 index 0000000..9e00022 --- /dev/null +++ b/glibc-upstream-2.34-323.patch @@ -0,0 +1,507 @@ +commit 32e5db37684ffcbc6ae34fcc6cdcf28670506baa +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: Rewrite _nss_dns_gethostbyaddr2_r and getanswer_ptr + + The simplification takes advantage of the split from getanswer_r. + It fixes various aliases issues, and optimizes NSS buffer usage. + The new DNS packet parsing helpers are used, too. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit e32547d661a43da63368e488b6cfa9c53b4dcf92) + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index a6bf73a091968358..2cd7170f20b60588 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -70,6 +70,7 @@ + * --Copyright-- + */ + ++#include + #include + #include + #include +@@ -117,10 +118,9 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, + struct hostent *result, char *buffer, + size_t buflen, int *errnop, int *h_errnop, + int map, int32_t *ttlp, char **canonp); +-static enum nss_status getanswer_ptr (const querybuf *answer, int anslen, +- const char *qname, +- struct hostent *result, char *buffer, +- size_t buflen, int *errnop, ++static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ char **hnamep, int *errnop, + int *h_errnop, int32_t *ttlp); + + static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, +@@ -457,36 +457,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + static const u_char v6local[] = { 0,0, 0,1 }; + const u_char *uaddr = (const u_char *)addr; +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[MAX_NR_ADDRS + 1]; +- char linebuffer[0]; +- } *host_data = (struct host_data *) buffer; +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char qbuf[MAXDNAME+1], *qp = NULL; + size_t size; + int n, status; + int olderr = errno; + +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- host_data = (struct host_data *) buffer; ++ /* Prepare the allocation buffer. Store the pointer array first, to ++ benefit from buffer alignment. */ ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); ++ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); ++ if (address_array == NULL) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } + + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) +@@ -530,8 +515,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + return NSS_STATUS_UNAVAIL; + } + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); +- + switch (af) + { + case AF_INET: +@@ -555,35 +538,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + break; + } + +- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; ++ n = __res_context_query (ctx, qbuf, C_IN, T_PTR, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, ++ NULL, NULL, NULL, NULL); + if (n < 0) + { + *h_errnop = h_errno; + __set_errno (olderr); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + __resolv_context_put (ctx); + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + +- status = getanswer_ptr (host_buffer.buf, n, qbuf, result, +- buffer, buflen, errnop, h_errnop, ttlp); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ status = getanswer_ptr (alt_dns_packet_buffer, n, ++ &abuf, &result->h_name, errnop, h_errnop, ttlp); ++ ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); ++ __resolv_context_put (ctx); ++ + if (status != NSS_STATUS_SUCCESS) +- { +- __resolv_context_put (ctx); +- return status; +- } ++ return status; + ++ /* result->h_name has already been set by getanswer_ptr. */ + result->h_addrtype = af; + result->h_length = len; +- memcpy (host_data->host_addr, addr, len); +- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; +- host_data->h_addr_ptrs[1] = NULL; ++ /* Increase the alignment to 4, in case there are applications out ++ there that expect at least this level of address alignment. */ ++ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); ++ alloc_buffer_copy_bytes (&abuf, uaddr, len); ++ address_array[1] = NULL; ++ ++ /* This check also covers allocation failure in getanswer_ptr. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ result->h_addr_list = address_array; ++ result->h_aliases = &address_array[1]; /* Points to NULL. */ ++ + *h_errnop = NETDB_SUCCESS; +- __resolv_context_put (ctx); + return NSS_STATUS_SUCCESS; + } + libc_hidden_def (_nss_dns_gethostbyaddr2_r) +@@ -962,287 +962,86 @@ getanswer_r (struct resolv_context *ctx, + } + + static enum nss_status +-getanswer_ptr (const querybuf *answer, int anslen, const char *qname, +- struct hostent *result, char *buffer, size_t buflen, ++getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, char **hnamep, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[0]; +- } *host_data; +- int linebuflen; +- const HEADER *hp; +- const u_char *end_of_message, *cp; +- int n, ancount, qdcount; +- int haveanswer, had_error; +- char *bp, **ap, **hap; +- char tbuf[MAXDNAME]; +- const char *tname; +- u_char packtmp[NS_MAXCDNAME]; +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- /* The buffer is too small. */ +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- host_data = (struct host_data *) buffer; +- linebuflen = buflen - sizeof (struct host_data); +- if (buflen - sizeof (struct host_data) != linebuflen) +- linebuflen = INT_MAX; +- +- tname = qname; +- result->h_name = NULL; +- end_of_message = answer->buf + anslen; +- +- /* +- * find first satisfactory answer +- */ +- hp = &answer->hdr; +- ancount = ntohs (hp->ancount); +- qdcount = ntohs (hp->qdcount); +- cp = answer->buf + HFIXEDSZ; +- if (__glibc_unlikely (qdcount != 1)) +- { +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) +- goto too_small; +- bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; +- linebuflen -= (ancount + 1) * sizeof (char *); +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) +- { +- *errnop = errno; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (__glibc_unlikely (__libc_res_dnok (bp) == 0)) +- { +- errno = EBADMSG; +- *errnop = EBADMSG; ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- cp += n + QFIXEDSZ; ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; + +- ap = host_data->aliases; +- *ap = NULL; +- result->h_aliases = host_data->aliases; +- hap = host_data->h_addr_ptrs; +- *hap = NULL; +- result->h_addr_list = host_data->h_addr_ptrs; +- haveanswer = 0; +- had_error = 0; +- +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ while (ancount > 0) + { +- int type, class; +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0 || __libc_res_dnok (bp) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; /* name */ +- +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- NS_GET16 (type, cp); +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- if (end_of_message - cp < n) +- { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } +- +- if (__glibc_unlikely (class != C_IN)) +- { +- /* XXX - debug? syslog? */ +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- if (type == T_CNAME) ++ if (rr.rtype == T_CNAME) + { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- tname = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; ++ expected_name = name_buffer; + } +- +- switch (type) ++ else if (rr.rtype == T_PTR ++ && __ns_samebinaryname (rr.rname, expected_name)) + { +- case T_PTR: +- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) ++ /* Decompress the target of the PTR record. This is the ++ host name we are looking for. We can only use it if it ++ is syntactically valid. Historically, only one host name ++ is returned here. If the recursive resolver performs DNS ++ record rotation, the returned host name is essentially ++ random, which is why multiple PTR records are rarely ++ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for ++ additional length checking. */ ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)) < 0 ++ || !__res_binary_hnok (expected_name) ++ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) + { +- ++had_error; +- break; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- /* bind would put multiple PTR records as aliases, but we don't do +- that. */ +- result->h_name = bp; +- *h_errnop = NETDB_SUCCESS; ++ /* Successful allocation is checked by the caller. */ ++ *hnamep = alloc_buffer_copy_string (abuf, hname); + return NSS_STATUS_SUCCESS; +- case T_A: +- case T_AAAA: +- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- /* Stop parsing at a record whose length is incorrect. */ +- if (n != rrtype_to_rdata_length (type)) +- { +- ++had_error; +- break; +- } +- +- /* Skip records of the wrong type. */ +- if (n != result->h_length) +- { +- cp += n; +- continue; +- } +- if (!haveanswer) +- { +- int nn; +- +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- result->h_name = bp; +- nn = strlen (bp) + 1; /* for the \0 */ +- bp += nn; +- linebuflen -= nn; +- } +- +- /* Provide sufficient alignment for both address +- families. */ +- enum { align = 4 }; +- _Static_assert ((align % __alignof__ (struct in_addr)) == 0, +- "struct in_addr alignment"); +- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, +- "struct in6_addr alignment"); +- { +- char *new_bp = PTR_ALIGN_UP (bp, align); +- linebuflen -= new_bp - bp; +- bp = new_bp; +- } +- +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- bp = __mempcpy (*hap++ = bp, cp, n); +- cp += n; +- linebuflen -= n; +- break; +- default: +- cp += n; +- continue; /* XXX - had_error++ ? */ + } +- if (had_error == 0) +- ++haveanswer; + } + +- if (haveanswer > 0) +- { +- *ap = NULL; +- *hap = NULL; +- +- if (result->h_name == NULL) +- { +- n = strlen (qname) + 1; /* For the \0. */ +- if (n > linebuflen) +- goto too_small; +- if (n >= MAXHOSTNAMELEN) +- goto no_recovery; +- result->h_name = bp; +- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ +- linebuflen -= n; +- } ++ /* No PTR record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + +- *h_errnop = NETDB_SUCCESS; +- return NSS_STATUS_SUCCESS; +- } +- no_recovery: + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; + return NSS_STATUS_TRYAGAIN; diff --git a/glibc-upstream-2.34-324.patch b/glibc-upstream-2.34-324.patch new file mode 100644 index 0000000..b77de6e --- /dev/null +++ b/glibc-upstream-2.34-324.patch @@ -0,0 +1,311 @@ +commit 7267341ec1b5c591c2e7946d0604d3cf1423db7d +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: Remove remnants of IPv6 address mapping + + res_use_inet6 always returns false since commit 3f8b44be0a658266adff5 + ("resolv: Remove support for RES_USE_INET6 and the inet6 option"). + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit a7fc30b522a0cd7c8c5e7e285b9531b704e02f04) + +diff --git a/resolv/README b/resolv/README +index 514e9bb617e710f1..2146bc3b27a6dc56 100644 +--- a/resolv/README ++++ b/resolv/README +@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c. + + res_hconf.c and res_hconf.h were contributed by David Mosberger, and + do not come from BIND. +- +-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are +-leftovers from BIND 4.9.7. +diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h +deleted file mode 100644 +index 7f85f7d5e393ec5f..0000000000000000 +--- a/resolv/mapv4v6addr.h ++++ /dev/null +@@ -1,69 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-static void +-map_v4v6_address (const char *src, char *dst) +-{ +- u_char *p = (u_char *) dst; +- int i; +- +- /* Move the IPv4 part to the right position. */ +- memcpy (dst + 12, src, INADDRSZ); +- +- /* Mark this ipv6 addr as a mapped ipv4. */ +- for (i = 0; i < 10; i++) +- *p++ = 0x00; +- *p++ = 0xff; +- *p = 0xff; +-} +diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h +deleted file mode 100644 +index c11038adf33f154d..0000000000000000 +--- a/resolv/mapv4v6hostent.h ++++ /dev/null +@@ -1,84 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-typedef union { +- int32_t al; +- char ac; +-} align; +- +-static int +-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp) +-{ +- char **ap; +- +- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) +- return 0; +- hp->h_addrtype = AF_INET6; +- hp->h_length = IN6ADDRSZ; +- for (ap = hp->h_addr_list; *ap; ap++) +- { +- int i = sizeof (align) - ((u_long) *bpp % sizeof (align)); +- +- if (*lenp < (i + IN6ADDRSZ)) +- /* Out of memory. */ +- return 1; +- *bpp += i; +- *lenp -= i; +- map_v4v6_address (*ap, *bpp); +- *ap = *bpp; +- *bpp += IN6ADDRSZ; +- *lenp -= IN6ADDRSZ; +- } +- return 0; +-} +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 2cd7170f20b60588..f8dc5a0a7d1eb156 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -88,10 +88,6 @@ + #include + #include + +-/* Get implementations of some internal functions. */ +-#include +-#include +- + #define RESOLVSORT + + #if PACKETSZ > 65536 +@@ -117,7 +113,7 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, + const char *qname, int qtype, + struct hostent *result, char *buffer, + size_t buflen, int *errnop, int *h_errnop, +- int map, int32_t *ttlp, char **canonp); ++ int32_t *ttlp, char **canonp); + static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, + char **hnamep, int *errnop, +@@ -198,7 +194,6 @@ gethostbyname3_context (struct resolv_context *ctx, + char tmp[NS_MAXDNAME]; + int size, type, n; + const char *cp; +- int map = 0; + int olderr = errno; + enum nss_status status; + +@@ -259,32 +254,12 @@ gethostbyname3_context (struct resolv_context *ctx, + *errnop = EAGAIN; + else + __set_errno (olderr); +- +- /* If we are looking for an IPv6 address and mapping is enabled +- by having the RES_USE_INET6 bit in _res.options set, we try +- another lookup. */ +- if (af == AF_INET6 && res_use_inet6 ()) +- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, +- host_buffer.buf != orig_host_buffer +- ? MAXPACKET : 1024, &host_buffer.ptr, +- NULL, NULL, NULL, NULL); +- +- if (n < 0) +- { +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); +- return status; +- } +- +- map = 1; +- +- result->h_addrtype = AF_INET; +- result->h_length = INADDRSZ; + } ++ else ++ status = getanswer_r ++ (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, ++ errnop, h_errnop, ttlp, canonp); + +- status = getanswer_r +- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, +- errnop, h_errnop, map, ttlp, canonp); + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + return status; +@@ -330,13 +305,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } +- status = NSS_STATUS_NOTFOUND; +- if (res_use_inet6 ()) +- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); +- if (status == NSS_STATUS_NOTFOUND) +- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); ++ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, ++ buflen, errnop, h_errnop, NULL, NULL); + __resolv_context_put (ctx); + return status; + } +@@ -649,7 +619,7 @@ static enum nss_status + getanswer_r (struct resolv_context *ctx, + const querybuf *answer, int anslen, const char *qname, int qtype, + struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) ++ int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) + { + struct host_data + { +@@ -665,7 +635,6 @@ getanswer_r (struct resolv_context *ctx, + char *bp, **ap, **hap; + char tbuf[MAXDNAME]; + u_char packtmp[NS_MAXCDNAME]; +- int have_to_map = 0; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; +@@ -846,9 +815,7 @@ getanswer_r (struct resolv_context *ctx, + continue; + } + +- if (type == T_A && qtype == T_AAAA && map) +- have_to_map = 1; +- else if (__glibc_unlikely (type != qtype)) ++ if (__glibc_unlikely (type != qtype)) + { + cp += n; + continue; /* XXX - had_error++ ? */ +@@ -945,9 +912,6 @@ getanswer_r (struct resolv_context *ctx, + linebuflen -= n; + } + +- if (have_to_map) +- if (map_v4v6_hostent (result, &bp, &linebuflen)) +- goto too_small; + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } diff --git a/glibc-upstream-2.34-325.patch b/glibc-upstream-2.34-325.patch new file mode 100644 index 0000000..7a282c5 --- /dev/null +++ b/glibc-upstream-2.34-325.patch @@ -0,0 +1,565 @@ +commit 9abc40d9b514fc51cd1a052d32d092a827c6e21a +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: Rewrite getanswer_r to match getanswer_ptr (bug 12154, bug 29305) + + Allocate the pointer arrays only at the end, when their sizes + are known. This addresses bug 29305. + + Skip over invalid names instead of failing lookups. This partially + fixes bug 12154 (for gethostbyname, fixing getaddrinfo requires + different changes). + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit d101d836e7e4bd1d4e4972b0e0bd0a55c9b650fa) + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index f8dc5a0a7d1eb156..10c21e1e827cde12 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -108,12 +108,19 @@ typedef union querybuf + u_char buf[MAXPACKET]; + } querybuf; + +-static enum nss_status getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, +- const char *qname, int qtype, +- struct hostent *result, char *buffer, +- size_t buflen, int *errnop, int *h_errnop, +- int32_t *ttlp, char **canonp); ++/* For historic reasons, pointers to IP addresses are char *, so use a ++ single list type for addresses and host names. */ ++#define DYNARRAY_STRUCT ptrlist ++#define DYNARRAY_ELEMENT char * ++#define DYNARRAY_PREFIX ptrlist_ ++#include ++ ++static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, ++ uint16_t qtype, struct alloc_buffer *abuf, ++ struct ptrlist *addresses, ++ struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp); ++static void addrsort (struct resolv_context *ctx, char **ap, int num); + static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, + struct alloc_buffer *abuf, + char **hnamep, int *errnop, +@@ -185,12 +192,6 @@ gethostbyname3_context (struct resolv_context *ctx, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp) + { +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char tmp[NS_MAXDNAME]; + int size, type, n; + const char *cp; +@@ -224,10 +225,12 @@ gethostbyname3_context (struct resolv_context *ctx, + && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) + name = cp; + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + +- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ n = __res_context_search (ctx, name, C_IN, type, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n < 0) + { + switch (errno) +@@ -256,12 +259,77 @@ gethostbyname3_context (struct resolv_context *ctx, + __set_errno (olderr); + } + else +- status = getanswer_r +- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, +- errnop, h_errnop, ttlp, canonp); ++ { ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ struct ptrlist addresses; ++ ptrlist_init (&addresses); ++ struct ptrlist aliases; ++ ptrlist_init (&aliases); ++ ++ status = getanswer_r (alt_dns_packet_buffer, n, type, ++ &abuf, &addresses, &aliases, ++ errnop, h_errnop, ttlp); ++ if (status == NSS_STATUS_SUCCESS) ++ { ++ if (ptrlist_has_failed (&addresses) ++ || ptrlist_has_failed (&aliases)) ++ { ++ /* malloc failure. Do not retry using the ERANGE protocol. */ ++ *errnop = ENOMEM; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_UNAVAIL; ++ } ++ ++ /* Reserve the address and alias arrays in the result ++ buffer. Both are NULL-terminated, but the first element ++ of the alias array is stored in h_name, so no extra space ++ for the NULL terminator is needed there. */ ++ result->h_addr_list ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&addresses) + 1); ++ result->h_aliases ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&aliases)); ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ /* Retry using the ERANGE protocol. */ ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { ++ /* Copy the address list and NULL-terminate it. */ ++ memcpy (result->h_addr_list, ptrlist_begin (&addresses), ++ ptrlist_size (&addresses) * sizeof (char *)); ++ result->h_addr_list[ptrlist_size (&addresses)] = NULL; ++ ++ /* Sort the address list if requested. */ ++ if (type == T_A && __resolv_context_sort_count (ctx) > 0) ++ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); ++ ++ /* Copy the aliases, excluding the last one. */ ++ memcpy (result->h_aliases, ptrlist_begin (&aliases), ++ (ptrlist_size (&aliases) - 1) * sizeof (char *)); ++ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; ++ ++ /* The last alias goes into h_name. */ ++ assert (ptrlist_size (&aliases) >= 1); ++ result->h_name = ptrlist_end (&aliases)[-1]; ++ ++ /* This is also the canonical name. */ ++ if (canonp != NULL) ++ *canonp = result->h_name; ++ } ++ } ++ ++ ptrlist_free (&aliases); ++ ptrlist_free (&addresses); ++ } ++ ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + return status; + } + +@@ -615,314 +683,128 @@ addrsort (struct resolv_context *ctx, char **ap, int num) + break; + } + +-static enum nss_status +-getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, const char *qname, int qtype, +- struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) ++/* Convert the uncompressed, binary domain name CDNAME into its ++ textual representation and add it to the end of ALIASES, allocating ++ space for a copy of the name from ABUF. Skip adding the name if it ++ is not a valid host name, and return false in that case, otherwise ++ true. */ ++static bool ++getanswer_r_store_alias (const unsigned char *cdname, ++ struct alloc_buffer *abuf, ++ struct ptrlist *aliases) + { +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[0]; +- } *host_data; +- int linebuflen; +- const HEADER *hp; +- const u_char *end_of_message, *cp; +- int n, ancount, qdcount; +- int haveanswer, had_error; +- char *bp, **ap, **hap; +- char tbuf[MAXDNAME]; +- u_char packtmp[NS_MAXCDNAME]; +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- /* The buffer is too small. */ +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- host_data = (struct host_data *) buffer; +- linebuflen = buflen - sizeof (struct host_data); +- if (buflen - sizeof (struct host_data) != linebuflen) +- linebuflen = INT_MAX; +- +- result->h_name = NULL; +- end_of_message = answer->buf + anslen; +- +- /* +- * find first satisfactory answer +- */ +- hp = &answer->hdr; +- ancount = ntohs (hp->ancount); +- qdcount = ntohs (hp->qdcount); +- cp = answer->buf + HFIXEDSZ; +- if (__glibc_unlikely (qdcount != 1)) +- { +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) +- goto too_small; +- bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; +- linebuflen -= (ancount + 1) * sizeof (char *); +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } ++ /* Filter out domain names that are not host names. */ ++ if (!__res_binary_hnok (cdname)) ++ return false; ++ ++ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks ++ for length. */ ++ char dname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) ++ return false; ++ /* Do not report an error on allocation failure, instead store NULL ++ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS ++ and detect the memory allocation failure or buffer space ++ exhaustion, and report it accordingly. */ ++ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); ++ return true; ++} + +- if (__glibc_unlikely (n < 0)) +- { +- *errnop = errno; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (__glibc_unlikely (__libc_res_hnok (bp) == 0)) ++static enum nss_status __attribute__ ((noinline)) ++getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, ++ struct alloc_buffer *abuf, ++ struct ptrlist *addresses, struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { +- errno = EBADMSG; +- *errnop = EBADMSG; ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- cp += n + QFIXEDSZ; + +- if (qtype == T_A || qtype == T_AAAA) ++ /* Treat the QNAME just like an alias. Error out if it is not a ++ valid host name. */ ++ if (ns_rr_cursor_rcode (&c) == NXDOMAIN ++ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) + { +- /* res_send() has already verified that the query name is the +- * same as the one we sent; this just gets the expanded name +- * (i.e., with the succeeding search-domain tacked on). +- */ +- n = strlen (bp) + 1; /* for the \0 */ +- if (n >= MAXHOSTNAMELEN) +- { +- *h_errnop = NO_RECOVERY; +- *errnop = ENOENT; +- return NSS_STATUS_TRYAGAIN; +- } +- result->h_name = bp; +- bp += n; +- linebuflen -= n; +- if (linebuflen < 0) +- goto too_small; +- /* The qname can be abbreviated, but h_name is now absolute. */ +- qname = result->h_name; ++ if (ttlp != NULL) ++ /* No negative caching. */ ++ *ttlp = 0; ++ *h_errnop = HOST_NOT_FOUND; ++ *errnop = ENOENT; ++ return NSS_STATUS_NOTFOUND; + } + +- ap = host_data->aliases; +- *ap = NULL; +- result->h_aliases = host_data->aliases; +- hap = host_data->h_addr_ptrs; +- *hap = NULL; +- result->h_addr_list = host_data->h_addr_ptrs; +- haveanswer = 0; +- had_error = 0; ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ for (; ancount > 0; --ancount) + { +- int type, class; +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; /* name */ +- +- if (__glibc_unlikely (cp + 10 > end_of_message)) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- NS_GET16 (type, cp); +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ +- +- if (end_of_message - cp < n) +- { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- if (__glibc_unlikely (class != C_IN)) +- { +- /* XXX - debug? syslog? */ +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } ++ /* Update TTL for recognized record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- if (type == T_CNAME) ++ if (rr.rtype == T_CNAME) + { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) +- continue; +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Store alias. */ +- *ap++ = bp; +- n = strlen (bp) + 1; /* For the \0. */ +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- bp += n; +- linebuflen -= n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- result->h_name = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; ++ /* And store the new name as an alias. */ ++ getanswer_r_store_alias (name_buffer, abuf, aliases); ++ expected_name = name_buffer; + } +- +- if (__glibc_unlikely (type != qtype)) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- cp += n; +- continue; /* XXX - had_error++ ? */ ++ /* Make a copy of the address and store it. Increase the ++ alignment to 4, in case there are applications out there ++ that expect at least this level of address alignment. */ ++ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); ++ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); + } +- +- switch (type) +- { +- case T_A: +- case T_AAAA: +- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- /* Stop parsing at a record whose length is incorrect. */ +- if (n != rrtype_to_rdata_length (type)) +- { +- ++had_error; +- break; +- } +- +- /* Skip records of the wrong type. */ +- if (n != result->h_length) +- { +- cp += n; +- continue; +- } +- if (!haveanswer) +- { +- int nn; +- +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- if (canonp != NULL) +- *canonp = bp; +- result->h_name = bp; +- nn = strlen (bp) + 1; /* for the \0 */ +- bp += nn; +- linebuflen -= nn; +- } +- +- /* Provide sufficient alignment for both address +- families. */ +- enum { align = 4 }; +- _Static_assert ((align % __alignof__ (struct in_addr)) == 0, +- "struct in_addr alignment"); +- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, +- "struct in6_addr alignment"); +- { +- char *new_bp = PTR_ALIGN_UP (bp, align); +- linebuflen -= new_bp - bp; +- bp = new_bp; +- } +- +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- bp = __mempcpy (*hap++ = bp, cp, n); +- cp += n; +- linebuflen -= n; +- break; +- default: +- abort (); +- } +- if (had_error == 0) +- ++haveanswer; + } + +- if (haveanswer > 0) ++ if (ptrlist_size (addresses) == 0) + { +- *ap = NULL; +- *hap = NULL; +- /* +- * Note: we sort even if host can take only one address +- * in its return structures - should give it the "best" +- * address in that case, not some random one +- */ +- if (haveanswer > 1 && qtype == T_A +- && __resolv_context_sort_count (ctx) > 0) +- addrsort (ctx, host_data->h_addr_ptrs, haveanswer); +- +- if (result->h_name == NULL) +- { +- n = strlen (qname) + 1; /* For the \0. */ +- if (n > linebuflen) +- goto too_small; +- if (n >= MAXHOSTNAMELEN) +- goto no_recovery; +- result->h_name = bp; +- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ +- linebuflen -= n; +- } ++ /* No address record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + ++ *h_errnop = NO_RECOVERY; ++ *errnop = ENOENT; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } +- no_recovery: +- *h_errnop = NO_RECOVERY; +- *errnop = ENOENT; +- /* 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 ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases +- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); + } + + static enum nss_status diff --git a/glibc-upstream-2.34-326.patch b/glibc-upstream-2.34-326.patch new file mode 100644 index 0000000..3784a3e --- /dev/null +++ b/glibc-upstream-2.34-326.patch @@ -0,0 +1,51 @@ +commit c36e7cca3571b0c92b09409c1df86a142596c210 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + nss_dns: In gaih_getanswer_slice, skip strange aliases (bug 12154) + + If the name is not a host name, skip adding it to the result, instead + of reporting query failure. This fixes bug 12154 for getaddrinfo. + + This commit still keeps the old parsing code, and only adjusts when + a host name is copied. + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 32b599ac8c21c4c332cc3900a792a1395bca79c7) + +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 10c21e1e827cde12..1cb3be71f04d98eb 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -971,12 +971,12 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + + n = -1; + } +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0)) ++ if (__glibc_unlikely (n < 0)) + { + ++had_error; + continue; + } +- if (*firstp && canon == NULL) ++ if (*firstp && canon == NULL && __libc_res_hnok (buffer)) + { + h_name = buffer; + buffer += h_namelen; +@@ -1022,14 +1022,14 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, + + n = __libc_dn_expand (answer->buf, end_of_message, cp, + tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) ++ if (__glibc_unlikely (n < 0)) + { + ++had_error; + continue; + } + cp += n; + +- if (*firstp) ++ if (*firstp && __libc_res_hnok (tbuf)) + { + /* Reclaim buffer space. */ + if (h_name + h_namelen == buffer) diff --git a/glibc-upstream-2.34-327.patch b/glibc-upstream-2.34-327.patch new file mode 100644 index 0000000..8019ca3 --- /dev/null +++ b/glibc-upstream-2.34-327.patch @@ -0,0 +1,449 @@ +commit 480c820493add16e8dda6f3189d834223e1f4f39 +Author: Florian Weimer +Date: Tue Aug 30 10:02:49 2022 +0200 + + resolv: Add new tst-resolv-invalid-cname + + This test checks resolution through CNAME chains that do not contain + host names (bug 12154). + + Reviewed-by: Siddhesh Poyarekar + (cherry picked from commit 9caf782276ecea4bc86fc94fbb52779736f3106d) + +Conflicts: + resolv/Makefile + (usual test differences) + +diff --git a/resolv/Makefile b/resolv/Makefile +index fded244d61068060..ea1518ec2da860c1 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -99,6 +99,7 @@ tests += \ + tst-resolv-binary \ + tst-resolv-byaddr \ + tst-resolv-edns \ ++ tst-resolv-invalid-cname \ + tst-resolv-network \ + tst-resolv-noaaaa \ + tst-resolv-nondecimal \ +@@ -279,6 +280,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c +new file mode 100644 +index 0000000000000000..ae2d4419b1978c02 +--- /dev/null ++++ b/resolv/tst-resolv-invalid-cname.c +@@ -0,0 +1,406 @@ ++/* Test handling of CNAMEs with non-host domain names (bug 12154). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Query strings describe the CNAME chain in the response. They have ++ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are ++ replaced by unsigned decimal numbers. COUNT is the number of CNAME ++ records in the response. BITS has two bits for each CNAME record, ++ describing a special prefix that is added to that CNAME. ++ ++ 0: No special leading label. ++ 1: Starting with "*.". ++ 2: Starting with "-x.". ++ 3: Starting with "star.*.". ++ ++ The first CNAME in the response using the two least significant ++ bits. ++ ++ For PTR queries, the QNAME format is different, it is either ++ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still ++ decimal), or: ++ ++COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. ++ ++ where BITS and COUNT are hexadecimal. */ ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ ++ /* The only other query type besides A is PTR. */ ++ if (qtype != T_A && qtype != T_AAAA) ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int bits, bits1, count; ++ char *tail = NULL; ++ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "example"); ++ else if (strstr (qname, "in-addr.arpa") != NULL ++ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa"); ++ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4) ++ { ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ bits |= bits1 << 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); ++ free (tail); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ unsigned int original_bits = bits; ++ for (int unique = 0; unique < count; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ ++ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." }; ++ char *new_name = xasprintf ("%sunique%d.example", ++ bits_to_prefix[bits & 3], unique); ++ bits >>= 2; ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ /* Actual answer record. */ ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ char ipv4[4] = {192, 168, count, original_bits}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ break; ++ case T_AAAA: ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ count, original_bits ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ break; ++ ++ case T_PTR: ++ { ++ char *name = xasprintf ("bits%u.count%u.example", ++ original_bits, count); ++ resolv_response_add_name (b, name); ++ free (name); ++ } ++ break; ++ } ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Controls which name resolution function is invoked. */ ++enum test_mode ++ { ++ byname, /* gethostbyname. */ ++ byname2, /* gethostbyname2. */ ++ gai, /* getaddrinfo without AI_CANONNAME. */ ++ gai_canon, /* getaddrinfo with AI_CANONNAME. */ ++ ++ test_mode_num /* Number of enum values. */ ++ }; ++ ++static const char * ++test_mode_to_string (enum test_mode mode) ++{ ++ switch (mode) ++ { ++ case byname: ++ return "byname"; ++ case byname2: ++ return "byname2"; ++ case gai: ++ return "gai"; ++ case gai_canon: ++ return "gai_canon"; ++ case test_mode_num: ++ /* Report error below. */ ++ } ++ FAIL_EXIT1 ("invalid test_mode: %d", mode); ++} ++ ++/* Append the name and aliases to OUT. */ ++static void ++append_names (FILE *out, const char *qname, int bits, int count, ++ enum test_mode mode) ++{ ++ /* Largest valid index which has a corresponding zero in bits ++ (meaning a syntactically valid CNAME). */ ++ int last_valid_cname = -1; ++ ++ for (int i = 0; i < count; ++i) ++ if ((bits & (3 << (i * 2))) == 0) ++ last_valid_cname = i; ++ ++ if (mode != gai) ++ { ++ const char *label; ++ if (mode == gai_canon) ++ label = "canonname"; ++ else ++ label = "name"; ++ if (last_valid_cname >= 0) ++ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname); ++ else ++ fprintf (out, "%s: %s\n", label, qname); ++ } ++ ++ if (mode == byname || mode == byname2) ++ { ++ if (last_valid_cname >= 0) ++ fprintf (out, "alias: %s\n", qname); ++ for (int i = 0; i < count; ++i) ++ { ++ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname) ++ fprintf (out, "alias: unique%d.example\n", i); ++ } ++ } ++} ++ ++/* Append the address information to OUT. */ ++static void ++append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode) ++{ ++ int last = count * 256 + bits; ++ if (mode == gai || mode == gai_canon) ++ { ++ if (af == AF_INET || af == AF_UNSPEC) ++ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits); ++ if (af == AF_INET6 || af == AF_UNSPEC) ++ { ++ if (last == 0) ++ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n"); ++ else ++ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last); ++ } ++ } ++ else ++ { ++ TEST_VERIFY (af != AF_UNSPEC); ++ if (af == AF_INET) ++ fprintf (out, "address: 192.168.%d.%d\n", count, bits); ++ if (af == AF_INET6) ++ { ++ if (last == 0) ++ fprintf (out, "address: 2001:db8::\n"); ++ else ++ fprintf (out, "address: 2001:db8::%x\n", last); ++ } ++ } ++} ++ ++/* Perform one test using a forward lookup. */ ++static void ++check_forward (int af, int bits, int count, enum test_mode mode) ++{ ++ char *qname = xasprintf ("bits%d.count%d.example", bits, count); ++ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s", ++ af, bits, count, test_mode_to_string (mode), qname); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ if (mode == gai_canon) ++ fprintf (expected.out, "flags: AI_CANONNAME\n"); ++ append_names (expected.out, qname, bits, count, mode); ++ append_addresses (expected.out, af, bits, count, mode); ++ xfclose_memstream (&expected); ++ ++ if (mode == gai || mode == gai_canon) ++ { ++ struct addrinfo *ai; ++ struct addrinfo hints = ++ { ++ .ai_family = af, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ if (mode == gai_canon) ++ hints.ai_flags |= AI_CANONNAME; ++ int ret = getaddrinfo (qname, "80", &hints, &ai); ++ check_addrinfo (label, ai, ret, expected.buffer); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++ else ++ { ++ struct hostent *e; ++ if (mode == gai) ++ { ++ TEST_COMPARE (af, AF_INET); ++ e = gethostbyname (qname); ++ } ++ else ++ { ++ if (af != AF_INET) ++ TEST_COMPARE (af, AF_INET6); ++ e = gethostbyname2 (qname, af); ++ } ++ check_hostent (label, e, expected.buffer); ++ } ++ ++ free (expected.buffer); ++ free (label); ++ free (qname); ++} ++ ++/* Perform one check using a reverse lookup. */ ++ ++static void ++check_reverse (int af, int bits, int count) ++{ ++ TEST_VERIFY (af == AF_INET || af == AF_INET6); ++ ++ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count); ++ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ fprintf (expected.out, "name: %s\n", fqdn); ++ append_addresses (expected.out, af, bits, count, byname); ++ xfclose_memstream (&expected); ++ ++ char addr[16] = { 0 }; ++ socklen_t addrlen; ++ if (af == AF_INET) ++ { ++ addr[0] = 192; ++ addr[1] = 168; ++ addr[2] = count; ++ addr[3] = bits; ++ addrlen = 4; ++ } ++ else ++ { ++ addr[0] = 0x20; ++ addr[1] = 0x01; ++ addr[2] = 0x0d; ++ addr[3] = 0xb8; ++ addr[14] = count; ++ addr[15] = bits; ++ addrlen = 16; ++ } ++ ++ struct hostent *e = gethostbyaddr (addr, addrlen, af); ++ check_hostent (label, e, expected.buffer); ++ ++ /* getnameinfo check is different. There is no generic check_* ++ function for it. */ ++ { ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (af == AF_INET) ++ { ++ sin.sin_family = AF_INET; ++ memcpy (&sin.sin_addr, addr, addrlen); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ else ++ { ++ sin6.sin6_family = AF_INET6; ++ memcpy (&sin6.sin6_addr, addr, addrlen); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_STRING (host, fqdn); ++ TEST_COMPARE_STRING (service, "80"); ++ } ++ ++ free (expected.buffer); ++ free (fqdn); ++ free (label); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int count = 0; count <= 3; ++count) ++ for (int bits = 0; bits <= 1 << (count * 2); ++bits) ++ { ++ if (count > 0 && bits == count) ++ /* The last bits value is only checked if count == 0. */ ++ continue; ++ ++ for (enum test_mode mode = 0; mode < test_mode_num; ++mode) ++ { ++ check_forward (AF_INET, bits, count, mode); ++ if (mode != byname) ++ check_forward (AF_INET6, bits, count, mode); ++ if (mode == gai || mode == gai_canon) ++ check_forward (AF_UNSPEC, bits, count, mode); ++ } ++ ++ check_reverse (AF_INET, bits, count); ++ check_reverse (AF_INET6, bits, count); ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.34-329.patch b/glibc-upstream-2.34-329.patch new file mode 100644 index 0000000..d718c5f --- /dev/null +++ b/glibc-upstream-2.34-329.patch @@ -0,0 +1,31 @@ +commit 044755e2faeeca13bb77b2e9e638a45e6e90a5fa +Author: Florian Weimer +Date: Tue Aug 30 13:30:03 2022 +0200 + + resolv: Fix building tst-resolv-invalid-cname for earlier C standards + + This fixes this compiler error: + + tst-resolv-invalid-cname.c: In function ‘test_mode_to_string’: + tst-resolv-invalid-cname.c:164:10: error: label at end of compound statement + case test_mode_num: + ^~~~~~~~~~~~~ + + Fixes commit 9caf782276ecea4bc86fc94fbb52779736f3106d + ("resolv: Add new tst-resolv-invalid-cname"). + + (cherry picked from commit d09aa4a17229bcaa2ec7642006b12612498582e7) + +diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c +index ae2d4419b1978c02..63dac90e02d6cbc7 100644 +--- a/resolv/tst-resolv-invalid-cname.c ++++ b/resolv/tst-resolv-invalid-cname.c +@@ -162,7 +162,7 @@ test_mode_to_string (enum test_mode mode) + case gai_canon: + return "gai_canon"; + case test_mode_num: +- /* Report error below. */ ++ break; /* Report error below. */ + } + FAIL_EXIT1 ("invalid test_mode: %d", mode); + } diff --git a/glibc-upstream-2.34-330.patch b/glibc-upstream-2.34-330.patch new file mode 100644 index 0000000..4fb22ef --- /dev/null +++ b/glibc-upstream-2.34-330.patch @@ -0,0 +1,33 @@ +commit a2e259014f8a0e5f3ff938314f3087b74255804d +Author: H.J. Lu +Date: Thu Nov 11 06:31:51 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_lock_full [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + + Reviewed-by: Szabolcs Nagy + (cherry picked from commit 0b82747dc48d5bf0871bdc6da8cb6eec1256355f) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index da624f322d06d0ee..a04e0158451c8fff 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -298,12 +298,12 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, +- oldval | FUTEX_WAITERS, +- oldval) +- != 0) ++ int val; ++ if ((val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, ++ oldval)) != oldval) + { +- oldval = mutex->__data.__lock; ++ oldval = val; + continue; + } + oldval |= FUTEX_WAITERS; diff --git a/glibc-upstream-2.34-331.patch b/glibc-upstream-2.34-331.patch new file mode 100644 index 0000000..59c359f --- /dev/null +++ b/glibc-upstream-2.34-331.patch @@ -0,0 +1,33 @@ +commit ed8300c054cae4aeb0bbfa043f5fccc91a4adbf5 +Author: H.J. Lu +Date: Thu Nov 11 06:54:01 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_clocklock_common [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + + Reviewed-by: Szabolcs Nagy + (cherry picked from commit 49302b8fdf9103b6fc0a398678668a22fa19574c) + +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 11ad7005d07afc6e..90cede9446e33fcf 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -234,12 +234,12 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex, + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, +- oldval | FUTEX_WAITERS, +- oldval) +- != 0) ++ int val; ++ if ((val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, ++ oldval)) != oldval) + { +- oldval = mutex->__data.__lock; ++ oldval = val; + continue; + } + oldval |= FUTEX_WAITERS; diff --git a/glibc-upstream-2.34-332.patch b/glibc-upstream-2.34-332.patch new file mode 100644 index 0000000..2a8d15a --- /dev/null +++ b/glibc-upstream-2.34-332.patch @@ -0,0 +1,46 @@ +commit a6b81f605dfba8650ea1f80122f41eb8e6c73dc7 +Author: H.J. Lu +Date: Tue Nov 2 18:33:07 2021 -0700 + + Add LLL_MUTEX_READ_LOCK [BZ #28537] + + CAS instruction is expensive. From the x86 CPU's point of view, getting + a cache line for writing is more expensive than reading. See Appendix + A.2 Spinlock in: + + https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/xeon-lock-scaling-analysis-paper.pdf + + The full compare and swap will grab the cache line exclusive and cause + excessive cache line bouncing. + + Add LLL_MUTEX_READ_LOCK to do an atomic load and skip CAS in spinlock + loop if compare may fail to reduce cache line bouncing on contended locks. + + Reviewed-by: Szabolcs Nagy + (cherry picked from commit d672a98a1af106bd68deb15576710cd61363f7a6) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index a04e0158451c8fff..9f40928cc6b9a067 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -65,6 +65,11 @@ lll_mutex_lock_optimized (pthread_mutex_t *mutex) + # define PTHREAD_MUTEX_VERSIONS 1 + #endif + ++#ifndef LLL_MUTEX_READ_LOCK ++# define LLL_MUTEX_READ_LOCK(mutex) \ ++ atomic_load_relaxed (&(mutex)->__data.__lock) ++#endif ++ + static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) + __attribute_noinline__; + +@@ -142,6 +147,8 @@ PTHREAD_MUTEX_LOCK (pthread_mutex_t *mutex) + break; + } + atomic_spin_nop (); ++ if (LLL_MUTEX_READ_LOCK (mutex) != 0) ++ continue; + } + while (LLL_MUTEX_TRYLOCK (mutex) != 0); + diff --git a/glibc-upstream-2.34-333.patch b/glibc-upstream-2.34-333.patch new file mode 100644 index 0000000..71f9e2a --- /dev/null +++ b/glibc-upstream-2.34-333.patch @@ -0,0 +1,66 @@ +commit 6bcfbee7277e4faa4b693bd965931f0d1883005d +Author: H.J. Lu +Date: Fri Nov 12 11:47:42 2021 -0800 + + Move assignment out of the CAS condition + + Update + + commit 49302b8fdf9103b6fc0a398678668a22fa19574c + Author: H.J. Lu + Date: Thu Nov 11 06:54:01 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_clocklock_common [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + + and + + commit 0b82747dc48d5bf0871bdc6da8cb6eec1256355f + Author: H.J. Lu + Date: Thu Nov 11 06:31:51 2021 -0800 + + Avoid extra load with CAS in __pthread_mutex_lock_full [BZ #28537] + + Replace boolean CAS with value CAS to avoid the extra load. + + by moving assignment out of the CAS condition. + + (cherry picked from commit 120ac6d238825452e8024e2f627da33b2508dfd3) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 9f40928cc6b9a067..49901ffa0a96d659 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -305,10 +305,9 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- int val; +- if ((val = atomic_compare_and_exchange_val_acq +- (&mutex->__data.__lock, oldval | FUTEX_WAITERS, +- oldval)) != oldval) ++ int val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, oldval); ++ if (val != oldval) + { + oldval = val; + continue; +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 90cede9446e33fcf..2e5506db06ccb1ec 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -234,10 +234,9 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex, + meantime. */ + if ((oldval & FUTEX_WAITERS) == 0) + { +- int val; +- if ((val = atomic_compare_and_exchange_val_acq +- (&mutex->__data.__lock, oldval | FUTEX_WAITERS, +- oldval)) != oldval) ++ int val = atomic_compare_and_exchange_val_acq ++ (&mutex->__data.__lock, oldval | FUTEX_WAITERS, oldval); ++ if (val != oldval) + { + oldval = val; + continue; diff --git a/glibc-upstream-2.34-334.patch b/glibc-upstream-2.34-334.patch new file mode 100644 index 0000000..1138256 --- /dev/null +++ b/glibc-upstream-2.34-334.patch @@ -0,0 +1,38 @@ +commit 43760d33d78f9ea8c8af942b570112ee801b99df +Author: Jangwoong Kim <6812skiii@gmail.com> +Date: Tue Dec 14 21:30:51 2021 +0900 + + nptl: Effectively skip CAS in spinlock loop + + The commit: + "Add LLL_MUTEX_READ_LOCK [BZ #28537]" + SHA1: d672a98a1af106bd68deb15576710cd61363f7a6 + + introduced LLL_MUTEX_READ_LOCK, to skip CAS in spinlock loop + if atomic load fails. But, "continue" inside of do-while loop + does not skip the evaluation of escape expression, thus CAS + is not skipped. + + Replace do-while with while and skip LLL_MUTEX_TRYLOCK if + LLL_MUTEX_READ_LOCK fails. + + Reviewed-by: H.J. Lu + (cherry picked from commit 6b8dbbd03ac88f169b65b5c7d7278576a11d2e44) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 49901ffa0a96d659..bbe754a272b97d91 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -147,10 +147,9 @@ PTHREAD_MUTEX_LOCK (pthread_mutex_t *mutex) + break; + } + atomic_spin_nop (); +- if (LLL_MUTEX_READ_LOCK (mutex) != 0) +- continue; + } +- while (LLL_MUTEX_TRYLOCK (mutex) != 0); ++ while (LLL_MUTEX_READ_LOCK (mutex) != 0 ++ || LLL_MUTEX_TRYLOCK (mutex) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } diff --git a/glibc-upstream-2.34-335.patch b/glibc-upstream-2.34-335.patch new file mode 100644 index 0000000..fdf1241 --- /dev/null +++ b/glibc-upstream-2.34-335.patch @@ -0,0 +1,68 @@ +commit 04efdcfac405723c23b25d124817bcfc1697e2d8 +Author: Noah Goldstein +Date: Wed Apr 27 15:13:02 2022 -0500 + + sysdeps: Add 'get_fast_jitter' interace in fast-jitter.h + + 'get_fast_jitter' is meant to be used purely for performance + purposes. In all cases it's used it should be acceptable to get no + randomness (see default case). An example use case is in setting + jitter for retries between threads at a lock. There is a + performance benefit to having jitter, but only if the jitter can + be generated very quickly and ultimately there is no serious issue + if no jitter is generated. + + The implementation generally uses 'HP_TIMING_NOW' iff it is + inlined (avoid any potential syscall paths). + Reviewed-by: H.J. Lu + + (cherry picked from commit 911c63a51c690dd1a97dfc587097277029baf00f) + +diff --git a/sysdeps/generic/fast-jitter.h b/sysdeps/generic/fast-jitter.h +new file mode 100644 +index 0000000000000000..4dd53e3475c3dfe6 +--- /dev/null ++++ b/sysdeps/generic/fast-jitter.h +@@ -0,0 +1,42 @@ ++/* Fallback for fast jitter just return 0. ++ Copyright (C) 2019-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _FAST_JITTER_H ++# define _FAST_JITTER_H ++ ++# include ++# include ++ ++/* Baseline just return 0. We could create jitter using a clock or ++ 'random_bits' but that may imply a syscall and the goal of ++ 'get_fast_jitter' is minimal overhead "randomness" when such ++ randomness helps performance. Adding high overhead the function ++ defeats the purpose. */ ++static inline uint32_t ++get_fast_jitter (void) ++{ ++# if HP_TIMING_INLINE ++ hp_timing_t jitter; ++ HP_TIMING_NOW (jitter); ++ return (uint32_t) jitter; ++# else ++ return 0; ++# endif ++} ++ ++#endif diff --git a/glibc-upstream-2.34-336.patch b/glibc-upstream-2.34-336.patch new file mode 100644 index 0000000..94b39f2 --- /dev/null +++ b/glibc-upstream-2.34-336.patch @@ -0,0 +1,209 @@ +commit ea69248445fb9b80da02ee0c7261cba4b1a5532e +Author: Wangyang Guo +Date: Fri May 6 01:50:10 2022 +0000 + + nptl: Add backoff mechanism to spinlock loop + + When mutiple threads waiting for lock at the same time, once lock owner + releases the lock, waiters will see lock available and all try to lock, + which may cause an expensive CAS storm. + + Binary exponential backoff with random jitter is introduced. As try-lock + attempt increases, there is more likely that a larger number threads + compete for adaptive mutex lock, so increase wait time in exponential. + A random jitter is also added to avoid synchronous try-lock from other + threads. + + v2: Remove read-check before try-lock for performance. + + v3: + 1. Restore read-check since it works well in some platform. + 2. Make backoff arch dependent, and enable it for x86_64. + 3. Limit max backoff to reduce latency in large critical section. + + v4: Fix strict-prototypes error in sysdeps/nptl/pthread_mutex_backoff.h + + v5: Commit log updated for regression in large critical section. + + Result of pthread-mutex-locks bench + + Test Platform: Xeon 8280L (2 socket, 112 CPUs in total) + First Row: thread number + First Col: critical section length + Values: backoff vs upstream, time based, low is better + + non-critical-length: 1 + 1 2 4 8 16 32 64 112 140 + 0 0.99 0.58 0.52 0.49 0.43 0.44 0.46 0.52 0.54 + 1 0.98 0.43 0.56 0.50 0.44 0.45 0.50 0.56 0.57 + 2 0.99 0.41 0.57 0.51 0.45 0.47 0.48 0.60 0.61 + 4 0.99 0.45 0.59 0.53 0.48 0.49 0.52 0.64 0.65 + 8 1.00 0.66 0.71 0.63 0.56 0.59 0.66 0.72 0.71 + 16 0.97 0.78 0.91 0.73 0.67 0.70 0.79 0.80 0.80 + 32 0.95 1.17 0.98 0.87 0.82 0.86 0.89 0.90 0.90 + 64 0.96 0.95 1.01 1.01 0.98 1.00 1.03 0.99 0.99 + 128 0.99 1.01 1.01 1.17 1.08 1.12 1.02 0.97 1.02 + + non-critical-length: 32 + 1 2 4 8 16 32 64 112 140 + 0 1.03 0.97 0.75 0.65 0.58 0.58 0.56 0.70 0.70 + 1 0.94 0.95 0.76 0.65 0.58 0.58 0.61 0.71 0.72 + 2 0.97 0.96 0.77 0.66 0.58 0.59 0.62 0.74 0.74 + 4 0.99 0.96 0.78 0.66 0.60 0.61 0.66 0.76 0.77 + 8 0.99 0.99 0.84 0.70 0.64 0.66 0.71 0.80 0.80 + 16 0.98 0.97 0.95 0.76 0.70 0.73 0.81 0.85 0.84 + 32 1.04 1.12 1.04 0.89 0.82 0.86 0.93 0.91 0.91 + 64 0.99 1.15 1.07 1.00 0.99 1.01 1.05 0.99 0.99 + 128 1.00 1.21 1.20 1.22 1.25 1.31 1.12 1.10 0.99 + + non-critical-length: 128 + 1 2 4 8 16 32 64 112 140 + 0 1.02 1.00 0.99 0.67 0.61 0.61 0.61 0.74 0.73 + 1 0.95 0.99 1.00 0.68 0.61 0.60 0.60 0.74 0.74 + 2 1.00 1.04 1.00 0.68 0.59 0.61 0.65 0.76 0.76 + 4 1.00 0.96 0.98 0.70 0.63 0.63 0.67 0.78 0.77 + 8 1.01 1.02 0.89 0.73 0.65 0.67 0.71 0.81 0.80 + 16 0.99 0.96 0.96 0.79 0.71 0.73 0.80 0.84 0.84 + 32 0.99 0.95 1.05 0.89 0.84 0.85 0.94 0.92 0.91 + 64 1.00 0.99 1.16 1.04 1.00 1.02 1.06 0.99 0.99 + 128 1.00 1.06 0.98 1.14 1.39 1.26 1.08 1.02 0.98 + + There is regression in large critical section. But adaptive mutex is + aimed for "quick" locks. Small critical section is more common when + users choose to use adaptive pthread_mutex. + + Signed-off-by: Wangyang Guo + Reviewed-by: H.J. Lu + (cherry picked from commit 8162147872491bb5b48e91543b19c49a29ae6b6d) + +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index bbe754a272b97d91..8f3f687f2a151d16 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -139,14 +139,26 @@ PTHREAD_MUTEX_LOCK (pthread_mutex_t *mutex) + int cnt = 0; + int max_cnt = MIN (max_adaptive_count (), + mutex->__data.__spins * 2 + 10); ++ int spin_count, exp_backoff = 1; ++ unsigned int jitter = get_jitter (); + do + { +- if (cnt++ >= max_cnt) ++ /* In each loop, spin count is exponential backoff plus ++ random jitter, random range is [0, exp_backoff-1]. */ ++ spin_count = exp_backoff + (jitter & (exp_backoff - 1)); ++ cnt += spin_count; ++ if (cnt >= max_cnt) + { ++ /* If cnt exceeds max spin count, just go to wait ++ queue. */ + LLL_MUTEX_LOCK (mutex); + break; + } +- atomic_spin_nop (); ++ do ++ atomic_spin_nop (); ++ while (--spin_count > 0); ++ /* Prepare for next loop. */ ++ exp_backoff = get_next_backoff (exp_backoff); + } + while (LLL_MUTEX_READ_LOCK (mutex) != 0 + || LLL_MUTEX_TRYLOCK (mutex) != 0); +diff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h +index b968afc4c6b61b92..ed186ce3df1fde0c 100644 +--- a/sysdeps/nptl/pthreadP.h ++++ b/sysdeps/nptl/pthreadP.h +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include "pthread_mutex_conf.h" + + +diff --git a/sysdeps/nptl/pthread_mutex_backoff.h b/sysdeps/nptl/pthread_mutex_backoff.h +new file mode 100644 +index 0000000000000000..5b26c22ac789f54f +--- /dev/null ++++ b/sysdeps/nptl/pthread_mutex_backoff.h +@@ -0,0 +1,35 @@ ++/* Pthread mutex backoff configuration. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++#ifndef _PTHREAD_MUTEX_BACKOFF_H ++#define _PTHREAD_MUTEX_BACKOFF_H 1 ++ ++static inline unsigned int ++get_jitter (void) ++{ ++ /* Arch dependent random jitter, return 0 disables random. */ ++ return 0; ++} ++ ++static inline int ++get_next_backoff (int backoff) ++{ ++ /* Next backoff, return 1 disables mutex backoff. */ ++ return 1; ++} ++ ++#endif +diff --git a/sysdeps/x86_64/nptl/pthread_mutex_backoff.h b/sysdeps/x86_64/nptl/pthread_mutex_backoff.h +new file mode 100644 +index 0000000000000000..ec74c3d9db61864e +--- /dev/null ++++ b/sysdeps/x86_64/nptl/pthread_mutex_backoff.h +@@ -0,0 +1,39 @@ ++/* Pthread mutex backoff configuration. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++#ifndef _PTHREAD_MUTEX_BACKOFF_H ++#define _PTHREAD_MUTEX_BACKOFF_H 1 ++ ++#include ++ ++static inline unsigned int ++get_jitter (void) ++{ ++ return get_fast_jitter (); ++} ++ ++#define MAX_BACKOFF 16 ++ ++static inline int ++get_next_backoff (int backoff) ++{ ++ /* Binary expontial backoff. Limiting max backoff ++ can reduce latency in large critical section. */ ++ return (backoff < MAX_BACKOFF) ? backoff << 1 : backoff; ++} ++ ++#endif diff --git a/glibc-upstream-2.34-337.patch b/glibc-upstream-2.34-337.patch new file mode 100644 index 0000000..41aea50 --- /dev/null +++ b/glibc-upstream-2.34-337.patch @@ -0,0 +1,26 @@ +commit 95f5089d4a57cd1e738be908c7a628cb7d0ce512 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86: include BMI1 and BMI2 in x86-64-v3 level + + The "System V Application Binary Interface AMD64 Architecture Processor + Supplement" mandates the BMI1 and BMI2 CPU features for the x86-64-v3 + level. + + Reviewed-by: Noah Goldstein + (cherry picked from commit b80f16adbd979831bf25ea491e1261e81885c2b6) + +diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h +index aa80f56ca635e54b..785c25a835edf004 100644 +--- a/sysdeps/x86/get-isa-level.h ++++ b/sysdeps/x86/get-isa-level.h +@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features) + isa_level |= GNU_PROPERTY_X86_ISA_1_V2; + if (CPU_FEATURE_USABLE_P (cpu_features, AVX) + && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURE_USABLE_P (cpu_features, F16C) + && CPU_FEATURE_USABLE_P (cpu_features, FMA) + && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) diff --git a/glibc-upstream-2.34-338.patch b/glibc-upstream-2.34-338.patch new file mode 100644 index 0000000..44dec62 --- /dev/null +++ b/glibc-upstream-2.34-338.patch @@ -0,0 +1,111 @@ +commit 414fc856ff4e011e62b88a21d30294637a152dc7 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 for AVX2 str(n)casecmp implementations + + The AVX2 str(n)casecmp implementations use the 'bzhi' instruction, which + belongs to the BMI2 CPU feature. + + NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF + as BSF if the CPU doesn't support TZCNT, and produces the same result + for non-zero input. + + Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit 10f79d3670b036925da63dc532b122d27ce65ff8) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 8d649e263eb24b8a..ca64b34c146a76f9 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -386,13 +386,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp, + IFUNC_IMPL_ADD (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_evex) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_avx2) + IFUNC_IMPL_ADD (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcasecmp, +@@ -407,13 +410,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp_l, + IFUNC_IMPL_ADD (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_evex) + IFUNC_IMPL_ADD (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_avx2) + IFUNC_IMPL_ADD (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_l_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcasecmp_l, +@@ -542,13 +548,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp, + IFUNC_IMPL_ADD (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_evex) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_avx2) + IFUNC_IMPL_ADD (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncasecmp, +@@ -564,13 +573,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp_l, + IFUNC_IMPL_ADD (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ & CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_evex) + IFUNC_IMPL_ADD (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_avx2) + IFUNC_IMPL_ADD (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_l_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncasecmp_l, +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 40819caf5ab10337..e61d6e9497bce9d9 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -32,6 +32,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) diff --git a/glibc-upstream-2.34-339.patch b/glibc-upstream-2.34-339.patch new file mode 100644 index 0000000..4820b0f --- /dev/null +++ b/glibc-upstream-2.34-339.patch @@ -0,0 +1,55 @@ +commit e1561d8cf005a23bcaf514802854b493829a25b1 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 for AVX2 strcmp implementation + + The AVX2 strcmp implementation uses the 'bzhi' instruction, which + belongs to the BMI2 CPU feature. + + NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF + as BSF if the CPU doesn't support TZCNT, and produces the same result + for non-zero input. + + Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit 4d64c6445735e9b34e2ac8e369312cbfc2f88e17) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index ca64b34c146a76f9..70931f15985334af 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -503,10 +503,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strcmp.c. */ + IFUNC_IMPL (i, name, strcmp, + IFUNC_IMPL_ADD (array, i, strcmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcmp_avx2) + IFUNC_IMPL_ADD (array, i, strcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strcmp, +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index b457fb4c150e4407..0c0cd20a03278a2b 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -40,11 +40,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) diff --git a/glibc-upstream-2.34-340.patch b/glibc-upstream-2.34-340.patch new file mode 100644 index 0000000..077c288 --- /dev/null +++ b/glibc-upstream-2.34-340.patch @@ -0,0 +1,62 @@ +commit b9cbb8dd48b545f3b36b5d411481dc0bd118ee94 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 for AVX2 strncmp implementation + + The AVX2 strncmp implementations uses the 'bzhi' instruction, which + belongs to the BMI2 CPU feature. + + NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF + as BSF if the CPU doesn't support TZCNT, and produces the same result + for non-zero input. + + Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit fc7de1d9b99ae1676bc626ddca422d7abee0eb48) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 70931f15985334af..34d5f6efe5421014 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -1022,15 +1022,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strncmp.c. */ + IFUNC_IMPL (i, name, strncmp, + IFUNC_IMPL_ADD (array, i, strncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_avx2) + IFUNC_IMPL_ADD (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_evex) + IFUNC_IMPL_ADD (array, i, strncmp, CPU_FEATURE_USABLE (SSE4_2), + __strncmp_sse42) +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index f94a421784bfe923..7632d7b2dd4447aa 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -39,11 +39,11 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) diff --git a/glibc-upstream-2.34-341.patch b/glibc-upstream-2.34-341.patch new file mode 100644 index 0000000..6e9814a --- /dev/null +++ b/glibc-upstream-2.34-341.patch @@ -0,0 +1,51 @@ +commit 67e863742d98c990b3d3b814b80042c0fa0d50a5 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 for AVX2 wcs(n)cmp implementations + + The AVX2 wcs(n)cmp implementations use the 'bzhi' instruction, which + belongs to the BMI2 CPU feature. + + NB: It also uses the 'tzcnt' BMI1 instruction, but it is executed as BSF + as BSF if the CPU doesn't support TZCNT, and produces the same result + for non-zero input. + + Partially fixes: b77b06e0e296 ("x86: Optimize strcmp-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit f31a5a884ed84bd37032729d4d1eb9d06c9f3c29) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 34d5f6efe5421014..e76a991dc671c1a9 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -693,10 +693,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcscmp.c. */ + IFUNC_IMPL (i, name, wcscmp, + IFUNC_IMPL_ADD (array, i, wcscmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcscmp_avx2) + IFUNC_IMPL_ADD (array, i, wcscmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcscmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcscmp, +@@ -709,10 +711,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcsncmp.c. */ + IFUNC_IMPL (i, name, wcsncmp, + IFUNC_IMPL_ADD (array, i, wcsncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsncmp_avx2) + IFUNC_IMPL_ADD (array, i, wcsncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsncmp_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsncmp, diff --git a/glibc-upstream-2.34-342.patch b/glibc-upstream-2.34-342.patch new file mode 100644 index 0000000..8750786 --- /dev/null +++ b/glibc-upstream-2.34-342.patch @@ -0,0 +1,61 @@ +commit 94b9c1b6409e34f3f0b2339f77d7ee78087422eb +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 for AVX2 (raw|w)memchr implementations + + The AVX2 memchr, rawmemchr and wmemchr implementations use the 'bzhi' + and 'sarx' instructions, which belongs to the BMI2 CPU feature. + + Fixes: acfd088a1963 ("x86: Optimize memchr-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit e3e7fab7fe5186d18ca2046d99ba321c27db30ad) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index e76a991dc671c1a9..81640cf00664e3ed 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -41,10 +41,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memchr.c. */ + IFUNC_IMPL (i, name, memchr, + IFUNC_IMPL_ADD (array, i, memchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __memchr_avx2) + IFUNC_IMPL_ADD (array, i, memchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __memchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, memchr, +@@ -283,10 +285,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/rawmemchr.c. */ + IFUNC_IMPL (i, name, rawmemchr, + IFUNC_IMPL_ADD (array, i, rawmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_avx2) + IFUNC_IMPL_ADD (array, i, rawmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __rawmemchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, rawmemchr, +@@ -787,10 +791,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wmemchr.c. */ + IFUNC_IMPL (i, name, wmemchr, + IFUNC_IMPL_ADD (array, i, wmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_avx2) + IFUNC_IMPL_ADD (array, i, wmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wmemchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wmemchr, diff --git a/glibc-upstream-2.34-343.patch b/glibc-upstream-2.34-343.patch new file mode 100644 index 0000000..dd9d4b8 --- /dev/null +++ b/glibc-upstream-2.34-343.patch @@ -0,0 +1,56 @@ +commit 36d6b9be3d7008a78e1f6e2e2db1947b76b206d8 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI2 and LZCNT for AVX2 memrchr implementation + + The AVX2 memrchr implementation uses the 'shlxl' instruction, which + belongs to the BMI2 CPU feature and uses the 'lzcnt' instruction, which + belongs to the LZCNT CPU feature. + + Fixes: af5306a735eb ("x86: Optimize memrchr-avx2.S") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit 3c0c78afabfed4b6fc161c159e628fbf14ff370b) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 6de72f72724b81ba..52bd00ea5cab6b22 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -31,6 +31,7 @@ IFUNC_SELECTOR (void) + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) + { + if (CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index 81640cf00664e3ed..d1fc1e75d6706413 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -174,15 +174,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/memrchr.c. */ + IFUNC_IMPL (i, name, memrchr, + IFUNC_IMPL_ADD (array, i, memrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_avx2) + IFUNC_IMPL_ADD (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT) + && CPU_FEATURE_USABLE (RTM)), + __memrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_evex) + + IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_sse2)) diff --git a/glibc-upstream-2.34-344.patch b/glibc-upstream-2.34-344.patch new file mode 100644 index 0000000..754168f --- /dev/null +++ b/glibc-upstream-2.34-344.patch @@ -0,0 +1,78 @@ +commit e570b865b53f33453d97160791a7d97e38bcc6e8 +Author: Aurelien Jarno +Date: Mon Oct 3 23:16:46 2022 +0200 + + x86-64: Require BMI1/BMI2 for AVX2 strrchr and wcsrchr implementations + + The AVX2 strrchr and wcsrchr implementation uses the 'blsmsk' + instruction which belongs to the BMI1 CPU feature and the 'shrx' + instruction, which belongs to the BMI2 CPU feature. + + Fixes: df7e295d18ff ("x86: Optimize {str|wcs}rchr-avx2") + Partially resolves: BZ #29611 + + Reviewed-by: Noah Goldstein + (cherry picked from commit 7e8283170c5d6805b609a040801d819e362a6292) + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index 52bd00ea5cab6b22..877f007dd6e38fe8 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -30,6 +30,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features* cpu_features = __get_cpu_features (); + + if (CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) + && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) + && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load)) +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index d1fc1e75d6706413..84f9e73e2b7df816 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -498,15 +498,21 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/strrchr.c. */ + IFUNC_IMPL (i, name, strrchr, + IFUNC_IMPL_ADD (array, i, strrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_avx2) + IFUNC_IMPL_ADD (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_evex) + IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_sse2)) + +@@ -687,15 +693,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Support sysdeps/x86_64/multiarch/wcsrchr.c. */ + IFUNC_IMPL (i, name, wcsrchr, + IFUNC_IMPL_ADD (array, i, wcsrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_avx2) + IFUNC_IMPL_ADD (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsrchr_avx2_rtm) + IFUNC_IMPL_ADD (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_evex) + IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_sse2)) diff --git a/glibc-upstream-2.34-345.patch b/glibc-upstream-2.34-345.patch new file mode 100644 index 0000000..c0028eb --- /dev/null +++ b/glibc-upstream-2.34-345.patch @@ -0,0 +1,46 @@ +commit e3976287b22422787f3cc6fc9adda58304b55bd9 +Author: Siddhesh Poyarekar +Date: Tue Oct 4 18:40:25 2022 -0400 + + nscd: Drop local address tuple variable [BZ #29607] + + When a request needs to be resent (e.g. due to insufficient buffer + space), the references to subsequent tuples in the local variable are + stale and should not be used. This used to work by accident before, but + since 1d495912a it no longer does. Instead of trying to reset it, just + let gethostbyname4_r write into TUMPBUF6 for us, thus maintaining a + consistent state at all times. This is now consistent with what is done + in gaih_inet for getaddrinfo. + + Resolves: BZ #29607 + Reported-by: Holger Hoffstätte + Tested-by: Holger Hoffstätte + Reviewed-by: Carlos O'Donell + (cherry picked from commit 6e33e5c4b73cea7b8aa3de0947123db16200fb65) + +diff --git a/nscd/aicache.c b/nscd/aicache.c +index 737ace11cc276021..3b300ad9b7db2297 100644 +--- a/nscd/aicache.c ++++ b/nscd/aicache.c +@@ -111,11 +111,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + "gethostbyname4_r"); + if (fct4 != NULL) + { +- struct gaih_addrtuple atmem; + struct gaih_addrtuple *at; + while (1) + { +- at = &atmem; ++ at = NULL; + rc6 = 0; + herrno = 0; + status[1] = DL_CALL_FCT (fct4, (key, &at, +@@ -138,7 +137,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + goto next_nip; + + /* We found the data. Count the addresses and the size. */ +- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL; ++ for (const struct gaih_addrtuple *at2 = at; at2 != NULL; + at2 = at2->next) + { + ++naddrs; diff --git a/glibc.spec b/glibc.spec index 2da3d32..428a3b6 100644 --- a/glibc.spec +++ b/glibc.spec @@ -148,7 +148,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 47%{?dist} +Release: 48%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -595,6 +595,45 @@ Patch387: glibc-rh2117712-3.patch Patch388: glibc-rh2117712-4.patch Patch389: glibc-rh2117712-5.patch Patch390: glibc-rh2117712-6.patch +Patch391: glibc-upstream-2.34-309.patch +Patch392: glibc-upstream-2.34-310.patch +Patch393: glibc-upstream-2.34-311.patch +Patch394: glibc-upstream-2.34-312.patch +# glibc-2.34-313-gbc5cb538e5 backported above as glibc-rh2118666.patch. +Patch395: glibc-upstream-2.34-314.patch +Patch396: glibc-upstream-2.34-315.patch +Patch397: glibc-upstream-2.34-316.patch +Patch398: glibc-upstream-2.34-317.patch +Patch399: glibc-upstream-2.34-318.patch +Patch400: glibc-upstream-2.34-319.patch +Patch401: glibc-upstream-2.34-320.patch +Patch402: glibc-upstream-2.34-321.patch +Patch403: glibc-upstream-2.34-322.patch +Patch404: glibc-upstream-2.34-323.patch +Patch405: glibc-upstream-2.34-324.patch +Patch406: glibc-upstream-2.34-325.patch +Patch407: glibc-upstream-2.34-326.patch +Patch408: glibc-upstream-2.34-327.patch +# glibc-2.34-328-g2def56a349 conflicts with glibc-rh2096191-2.patch; +# glibc-rh2129005.patch contains the original master branch commit instead. +Patch409: glibc-rh2129005.patch +Patch410: glibc-upstream-2.34-329.patch +Patch411: glibc-upstream-2.34-330.patch +Patch412: glibc-upstream-2.34-331.patch +Patch413: glibc-upstream-2.34-332.patch +Patch414: glibc-upstream-2.34-333.patch +Patch415: glibc-upstream-2.34-334.patch +Patch416: glibc-upstream-2.34-335.patch +Patch417: glibc-upstream-2.34-336.patch +Patch418: glibc-upstream-2.34-337.patch +Patch419: glibc-upstream-2.34-338.patch +Patch420: glibc-upstream-2.34-339.patch +Patch421: glibc-upstream-2.34-340.patch +Patch422: glibc-upstream-2.34-341.patch +Patch423: glibc-upstream-2.34-342.patch +Patch424: glibc-upstream-2.34-343.patch +Patch425: glibc-upstream-2.34-344.patch +Patch426: glibc-upstream-2.34-345.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2651,6 +2690,48 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Thu Oct 13 2022 Arjun Shankar - 2.34-48 +- Handle non-hostname CNAME aliases during name resolution (#2129005) +- Sync with upstream branch release/2.34/master, + commit e3976287b22422787f3cc6fc9adda58304b55bd9: +- nscd: Drop local address tuple variable [BZ #29607] +- x86-64: Require BMI1/BMI2 for AVX2 strrchr and wcsrchr implementations +- x86-64: Require BMI2 and LZCNT for AVX2 memrchr implementation +- x86-64: Require BMI2 for AVX2 (raw|w)memchr implementations +- x86-64: Require BMI2 for AVX2 wcs(n)cmp implementations +- x86-64: Require BMI2 for AVX2 strncmp implementation +- x86-64: Require BMI2 for AVX2 strcmp implementation +- x86-64: Require BMI2 for AVX2 str(n)casecmp implementations +- x86: include BMI1 and BMI2 in x86-64-v3 level +- nptl: Add backoff mechanism to spinlock loop +- sysdeps: Add 'get_fast_jitter' interace in fast-jitter.h +- nptl: Effectively skip CAS in spinlock loop +- Move assignment out of the CAS condition +- Add LLL_MUTEX_READ_LOCK [BZ #28537] +- Avoid extra load with CAS in __pthread_mutex_clocklock_common [BZ #28537] +- Avoid extra load with CAS in __pthread_mutex_lock_full [BZ #28537] +- resolv: Fix building tst-resolv-invalid-cname for earlier C standards +- nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces +- resolv: Add new tst-resolv-invalid-cname +- nss_dns: In gaih_getanswer_slice, skip strange aliases (bug 12154) + (#2129005) +- nss_dns: Rewrite getanswer_r to match getanswer_ptr (bug 12154, bug 29305) +- nss_dns: Remove remnants of IPv6 address mapping +- nss_dns: Rewrite _nss_dns_gethostbyaddr2_r and getanswer_ptr +- nss_dns: Split getanswer_ptr from getanswer_r +- resolv: Add DNS packet parsing helpers geared towards wire format +- resolv: Add internal __ns_name_length_uncompressed function +- resolv: Add the __ns_samebinaryname function +- resolv: Add internal __res_binary_hnok function +- resolv: Add tst-resolv-aliases +- resolv: Add tst-resolv-byaddr for testing reverse lookup +- gconv: Use 64-bit interfaces in gconv_parseconfdir (bug 29583) +- elf: Fix hwcaps string size overestimation +- nscd: Fix netlink cache invalidation if epoll is used [BZ #29415] +- Apply asm redirections in wchar.h before first use +- Apply asm redirections in stdio.h before first use [BZ #27087] +- elf: Call __libc_early_init for reused namespaces (bug 29528) + * Tue Oct 11 2022 Florian Weimer - 2.34-47 - Simplify the glibc system call profile (#2117712)