import glibc-2.28-127.el8_3.2

This commit is contained in:
CentOS Sources 2021-02-16 04:18:24 -05:00 committed by Andrew Lukoshko
parent d24c9cf076
commit f43c687a7a
9 changed files with 1091 additions and 1 deletions

View File

@ -0,0 +1,62 @@
Partial backport of:
commit 333221862ecbebde60dd16e7ca17d26444e62f50
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Apr 8 11:19:38 2019 +0200
resolv: Remove RES_INSECURE1, RES_INSECURE2
Always perform the associated security checks.
The constants and their debug output handling are preserve in this
backport.
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 705ecb7189d215c2..c9b02cca130bc20d 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1324,31 +1324,25 @@ send_dg(res_state statp,
*/
goto wait;
}
- if (!(statp->options & RES_INSECURE1) &&
- !res_ourserver_p(statp, &from)) {
- /*
- * response from wrong server? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
- if (!(statp->options & RES_INSECURE2)
- && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
+
+ /* Paranoia check. Due to the connected UDP socket,
+ the kernel has already filtered invalid addresses
+ for us. */
+ if (!res_ourserver_p(statp, &from))
+ goto wait;
+
+ /* Check for the correct header layout and a matching
+ question. */
+ if ((recvresp1 || !res_queriesmatch(buf, buf + buflen,
*thisansp,
*thisansp
+ *thisanssizp))
&& (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
*thisansp,
*thisansp
- + *thisanssizp))) {
- /*
- * response contains wrong query? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
+ + *thisanssizp)))
+ goto wait;
+
if (anhp->rcode == SERVFAIL ||
anhp->rcode == NOTIMP ||
anhp->rcode == REFUSED) {

View File

@ -0,0 +1,51 @@
Backport the support/ changes from this commit, to avoid future
conflicts:
commit 446997ff1433d33452b81dfa9e626b8dccf101a4
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Oct 30 17:26:58 2019 +0100
resolv: Implement trust-ad option for /etc/resolv.conf [BZ #20358]
This introduces a concept of trusted name servers, for which the
AD bit is passed through to applications. For untrusted name
servers (the default), the AD bit in responses are cleared, to
provide a safe default.
This approach is very similar to the one suggested by Pavel Šimerda
in <https://bugzilla.redhat.com/show_bug.cgi?id=1164339#c15>.
The DNS test framework in support/ is enhanced with support for
setting the AD bit in responses.
Tested on x86_64-linux-gnu.
Change-Id: Ibfe0f7c73ea221c35979842c5c3b6ed486495ccc
diff --git a/support/resolv_test.c b/support/resolv_test.c
index 3f2a09f36f445878..28af227cb5ed901c 100644
--- a/support/resolv_test.c
+++ b/support/resolv_test.c
@@ -182,6 +182,8 @@ resolv_response_init (struct resolv_response_builder *b,
if (flags.tc)
b->buffer[2] |= 0x02;
b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */
+ if (flags.ad)
+ b->buffer[3] |= 0x20;
/* Fill in the initial section count values. */
b->buffer[4] = flags.qdcount >> 8;
diff --git a/support/resolv_test.h b/support/resolv_test.h
index 4c2e6c1b417f5fcd..be736aead40cd0cc 100644
--- a/support/resolv_test.h
+++ b/support/resolv_test.h
@@ -134,6 +134,9 @@ struct resolv_response_flags
/* If true, the TC (truncation) flag will be set. */
bool tc;
+ /* If true, the AD (authenticated data) flag will be set. */
+ bool ad;
+
/* Initial section count values. Can be used to artificially
increase the counts, for malformed packet testing.*/
unsigned short qdcount;

View File

@ -0,0 +1,293 @@
commit 873e239a4c3d8ec235c27439c1bdc5bbf8aa1818
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Oct 14 10:54:39 2020 +0200
support: Provide a way to reorder responses within the DNS test server
diff --git a/support/Makefile b/support/Makefile
index 3c940aa6a7bdfc99..37d5dcc92a5c6dee 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -35,6 +35,8 @@ libsupport-routines = \
ignore_stderr \
next_to_fault \
oom_error \
+ resolv_response_context_duplicate \
+ resolv_response_context_free \
resolv_test \
set_fortify_handler \
support-xfstat \
diff --git a/support/resolv_response_context_duplicate.c b/support/resolv_response_context_duplicate.c
new file mode 100644
index 0000000000000000..f9c5c3462ad053ec
--- /dev/null
+++ b/support/resolv_response_context_duplicate.c
@@ -0,0 +1,37 @@
+/* Duplicate a response context used in DNS resolver tests.
+ Copyright (C) 2020 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+struct resolv_response_context *
+resolv_response_context_duplicate (const struct resolv_response_context *ctx)
+{
+ struct resolv_response_context *result = xmalloc (sizeof (*result));
+ memcpy (result, ctx, sizeof (*result));
+ if (result->client_address != NULL)
+ {
+ result->client_address = xmalloc (result->client_address_length);
+ memcpy (result->client_address, ctx->client_address,
+ result->client_address_length);
+ }
+ result->query_buffer = xmalloc (result->query_length);
+ memcpy (result->query_buffer, ctx->query_buffer, result->query_length);
+ return result;
+}
diff --git a/support/resolv_response_context_free.c b/support/resolv_response_context_free.c
new file mode 100644
index 0000000000000000..b88c05ffd4acfdd4
--- /dev/null
+++ b/support/resolv_response_context_free.c
@@ -0,0 +1,28 @@
+/* Free a response context used in DNS resolver tests.
+ Copyright (C) 2020 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <support/resolv_test.h>
+
+void
+resolv_response_context_free (struct resolv_response_context *ctx)
+{
+ free (ctx->query_buffer);
+ free (ctx->client_address);
+ free (ctx);
+}
diff --git a/support/resolv_test.c b/support/resolv_test.c
index 28af227cb5ed901c..8cca4e6cf723de28 100644
--- a/support/resolv_test.c
+++ b/support/resolv_test.c
@@ -434,9 +434,9 @@ resolv_response_buffer (const struct resolv_response_builder *b)
return result;
}
-static struct resolv_response_builder *
-response_builder_allocate
- (const unsigned char *query_buffer, size_t query_length)
+struct resolv_response_builder *
+resolv_response_builder_allocate (const unsigned char *query_buffer,
+ size_t query_length)
{
struct resolv_response_builder *b = xmalloc (sizeof (*b));
memset (b, 0, offsetof (struct resolv_response_builder, buffer));
@@ -445,8 +445,8 @@ response_builder_allocate
return b;
}
-static void
-response_builder_free (struct resolv_response_builder *b)
+void
+resolv_response_builder_free (struct resolv_response_builder *b)
{
tdestroy (b->compression_offsets, free);
free (b);
@@ -661,13 +661,17 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
struct resolv_response_context ctx =
{
+ .test = obj,
+ .client_address = &peer,
+ .client_address_length = peerlen,
.query_buffer = query,
.query_length = length,
.server_index = server_index,
.tcp = false,
.edns = qinfo.edns,
};
- struct resolv_response_builder *b = response_builder_allocate (query, length);
+ struct resolv_response_builder *b
+ = resolv_response_builder_allocate (query, length);
obj->config.response_callback
(&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
@@ -684,7 +688,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
if (b->offset >= 12)
printf ("info: UDP server %d: sending response:"
" %zu bytes, RCODE %d (for %s/%u/%u)\n",
- server_index, b->offset, b->buffer[3] & 0x0f,
+ ctx.server_index, b->offset, b->buffer[3] & 0x0f,
qinfo.qname, qinfo.qclass, qinfo.qtype);
else
printf ("info: UDP server %d: sending response: %zu bytes"
@@ -694,23 +698,31 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
if (b->truncate_bytes > 0)
printf ("info: truncated by %u bytes\n", b->truncate_bytes);
}
- size_t to_send = b->offset;
- if (to_send < b->truncate_bytes)
- to_send = 0;
- else
- to_send -= b->truncate_bytes;
-
- /* Ignore most errors here because the other end may have closed
- the socket. */
- if (sendto (obj->servers[server_index].socket_udp,
- b->buffer, to_send, 0,
- (struct sockaddr *) &peer, peerlen) < 0)
- TEST_VERIFY_EXIT (errno != EBADF);
+ resolv_response_send_udp (&ctx, b);
}
- response_builder_free (b);
+ resolv_response_builder_free (b);
return true;
}
+void
+resolv_response_send_udp (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b)
+{
+ TEST_VERIFY_EXIT (!ctx->tcp);
+ size_t to_send = b->offset;
+ if (to_send < b->truncate_bytes)
+ to_send = 0;
+ else
+ to_send -= b->truncate_bytes;
+
+ /* Ignore most errors here because the other end may have closed
+ the socket. */
+ if (sendto (ctx->test->servers[ctx->server_index].socket_udp,
+ b->buffer, to_send, 0,
+ ctx->client_address, ctx->client_address_length) < 0)
+ TEST_VERIFY_EXIT (errno != EBADF);
+}
+
/* UDP thread_callback function. Variant for one thread per
server. */
static void
@@ -897,14 +909,15 @@ server_thread_tcp_client (void *arg)
struct resolv_response_context ctx =
{
+ .test = closure->obj,
.query_buffer = query_buffer,
.query_length = query_length,
.server_index = closure->server_index,
.tcp = true,
.edns = qinfo.edns,
};
- struct resolv_response_builder *b = response_builder_allocate
- (query_buffer, query_length);
+ struct resolv_response_builder *b
+ = resolv_response_builder_allocate (query_buffer, query_length);
closure->obj->config.response_callback
(&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
@@ -936,7 +949,7 @@ server_thread_tcp_client (void *arg)
writev_fully (closure->client_socket, buffers, 2);
}
bool close_flag = b->close;
- response_builder_free (b);
+ resolv_response_builder_free (b);
free (query_buffer);
if (close_flag)
break;
diff --git a/support/resolv_test.h b/support/resolv_test.h
index be736aead40cd0cc..ff5571dace92c936 100644
--- a/support/resolv_test.h
+++ b/support/resolv_test.h
@@ -35,25 +35,36 @@ struct resolv_edns_info
uint16_t payload_size;
};
+/* This opaque struct collects information about the resolver testing
+ currently in progress. */
+struct resolv_test;
+
/* This struct provides context information when the response callback
specified in struct resolv_redirect_config is invoked. */
struct resolv_response_context
{
- const unsigned char *query_buffer;
+ struct resolv_test *test;
+ void *client_address;
+ size_t client_address_length;
+ unsigned char *query_buffer;
size_t query_length;
int server_index;
bool tcp;
struct resolv_edns_info edns;
};
+/* Produces a deep copy of the context. */
+struct resolv_response_context *
+ resolv_response_context_duplicate (const struct resolv_response_context *);
+
+/* Frees the copy. For the context passed to the response function,
+ this happens implicitly. */
+void resolv_response_context_free (struct resolv_response_context *);
+
/* This opaque struct is used to construct responses from within the
response callback function. */
struct resolv_response_builder;
-/* This opaque struct collects information about the resolver testing
- currently in progress. */
-struct resolv_test;
-
enum
{
/* Maximum number of test servers supported by the framework. */
@@ -188,6 +199,22 @@ void resolv_response_close (struct resolv_response_builder *);
/* The size of the response packet built so far. */
size_t resolv_response_length (const struct resolv_response_builder *);
+/* Allocates a response builder tied to a specific query packet,
+ starting at QUERY_BUFFER, containing QUERY_LENGTH bytes. */
+struct resolv_response_builder *
+ resolv_response_builder_allocate (const unsigned char *query_buffer,
+ size_t query_length);
+
+/* Deallocates a response buffer. */
+void resolv_response_builder_free (struct resolv_response_builder *);
+
+/* Sends a UDP response using a specific context. This can be used to
+ reorder or duplicate responses, along with
+ resolv_response_context_duplicate and
+ response_builder_allocate. */
+void resolv_response_send_udp (const struct resolv_response_context *,
+ struct resolv_response_builder *);
+
__END_DECLS
#endif /* SUPPORT_RESOLV_TEST_H */

View File

@ -0,0 +1,36 @@
commit 08443b19965f48862b02c2fd7b33a39d66daf2ff
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Oct 14 10:54:39 2020 +0200
support: Provide a way to clear the RA bit in DNS server responses
diff --git a/support/resolv_test.c b/support/resolv_test.c
index 8cca4e6cf723de28..9323f1d55b0be8f1 100644
--- a/support/resolv_test.c
+++ b/support/resolv_test.c
@@ -181,7 +181,9 @@ resolv_response_init (struct resolv_response_builder *b,
b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */
if (flags.tc)
b->buffer[2] |= 0x02;
- b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */
+ b->buffer[3] = flags.rcode;
+ if (!flags.clear_ra)
+ b->buffer[3] |= 0x80;
if (flags.ad)
b->buffer[3] |= 0x20;
diff --git a/support/resolv_test.h b/support/resolv_test.h
index ff5571dace92c936..825abb9ff2897a43 100644
--- a/support/resolv_test.h
+++ b/support/resolv_test.h
@@ -148,6 +148,10 @@ struct resolv_response_flags
/* If true, the AD (authenticated data) flag will be set. */
bool ad;
+ /* If true, do not set the RA (recursion available) flag in the
+ response. */
+ bool clear_ra;
+
/* Initial section count values. Can be used to artificially
increase the counts, for malformed packet testing.*/
unsigned short qdcount;

View File

@ -0,0 +1,442 @@
commit f1f00c072138af90ae6da180f260111f09afe7a3
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Oct 14 10:54:39 2020 +0200
resolv: Handle transaction ID collisions in parallel queries (bug 26600)
If the transaction IDs are equal, the old check attributed both
responses to the first query, not recognizing the second response.
This fixes bug 26600.
diff --git a/resolv/Makefile b/resolv/Makefile
index 72a0f196506ac489..cee5225f8933f245 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -62,6 +62,11 @@ tests += \
tst-resolv-search \
tst-resolv-trailing \
+# This test calls __res_context_send directly, which is not exported
+# from libresolv.
+tests-internal += tst-resolv-txnid-collision
+tests-static += tst-resolv-txnid-collision
+
# These tests need libdl.
ifeq (yes,$(build-shared))
tests += \
@@ -202,6 +207,8 @@ $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-threads: \
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \
+ $(static-thread-library)
$(objpfx)tst-resolv-canonname: \
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/res_send.c b/resolv/res_send.c
index c9b02cca130bc20d..ac19627634281c2f 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -1315,15 +1315,6 @@ send_dg(res_state statp,
*terrno = EMSGSIZE;
return close_and_return_error (statp, resplen2);
}
- if ((recvresp1 || hp->id != anhp->id)
- && (recvresp2 || hp2->id != anhp->id)) {
- /*
- * response from old query, ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
/* Paranoia check. Due to the connected UDP socket,
the kernel has already filtered invalid addresses
@@ -1333,15 +1324,24 @@ send_dg(res_state statp,
/* Check for the correct header layout and a matching
question. */
- if ((recvresp1 || !res_queriesmatch(buf, buf + buflen,
- *thisansp,
- *thisansp
- + *thisanssizp))
- && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
- *thisansp,
- *thisansp
- + *thisanssizp)))
- goto wait;
+ int matching_query = 0; /* Default to no matching query. */
+ if (!recvresp1
+ && anhp->id == hp->id
+ && res_queriesmatch (buf, buf + buflen,
+ *thisansp, *thisansp + *thisanssizp))
+ matching_query = 1;
+ if (!recvresp2
+ && anhp->id == hp2->id
+ && res_queriesmatch (buf2, buf2 + buflen2,
+ *thisansp, *thisansp + *thisanssizp))
+ matching_query = 2;
+ if (matching_query == 0)
+ /* Spurious UDP packet. Drop it and continue
+ waiting. */
+ {
+ need_recompute = 1;
+ goto wait;
+ }
if (anhp->rcode == SERVFAIL ||
anhp->rcode == NOTIMP ||
@@ -1356,7 +1356,7 @@ send_dg(res_state statp,
/* No data from the first reply. */
resplen = 0;
/* We are waiting for a possible second reply. */
- if (hp->id == anhp->id)
+ if (matching_query == 1)
recvresp1 = 1;
else
recvresp2 = 1;
@@ -1387,7 +1387,7 @@ send_dg(res_state statp,
return (1);
}
/* Mark which reply we received. */
- if (recvresp1 == 0 && hp->id == anhp->id)
+ if (matching_query == 1)
recvresp1 = 1;
else
recvresp2 = 1;
diff --git a/resolv/tst-resolv-txnid-collision.c b/resolv/tst-resolv-txnid-collision.c
new file mode 100644
index 0000000000000000..611d37362f3e5e89
--- /dev/null
+++ b/resolv/tst-resolv-txnid-collision.c
@@ -0,0 +1,329 @@
+/* Test parallel queries with transaction ID collisions.
+ Copyright (C) 2020 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <arpa/nameser.h>
+#include <array_length.h>
+#include <resolv-internal.h>
+#include <resolv_context.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+
+/* Result of parsing a DNS question name.
+
+ A question name has the form reorder-N-M-rcode-C.example.net, where
+ N and M are either 0 and 1, corresponding to the reorder member,
+ and C is a number that will be stored in the rcode field.
+
+ Also see parse_qname below. */
+struct parsed_qname
+{
+ /* The DNS response code requested from the first server. The
+ second server always responds with RCODE zero. */
+ int rcode;
+
+ /* Indicates whether to perform reordering in the responses from the
+ respective server. */
+ bool reorder[2];
+};
+
+/* Fills *PARSED based on QNAME. */
+static void
+parse_qname (struct parsed_qname *parsed, const char *qname)
+{
+ int reorder0;
+ int reorder1;
+ int rcode;
+ char *suffix;
+ if (sscanf (qname, "reorder-%d-%d.rcode-%d.%ms",
+ &reorder0, &reorder1, &rcode, &suffix) == 4)
+ {
+ if (reorder0 != 0)
+ TEST_COMPARE (reorder0, 1);
+ if (reorder1 != 0)
+ TEST_COMPARE (reorder1, 1);
+ TEST_VERIFY (rcode >= 0 && rcode <= 15);
+ TEST_COMPARE_STRING (suffix, "example.net");
+ free (suffix);
+
+ parsed->rcode = rcode;
+ parsed->reorder[0] = reorder0;
+ parsed->reorder[1] = reorder1;
+ }
+ else
+ FAIL_EXIT1 ("unexpected query: %s", qname);
+}
+
+/* Used to construct a response. The first server responds with an
+ error, the second server succeeds. */
+static void
+build_response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ struct parsed_qname parsed;
+ parse_qname (&parsed, qname);
+
+ switch (ctx->server_index)
+ {
+ case 0:
+ {
+ struct resolv_response_flags flags = { 0 };
+ if (parsed.rcode == 0)
+ /* Simulate a delegation in case a NODATA (RCODE zero)
+ response is requested. */
+ flags.clear_ra = true;
+ else
+ flags.rcode = parsed.rcode;
+
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+ }
+ break;
+
+ case 1:
+ {
+ struct resolv_response_flags flags = { 0, };
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+
+ resolv_response_section (b, ns_s_an);
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
+ if (qtype == T_A)
+ {
+ char ipv4[4] = { 192, 0, 2, 1 };
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+ }
+ else
+ {
+ char ipv6[16]
+ = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+ }
+ resolv_response_close_record (b);
+ }
+ break;
+ }
+}
+
+/* Used to reorder responses. */
+struct resolv_response_context *previous_query;
+
+/* Used to keep track of the queries received. */
+static int previous_server_index = -1;
+static uint16_t previous_qtype;
+
+/* For each server, buffer the first query and then send both answers
+ to the second query, reordered if requested. */
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ TEST_VERIFY (qtype == T_A || qtype == T_AAAA);
+ if (ctx->server_index != 0)
+ TEST_COMPARE (ctx->server_index, 1);
+
+ struct parsed_qname parsed;
+ parse_qname (&parsed, qname);
+
+ if (previous_query == NULL)
+ {
+ /* No buffered query. Record this query and do not send a
+ response. */
+ TEST_COMPARE (previous_qtype, 0);
+ previous_query = resolv_response_context_duplicate (ctx);
+ previous_qtype = qtype;
+ resolv_response_drop (b);
+ previous_server_index = ctx->server_index;
+
+ if (test_verbose)
+ printf ("info: buffering first query for: %s\n", qname);
+ }
+ else
+ {
+ TEST_VERIFY (previous_query != 0);
+ TEST_COMPARE (ctx->server_index, previous_server_index);
+ TEST_VERIFY (previous_qtype != qtype); /* Not a duplicate. */
+
+ /* If reordering, send a response for this query explicitly, and
+ then skip the implicit send. */
+ if (parsed.reorder[ctx->server_index])
+ {
+ if (test_verbose)
+ printf ("info: sending reordered second response for: %s\n",
+ qname);
+ build_response (ctx, b, qname, qclass, qtype);
+ resolv_response_send_udp (ctx, b);
+ resolv_response_drop (b);
+ }
+
+ /* Build a response for the previous query and send it, thus
+ reordering the two responses. */
+ {
+ if (test_verbose)
+ printf ("info: sending first response for: %s\n", qname);
+ struct resolv_response_builder *btmp
+ = resolv_response_builder_allocate (previous_query->query_buffer,
+ previous_query->query_length);
+ build_response (ctx, btmp, qname, qclass, previous_qtype);
+ resolv_response_send_udp (ctx, btmp);
+ resolv_response_builder_free (btmp);
+ }
+
+ /* If not reordering, send the reply as usual. */
+ if (!parsed.reorder[ctx->server_index])
+ {
+ if (test_verbose)
+ printf ("info: sending non-reordered second response for: %s\n",
+ qname);
+ build_response (ctx, b, qname, qclass, qtype);
+ }
+
+ /* Unbuffer the response and prepare for the next query. */
+ resolv_response_context_free (previous_query);
+ previous_query = NULL;
+ previous_qtype = 0;
+ previous_server_index = -1;
+ }
+}
+
+/* Runs a query for QNAME and checks for the expected reply. See
+ struct parsed_qname for the expected format for QNAME. */
+static void
+test_qname (const char *qname, int rcode)
+{
+ struct resolv_context *ctx = __resolv_context_get ();
+ TEST_VERIFY_EXIT (ctx != NULL);
+
+ unsigned char q1[512];
+ int q1len = res_mkquery (QUERY, qname, C_IN, T_A, NULL, 0, NULL,
+ q1, sizeof (q1));
+ TEST_VERIFY_EXIT (q1len > 12);
+
+ unsigned char q2[512];
+ int q2len = res_mkquery (QUERY, qname, C_IN, T_AAAA, NULL, 0, NULL,
+ q2, sizeof (q2));
+ TEST_VERIFY_EXIT (q2len > 12);
+
+ /* Produce a transaction ID collision. */
+ memcpy (q2, q1, 2);
+
+ unsigned char ans1[512];
+ unsigned char *ans1p = ans1;
+ unsigned char *ans2p = NULL;
+ int nans2p = 0;
+ int resplen2 = 0;
+ int ans2p_malloced = 0;
+
+ /* Perform a parallel A/AAAA query. */
+ int resplen1 = __res_context_send (ctx, q1, q1len, q2, q2len,
+ ans1, sizeof (ans1), &ans1p,
+ &ans2p, &nans2p,
+ &resplen2, &ans2p_malloced);
+
+ TEST_VERIFY (resplen1 > 12);
+ TEST_VERIFY (resplen2 > 12);
+ if (resplen1 <= 12 || resplen2 <= 12)
+ return;
+
+ if (rcode == 1 || rcode == 3)
+ {
+ /* Format Error and Name Error responses does not trigger
+ switching to the next server. */
+ TEST_COMPARE (ans1p[3] & 0x0f, rcode);
+ TEST_COMPARE (ans2p[3] & 0x0f, rcode);
+ return;
+ }
+
+ /* The response should be successful. */
+ TEST_COMPARE (ans1p[3] & 0x0f, 0);
+ TEST_COMPARE (ans2p[3] & 0x0f, 0);
+
+ /* Due to bug 19691, the answer may not be in the slot matching the
+ query. Assume that the AAAA response is the longer one. */
+ unsigned char *a_answer;
+ int a_answer_length;
+ unsigned char *aaaa_answer;
+ int aaaa_answer_length;
+ if (resplen2 > resplen1)
+ {
+ a_answer = ans1p;
+ a_answer_length = resplen1;
+ aaaa_answer = ans2p;
+ aaaa_answer_length = resplen2;
+ }
+ else
+ {
+ a_answer = ans2p;
+ a_answer_length = resplen2;
+ aaaa_answer = ans1p;
+ aaaa_answer_length = resplen1;
+ }
+
+ {
+ char *expected = xasprintf ("name: %s\n"
+ "address: 192.0.2.1\n",
+ qname);
+ check_dns_packet (qname, a_answer, a_answer_length, expected);
+ free (expected);
+ }
+ {
+ char *expected = xasprintf ("name: %s\n"
+ "address: 2001:db8::1\n",
+ qname);
+ check_dns_packet (qname, aaaa_answer, aaaa_answer_length, expected);
+ free (expected);
+ }
+
+ if (ans2p_malloced)
+ free (ans2p);
+
+ __resolv_context_put (ctx);
+}
+
+static int
+do_test (void)
+{
+ struct resolv_test *aux = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response,
+ });
+
+ for (int rcode = 0; rcode <= 5; ++rcode)
+ for (int do_reorder_0 = 0; do_reorder_0 < 2; ++do_reorder_0)
+ for (int do_reorder_1 = 0; do_reorder_1 < 2; ++do_reorder_1)
+ {
+ char *qname = xasprintf ("reorder-%d-%d.rcode-%d.example.net",
+ do_reorder_0, do_reorder_1, rcode);
+ test_qname (qname, rcode);
+ free (qname);
+ }
+
+ resolv_test_end (aux);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,31 @@
commit b8b53b338f6da91e86d115a39da860cefac736ad
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Oct 15 12:33:13 2020 +0200
resolv: Serialize processing in resolv/tst-resolv-txnid-collision
When switching name servers, response processing by two server
threads clobbers the global test state. (There is still some
risk that this test is negatively impact by packet drops and
packet reordering, but this applies to many of the resolver tests
and is difficult to avoid.)
Fixes commit f1f00c072138af90ae6da180f260111f09afe7a3 ("resolv:
Handle transaction ID collisions in parallel queries (bug 26600)").
diff --git a/resolv/tst-resolv-txnid-collision.c b/resolv/tst-resolv-txnid-collision.c
index 611d37362f3e5e89..189b76f1268f4e4d 100644
--- a/resolv/tst-resolv-txnid-collision.c
+++ b/resolv/tst-resolv-txnid-collision.c
@@ -309,6 +309,11 @@ do_test (void)
((struct resolv_redirect_config)
{
.response_callback = response,
+
+ /* The response callback use global state (the previous_*
+ variables), and query processing must therefore be
+ serialized. */
+ .single_thread_udp = true,
});
for (int rcode = 0; rcode <= 5; ++rcode)

View File

@ -0,0 +1,97 @@
commit d3c57027470b78dba79c6d931e4e409b1fecfc80
Author: Patrick McGehearty <patrick.mcgehearty@oracle.com>
Date: Mon Sep 28 20:11:28 2020 +0000
Reversing calculation of __x86_shared_non_temporal_threshold
The __x86_shared_non_temporal_threshold determines when memcpy on x86
uses non_temporal stores to avoid pushing other data out of the last
level cache.
This patch proposes to revert the calculation change made by H.J. Lu's
patch of June 2, 2017.
H.J. Lu's patch selected a threshold suitable for a single thread
getting maximum performance. It was tuned using the single threaded
large memcpy micro benchmark on an 8 core processor. The last change
changes the threshold from using 3/4 of one thread's share of the
cache to using 3/4 of the entire cache of a multi-threaded system
before switching to non-temporal stores. Multi-threaded systems with
more than a few threads are server-class and typically have many
active threads. If one thread consumes 3/4 of the available cache for
all threads, it will cause other active threads to have data removed
from the cache. Two examples show the range of the effect. John
McCalpin's widely parallel Stream benchmark, which runs in parallel
and fetches data sequentially, saw a 20% slowdown with this patch on
an internal system test of 128 threads. This regression was discovered
when comparing OL8 performance to OL7. An example that compares
normal stores to non-temporal stores may be found at
https://vgatherps.github.io/2018-09-02-nontemporal/. A simple test
shows performance loss of 400 to 500% due to a failure to use
nontemporal stores. These performance losses are most likely to occur
when the system load is heaviest and good performance is critical.
The tunable x86_non_temporal_threshold can be used to override the
default for the knowledgable user who really wants maximum cache
allocation to a single thread in a multi-threaded system.
The manual entry for the tunable has been expanded to provide
more information about its purpose.
modified: sysdeps/x86/cacheinfo.c
modified: manual/tunables.texi
Conflicts:
manual/tunables.texi
(Downstream uses the glibc.tune namespace, upstream uses
glibc.cpu.)
sysdeps/x86/cacheinfo.c
(Downstream does not have rep_movsb_threshold,
x86_rep_stosb_threshold tunables.)
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 3dc6f9a44592c030..3e1e519dff153b09 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -364,7 +364,11 @@ set shared cache size in bytes for use in memory and string routines.
@deftp Tunable glibc.tune.x86_non_temporal_threshold
The @code{glibc.tune.x86_non_temporal_threshold} tunable allows the user
-to set threshold in bytes for non temporal store.
+to set threshold in bytes for non temporal store. Non temporal stores
+give a hint to the hardware to move data directly to memory without
+displacing other data from the cache. This tunable is used by some
+platforms to determine when to use non temporal stores in operations
+like memmove and memcpy.
This tunable is specific to i386 and x86-64.
@end deftp
diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c
index b9444ddd52051e05..42b468d0c4885bad 100644
--- a/sysdeps/x86/cacheinfo.c
+++ b/sysdeps/x86/cacheinfo.c
@@ -778,14 +778,20 @@ intel_bug_no_cache_info:
__x86_shared_cache_size = shared;
}
- /* The large memcpy micro benchmark in glibc shows that 6 times of
- shared cache size is the approximate value above which non-temporal
- store becomes faster on a 8-core processor. This is the 3/4 of the
- total shared cache size. */
+ /* The default setting for the non_temporal threshold is 3/4 of one
+ thread's share of the chip's cache. For most Intel and AMD processors
+ with an initial release date between 2017 and 2020, a thread's typical
+ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4
+ threshold leaves 125 KBytes to 500 KBytes of the thread's data
+ in cache after a maximum temporal copy, which will maintain
+ in cache a reasonable portion of the thread's stack and other
+ active data. If the threshold is set higher than one thread's
+ share of the cache, it has a substantial risk of negatively
+ impacting the performance of other threads running on the chip. */
__x86_shared_non_temporal_threshold
= (cpu_features->non_temporal_threshold != 0
? cpu_features->non_temporal_threshold
- : __x86_shared_cache_size * threads * 3 / 4);
+ : __x86_shared_cache_size * 3 / 4);
}
#endif

View File

@ -0,0 +1,64 @@
commit 8813b2682e4094e43b0cf1634e99619f1b8b2c62
Author: Sajan Karumanchi <sajan.karumanchi@amd.com>
Date: Wed Oct 28 13:05:33 2020 +0530
x86: Optimizing memcpy for AMD Zen architecture.
Modifying the shareable cache '__x86_shared_cache_size', which is a
factor in computing the non-temporal threshold parameter
'__x86_shared_non_temporal_threshold' to optimize memcpy for AMD Zen
architectures.
In the existing implementation, the shareable cache is computed as 'L3
per thread, L2 per core'. Recomputing this shareable cache as 'L3 per
CCX(Core-Complex)' has brought in performance gains.
As per the large bench variant results, this patch also addresses the
regression problem on AMD Zen architectures.
Backport of commit 59803e81f96b479c17f583b31eac44b57591a1bf upstream,
with the fix from cb3a749a22a55645dc6a52659eea765300623f98 ("x86:
Restore processing of cache size tunables in init_cacheinfo") applied.
Reviewed-by: Premachandra Mallappa <premachandra.mallappa@amd.com>
Co-Authored-by: Florian Weimer <fweimer@redhat.com>
Backport is off the release/2.32/master branch upstream, to minimize
conflicts. Adjusted for missing "basic" member in struct cpu_features.
diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c
index 42b468d0c4885bad..57c36d030a76c8b2 100644
--- a/sysdeps/x86/cacheinfo.c
+++ b/sysdeps/x86/cacheinfo.c
@@ -722,7 +722,7 @@ intel_bug_no_cache_info:
threads = 1 << ((ecx >> 12) & 0x0f);
}
- if (threads == 0)
+ if (threads == 0 || cpu_features->family >= 0x17)
{
/* If APIC ID width is not available, use logical
processor count. */
@@ -737,8 +737,22 @@ intel_bug_no_cache_info:
if (threads > 0)
shared /= threads;
- /* Account for exclusive L2 and L3 caches. */
- shared += core;
+ /* Get shared cache per ccx for Zen architectures. */
+ if (cpu_features->family >= 0x17)
+ {
+ unsigned int eax;
+
+ /* Get number of threads share the L3 cache in CCX. */
+ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
+
+ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
+ shared *= threads_per_ccx;
+ }
+ else
+ {
+ /* Account for exclusive L2 and L3 caches. */
+ shared += core;
+ }
}
#ifndef DISABLE_PREFETCHW

View File

@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.28
%define glibcversion 2.28
%define glibcrelease 127%{?dist}
%define glibcrelease 127%{?dist}.2
# Pre-release tarballs are pulled in from git using a command that is
# effectively:
#
@ -486,6 +486,14 @@ Patch352: glibc-rh1642150-4.patch
Patch353: glibc-rh1836867.patch
Patch354: glibc-rh1821531-1.patch
Patch355: glibc-rh1821531-2.patch
Patch356: glibc-rh1904153-1.patch
Patch357: glibc-rh1904153-2.patch
Patch358: glibc-rh1904153-3.patch
Patch359: glibc-rh1904153-4.patch
Patch360: glibc-rh1904153-5.patch
Patch361: glibc-rh1904153-6.patch
Patch362: glibc-rh1913750-1.patch
Patch363: glibc-rh1913750-2.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2384,6 +2392,12 @@ fi
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog
* Tue Jan 5 2021 Florian Weimer <fweimer@redhat.com> - 2.28-127.2
- x86: Update auto-tuning of memcpy non-temporal threshold (#1913750)
* Mon Dec 7 2020 Florian Weimer <fweimer@redhat.com> - 2.28-127.1
- resolv: Handle DNS transaction ID collisions (#1904153)
* Tue Jun 09 2020 Carlos O'Donell <calros@redhat.com> - 2.28-127
- Improve performance of library strstr() function (#1821531)