From 2111a3d16df0471f2f7ed91bfa1716290864d345 Mon Sep 17 00:00:00 2001 From: Patsy Griffin Date: Fri, 6 Jun 2025 14:04:39 -0400 Subject: [PATCH] Keep reloading /etc/resolv.conf after timeouts with getaddrinfo and AF_UNSPEC. Avoid timeouts with getaddrinfo, AF_UNSPEC, and certain DNS error responses. Resolves: RHEL-18039 --- glibc-RHEL-18039-1.patch | 59 +++++++++++ glibc-RHEL-18039-2.patch | 197 +++++++++++++++++++++++++++++++++++++ glibc-RHEL-18039-3.patch | 203 ++++++++++++++++++++++++++++++++++++++ glibc-RHEL-18039-4.patch | 81 +++++++++++++++ glibc-RHEL-18039-5.patch | 207 +++++++++++++++++++++++++++++++++++++++ glibc-RHEL-18039-6.patch | 28 ++++++ glibc.spec | 14 ++- 7 files changed, 788 insertions(+), 1 deletion(-) create mode 100644 glibc-RHEL-18039-1.patch create mode 100644 glibc-RHEL-18039-2.patch create mode 100644 glibc-RHEL-18039-3.patch create mode 100644 glibc-RHEL-18039-4.patch create mode 100644 glibc-RHEL-18039-5.patch create mode 100644 glibc-RHEL-18039-6.patch diff --git a/glibc-RHEL-18039-1.patch b/glibc-RHEL-18039-1.patch new file mode 100644 index 0000000..237d979 --- /dev/null +++ b/glibc-RHEL-18039-1.patch @@ -0,0 +1,59 @@ +commit 868ab8923a2ec977faafec97ecafac0c3159c1b2 +Author: Florian Weimer +Date: Thu Jun 13 18:56:30 2024 +0200 + + resolv: Track single-request fallback via _res._flags (bug 31476) + + This avoids changing _res.options, which inteferes with change + detection as part of automatic reloading of /etc/resolv.conf. + + Reviewed-by: DJ Delorie + +diff -Nrup a/resolv/res_send.c b/resolv/res_send.c +--- a/resolv/res_send.c 2025-02-19 21:54:08.104421209 -0500 ++++ b/resolv/res_send.c 2025-02-19 21:54:51.202625194 -0500 +@@ -1065,9 +1065,11 @@ send_dg(res_state statp, + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; +- bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0; +- bool single_request = (((statp->options & RES_SNGLKUP) != 0) +- | single_request_reopen); ++ bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP) ++ || (statp->_flags & RES_F_SNGLKUPREOP)); ++ bool single_request = ((statp->options & RES_SNGLKUP) ++ || (statp->_flags & RES_F_SNGLKUP) ++ || single_request_reopen); + int save_gotsomewhere = *gotsomewhere; + + int retval; +@@ -1124,14 +1126,14 @@ send_dg(res_state statp, + have received the first answer. */ + if (!single_request) + { +- statp->options |= RES_SNGLKUP; ++ statp->_flags |= RES_F_SNGLKUP; + single_request = true; + *gotsomewhere = save_gotsomewhere; + goto retry; + } + else if (!single_request_reopen) + { +- statp->options |= RES_SNGLKUPREOP; ++ statp->_flags |= RES_F_SNGLKUPREOP; + single_request_reopen = true; + *gotsomewhere = save_gotsomewhere; + __res_iclose (statp, false); +diff -Nrup a/resolv/resolv-internal.h b/resolv/resolv-internal.h +--- a/resolv/resolv-internal.h 2025-02-19 21:54:08.104421209 -0500 ++++ b/resolv/resolv-internal.h 2025-02-19 21:56:25.771072777 -0500 +@@ -26,7 +26,8 @@ + #define RES_F_VC 0x00000001 /* Socket is TCP. */ + #define RES_F_CONN 0x00000002 /* Socket is connected. */ + #define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors. */ +- ++#define RES_F_SNGLKUP 0x00200000 /* Private version of RES_SNGLKUP. */ ++#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP. */ + + /* Internal version of RES_USE_INET6 which does not trigger a + deprecation warning. */ diff --git a/glibc-RHEL-18039-2.patch b/glibc-RHEL-18039-2.patch new file mode 100644 index 0000000..5baab0e --- /dev/null +++ b/glibc-RHEL-18039-2.patch @@ -0,0 +1,197 @@ +commit 691a3b2e9bfaba842e46a5ccb7f5e6ea144c3ade +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Allow short error responses to match any query (bug 31890) + + Reviewed-by: DJ Delorie + +Conflicts: + resolv/res_send.c: res_queriesmatch/__libc_res_queriesmatch + +diff -Nrup a/resolv/Makefile b/resolv/Makefile +--- a/resolv/Makefile 2025-06-06 08:53:20.890276516 -0400 ++++ b/resolv/Makefile 2025-06-06 08:57:09.981844872 -0400 +@@ -62,6 +62,7 @@ tests += \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-short-response \ + tst-resolv-trailing \ + + # This test calls __res_context_send directly, which is not exported +@@ -208,6 +209,8 @@ $(objpfx)tst-resolv-nondecimal: $(objpfx + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-short-response: $(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) +diff -Nrup a/resolv/res_send.c b/resolv/res_send.c +--- a/resolv/res_send.c 2025-06-06 08:53:30.892216323 -0400 ++++ b/resolv/res_send.c 2025-06-06 08:59:35.588914830 -0400 +@@ -1322,17 +1322,30 @@ send_dg(res_state statp, + goto wait; + + /* Check for the correct header layout and a matching +- question. */ ++ question. Some recursive resolvers send REFUSED ++ without copying back the question section ++ (producing a response that is only HFIXEDSZ bytes ++ long). Skip query matching in this case. */ ++ bool thisansp_error = (anhp->rcode == SERVFAIL || ++ anhp->rcode == NOTIMP || ++ anhp->rcode == REFUSED); ++ bool skip_query_match = (*thisresplenp == HFIXEDSZ ++ && ntohs (anhp->qdcount) == 0 ++ && thisansp_error); + int matching_query = 0; /* Default to no matching query. */ + if (!recvresp1 + && anhp->id == hp->id +- && res_queriesmatch (buf, buf + buflen, +- *thisansp, *thisansp + *thisanssizp)) ++ && (skip_query_match ++ || 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)) ++ && (skip_query_match ++ || res_queriesmatch (buf2, buf2 + buflen2, ++ *thisansp, ++ *thisansp + *thisanssizp))) + matching_query = 2; + if (matching_query == 0) + /* Spurious UDP packet. Drop it and continue +@@ -1342,9 +1355,7 @@ send_dg(res_state statp, + goto wait; + } + +- if (anhp->rcode == SERVFAIL || +- anhp->rcode == NOTIMP || +- anhp->rcode == REFUSED) { ++ if (thisansp_error) { + next_ns: + if (recvresp1 || (buf2 != NULL && recvresp2)) { + *resplen2 = 0; +diff -Nrup a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +--- a/resolv/tst-resolv-short-response.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/resolv/tst-resolv-short-response.c 2025-06-06 08:57:09.987844834 -0400 +@@ -0,0 +1,112 @@ ++/* Test for spurious timeouts with short 12-byte responses (bug 31890). ++ Copyright (C) 2024 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 ++ ++/* The rcode in the initial response. */ ++static volatile int rcode; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ switch (ctx->server_index) ++ { ++ case 0: ++ /* First server times out. */ ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ break; ++ case 1: ++ /* Second server sends reply. */ ++ resolv_response_init (b, (struct resolv_response_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); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ char ipv4[4] = {192, 0, 2, 17}; ++ 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, 0, 1}; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ break; ++ default: ++ FAIL_EXIT1 ("unexpected TYPE%d query", qtype); ++ } ++ resolv_response_close_record (b); ++ break; ++ default: ++ FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index); ++ } ++} ++ ++static void ++check_one (void) ++{ ++ ++ /* The buggy 1-second query timeout results in 30 seconds of delay, ++ which triggers a test timeout failure. */ ++ for (int i = 0; i < 10; ++i) ++ { ++ check_hostent ("www.example", gethostbyname ("www.example"), ++ "name: www.example\n" ++ "address: 192.0.2.17\n"); ++ check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), ++ "name: www.example\n" ++ "address: 2001:db8::1\n"); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ _res.options |= RES_SNGLKUP; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-18039-3.patch b/glibc-RHEL-18039-3.patch new file mode 100644 index 0000000..68c505b --- /dev/null +++ b/glibc-RHEL-18039-3.patch @@ -0,0 +1,203 @@ +commit af625987d619388a100b153520d3ee308bda9889 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Do not wait for non-existing second DNS response after error (bug 30081) + + In single-request mode, there is no second response after an error + because the second query has not been sent yet. Waiting for it + introduces an unnecessary timeout. + + Reviewed-by: DJ Delorie + +diff -Nrup a/resolv/Makefile b/resolv/Makefile +--- a/resolv/Makefile 2025-02-19 22:32:03.567568899 -0500 ++++ b/resolv/Makefile 2025-02-19 22:36:58.647149025 -0500 +@@ -62,6 +62,7 @@ tests += \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-semi-failure \ + tst-resolv-short-response \ + tst-resolv-trailing \ + +@@ -209,6 +210,8 @@ $(objpfx)tst-resolv-nondecimal: $(objpfx + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-semi-failure: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) +diff -Nrup a/resolv/res_send.c b/resolv/res_send.c +--- a/resolv/res_send.c 2025-02-19 22:32:03.567568899 -0500 ++++ b/resolv/res_send.c 2025-02-19 22:34:59.213509475 -0500 +@@ -1361,7 +1361,7 @@ send_dg(res_state statp, + *resplen2 = 0; + return resplen; + } +- if (buf2 != NULL) ++ if (buf2 != NULL && !single_request) + { + /* No data from the first reply. */ + resplen = 0; +diff -Nrup a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +--- a/resolv/tst-resolv-semi-failure.c 1969-12-31 19:00:00.000000000 -0500 ++++ b/resolv/tst-resolv-semi-failure.c 2025-02-19 22:34:59.213509475 -0500 +@@ -0,0 +1,133 @@ ++/* Test parallel failure/success responses (bug 30081). ++ Copyright (C) 2024 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 ++ ++/* The rcode in the initial response. */ ++static volatile int rcode; ++ ++/* Whether to fail the initial A query (!fail_aaaa) or the initial ++ AAAA query (fail_aaaa). */ ++static volatile bool fail_aaaa; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* Handle the failing query. */ ++ if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0) ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ return; ++ } ++ ++ /* Otherwise produce a response. */ ++ resolv_response_init (b, (struct resolv_response_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); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ char ipv4[4] = {192, 0, 2, 17}; ++ 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, 0, 1}; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ break; ++ default: ++ FAIL_EXIT1 ("unexpected TYPE%d query", qtype); ++ } ++ resolv_response_close_record (b); ++} ++ ++static void ++check_one (void) ++{ ++ ++ /* The buggy 1-second query timeout results in 30 seconds of delay, ++ which triggers are test timeout failure. */ ++ for (int i = 0; i < 30; ++i) ++ { ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ const char *expected; ++ if (ret == 0 && ai->ai_next != NULL) ++ expected = ("address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ else ++ /* Only one response because the AAAA lookup failure is ++ treated as an ignoreable error. */ ++ expected = "address: STREAM/TCP 192.0.2.17 80\n"; ++ check_addrinfo ("www.example", ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; ++ ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } ++ ++ resolv_test_end (aux); ++ } ++ ++ return 0; ++} ++ ++#include +diff -Nrup a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +--- a/resolv/tst-resolv-short-response.c 2025-02-19 22:32:03.567568899 -0500 ++++ b/resolv/tst-resolv-short-response.c 2025-02-19 22:34:59.213509475 -0500 +@@ -81,6 +81,18 @@ check_one (void) + check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), + "name: www.example\n" + "address: 2001:db8::1\n"); ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ check_addrinfo ("www.example", ai, ret, ++ "address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ if (ret == 0) ++ freeaddrinfo (ai); + } + } + diff --git a/glibc-RHEL-18039-4.patch b/glibc-RHEL-18039-4.patch new file mode 100644 index 0000000..8313e68 --- /dev/null +++ b/glibc-RHEL-18039-4.patch @@ -0,0 +1,81 @@ +commit 95f61610f3e481d191b6184432342236fd59186d +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Support clearing option flags with a “-” prefix (bug 14799) + + I think using a “-” prefix is less confusing than introducing + double-negation construct (“no-no-tld-query”). + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS: Dropped + resolv/res_init.c: DEPRECATED_RES_USE_INET6 and RES_TRUSTAD + +diff -Nrup a/resolv/res_init.c b/resolv/res_init.c +--- a/resolv/res_init.c 2025-05-21 08:57:39.108958310 -0400 ++++ b/resolv/res_init.c 2025-05-21 08:59:11.528419481 -0400 +@@ -682,27 +682,29 @@ res_setoptions (struct resolv_conf_parse + { + char str[22]; + uint8_t len; +- uint8_t clear; + unsigned long int flag; + } options[] = { + #define STRnLEN(str) str, sizeof (str) - 1 +- { STRnLEN ("inet6"), 0, DEPRECATED_RES_USE_INET6 }, +- { STRnLEN ("rotate"), 0, RES_ROTATE }, +- { STRnLEN ("edns0"), 0, RES_USE_EDNS0 }, +- { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP }, +- { STRnLEN ("single-request"), 0, RES_SNGLKUP }, +- { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-reload"), 0, RES_NORELOAD }, +- { STRnLEN ("use-vc"), 0, RES_USEVC }, +- { STRnLEN ("no-aaaa"), 0, RES_NOAAAA }, ++ { STRnLEN ("inet6"), DEPRECATED_RES_USE_INET6 }, ++ { STRnLEN ("rotate"), RES_ROTATE }, ++ { STRnLEN ("edns0"), RES_USE_EDNS0 }, ++ { STRnLEN ("single-request-reopen"), RES_SNGLKUPREOP }, ++ { STRnLEN ("single-request"), RES_SNGLKUP }, ++ { STRnLEN ("no_tld_query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-tld-query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-reload"), RES_NORELOAD }, ++ { STRnLEN ("use-vc"), RES_USEVC }, ++ { STRnLEN ("no-aaaa"), RES_NOAAAA }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) ++ bool negate_option = *cp == '-'; ++ if (negate_option) ++ ++cp; + for (int i = 0; i < noptions; ++i) + if (strncmp (cp, options[i].str, options[i].len) == 0) + { +- if (options[i].clear) +- parser->template.options &= options[i].flag; ++ if (negate_option) ++ parser->template.options &= ~options[i].flag; + else + parser->template.options |= options[i].flag; + break; +diff -Nrup a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +--- a/resolv/tst-resolv-res_init-skeleton.c 2025-05-21 08:57:39.109958315 -0400 ++++ b/resolv/tst-resolv-res_init-skeleton.c 2025-05-21 08:58:09.541110166 -0400 +@@ -680,6 +680,16 @@ struct test_case test_cases[] = + "; nameserver[0]: [192.0.2.1]:53\n", + .res_options = "attempts:5 ndots:3 edns0 ", + }, ++ {.name = "RES_OPTIONS can clear flags", ++ .conf = "options ndots:2 use-vc no-aaaa edns0\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options ndots:3 use-vc\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n", ++ .res_options = "ndots:3 -edns0 -no-aaaa", ++ }, + {.name = "many search list entries (bug 19569)", + .conf = "nameserver 192.0.2.1\n" + "search corp.example.com support.example.com" diff --git a/glibc-RHEL-18039-5.patch b/glibc-RHEL-18039-5.patch new file mode 100644 index 0000000..41d36fd --- /dev/null +++ b/glibc-RHEL-18039-5.patch @@ -0,0 +1,207 @@ +commit 765325951ac5c7d072278c9424930b29657e9758 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Implement strict-error stub resolver option (bug 27929) + + For now, do not enable this mode by default due to the potential + impact on compatibility with existing deployments. + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS + (Dropped) + +diff -Nrup a/resolv/res_init.c b/resolv/res_init.c +--- a/resolv/res_init.c 2025-06-06 07:00:12.496548260 -0400 ++++ b/resolv/res_init.c 2025-06-06 07:02:49.092632696 -0400 +@@ -695,6 +695,7 @@ res_setoptions (struct resolv_conf_parse + { STRnLEN ("no-reload"), RES_NORELOAD }, + { STRnLEN ("use-vc"), RES_USEVC }, + { STRnLEN ("no-aaaa"), RES_NOAAAA }, ++ { STRnLEN ("strict-error"), RES_STRICTERR }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) + bool negate_option = *cp == '-'; +diff -Nrup a/resolv/res_send.c b/resolv/res_send.c +--- a/resolv/res_send.c 2025-06-06 07:00:12.434548622 -0400 ++++ b/resolv/res_send.c 2025-06-06 07:02:49.095632678 -0400 +@@ -1357,21 +1357,38 @@ send_dg(res_state statp, + + if (thisansp_error) { + next_ns: +- if (recvresp1 || (buf2 != NULL && recvresp2)) { +- *resplen2 = 0; +- return resplen; +- } +- if (buf2 != NULL && !single_request) ++ /* Outside of strict-error mode, use the first ++ response even if the second response is an ++ error. This allows parallel resolution to ++ succeed even if the recursive resolver ++ always answers with SERVFAIL for AAAA ++ queries (which still happens in practice ++ unfortunately). ++ ++ In strict-error mode, always switch to the ++ next server and try to get a response from ++ there. */ ++ if ((statp->options & RES_STRICTERR) == 0) + { +- /* No data from the first reply. */ +- resplen = 0; +- /* We are waiting for a possible second reply. */ +- if (matching_query == 1) +- recvresp1 = 1; +- else +- recvresp2 = 1; ++ if (recvresp1 || (buf2 != NULL && recvresp2)) ++ { ++ *resplen2 = 0; ++ return resplen; ++ } ++ ++ if (buf2 != NULL && !single_request) ++ { ++ /* No data from the first reply. */ ++ resplen = 0; ++ /* We are waiting for a possible ++ second reply. */ ++ if (matching_query == 1) ++ recvresp1 = 1; ++ else ++ recvresp2 = 1; + +- goto wait; ++ goto wait; ++ } + } + + /* don't retry if called from dig */ +diff -Nrup a/resolv/resolv.h b/resolv/resolv.h +--- a/resolv/resolv.h 2025-06-06 06:59:53.530659146 -0400 ++++ b/resolv/resolv.h 2025-06-06 07:09:57.754126400 -0400 +@@ -136,6 +136,7 @@ struct res_sym { + as a TLD. */ + #define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */ + #define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */ ++#define RES_STRICTERR 0x10000000 /* Report more DNS errors as errors. */ + + #define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH) + +diff -Nrup a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +--- a/resolv/tst-resolv-res_init-skeleton.c 2025-06-06 07:00:12.499548242 -0400 ++++ b/resolv/tst-resolv-res_init-skeleton.c 2025-06-06 07:11:46.131274310 -0400 +@@ -130,6 +130,7 @@ print_resp (FILE *fp, res_state resp) + print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query"); + print_option_flag (fp, &options, RES_NORELOAD, "no-reload"); + print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa"); ++ print_option_flag (fp, &options, RES_STRICTERR, "strict-error"); + fputc ('\n', fp); + if (options != 0) + fprintf (fp, "; error: unresolved option bits: 0x%x\n", options); +@@ -731,6 +732,15 @@ struct test_case test_cases[] = + "search example.com\n" + "; search[0]: example.com\n" + "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, ++ {.name = "strict-error flag", ++ .conf = "options strict-error\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options strict-error\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, + { NULL } +diff -Nrup a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +--- a/resolv/tst-resolv-semi-failure.c 2025-06-06 07:00:12.438548599 -0400 ++++ b/resolv/tst-resolv-semi-failure.c 2025-06-06 07:02:49.099632654 -0400 +@@ -67,6 +67,9 @@ response (const struct resolv_response_c + resolv_response_close_record (b); + } + ++/* Set to 1 if strict error checking is enabled. */ ++static int do_strict_error; ++ + static void + check_one (void) + { +@@ -83,7 +86,10 @@ check_one (void) + struct addrinfo *ai; + int ret = getaddrinfo ("www.example", "80", &hints, &ai); + const char *expected; +- if (ret == 0 && ai->ai_next != NULL) ++ /* In strict-error mode, a switch to the second name server ++ happens, and both responses are received, so a single ++ response is a bug. */ ++ if (do_strict_error || (ret == 0 && ai->ai_next != NULL)) + expected = ("address: STREAM/TCP 192.0.2.17 80\n" + "address: STREAM/TCP 2001:db8::1 80\n"); + else +@@ -99,33 +105,36 @@ check_one (void) + static int + do_test (void) + { +- for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) +- { +- struct resolv_test *aux = resolv_test_start +- ((struct resolv_redirect_config) +- { +- .response_callback = response, +- }); +- +- if (do_single_lookup) +- _res.options |= RES_SNGLKUP; +- +- for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) +- { +- fail_aaaa = do_fail_aaaa; ++ for (do_strict_error = 0; do_strict_error < 2; ++do_strict_error) ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ if (do_strict_error) ++ _res.options |= RES_STRICTERR; ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; ++ ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } + +- rcode = 2; /* SERVFAIL. */ +- check_one (); +- +- rcode = 4; /* NOTIMP. */ +- check_one (); +- +- rcode = 5; /* REFUSED. */ +- check_one (); +- } +- +- resolv_test_end (aux); +- } ++ resolv_test_end (aux); ++ } + + return 0; + } diff --git a/glibc-RHEL-18039-6.patch b/glibc-RHEL-18039-6.patch new file mode 100644 index 0000000..d14093c --- /dev/null +++ b/glibc-RHEL-18039-6.patch @@ -0,0 +1,28 @@ +commit ec119972cb2598c04ec7d4219e20506006836f64 +Author: Florian Weimer +Date: Thu Aug 1 10:46:10 2024 +0200 + + resolv: Fix tst-resolv-short-response for older GCC (bug 32042) + + Previous GCC versions do not support the C23 change that + allows labels on declarations. + + Reviewed-by: Adhemerval Zanella + +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +index be354ae1c7..9b06b0c176 100644 +--- a/resolv/tst-resolv-short-response.c ++++ b/resolv/tst-resolv-short-response.c +@@ -33,8 +33,10 @@ response (const struct resolv_response_context *ctx, + { + case 0: + /* First server times out. */ +- struct resolv_response_flags flags = {.rcode = rcode}; +- resolv_response_init (b, flags); ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ } + break; + case 1: + /* Second server sends reply. */ diff --git a/glibc.spec b/glibc.spec index 9ea2e39..145e09f 100644 --- a/glibc.spec +++ b/glibc.spec @@ -115,7 +115,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: %{glibcrelease}.23 +Release: %{glibcrelease}.24 # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -1279,6 +1279,12 @@ Patch1044: glibc-RHEL-92685-8.patch Patch1045: glibc-RHEL-92685-9.patch Patch1046: glibc-RHEL-93937-1.patch Patch1047: glibc-RHEL-93937-2.patch +Patch1048: glibc-RHEL-18039-1.patch +Patch1049: glibc-RHEL-18039-2.patch +Patch1050: glibc-RHEL-18039-3.patch +Patch1051: glibc-RHEL-18039-4.patch +Patch1052: glibc-RHEL-18039-5.patch +Patch1053: glibc-RHEL-18039-6.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2940,6 +2946,12 @@ fi %{_libdir}/libpthread_nonshared.a %changelog +* Thu Jun 05 2025 Patsy Griffin - 2.28-251.24 +- Keep reloading /etc/resolv.conf after timeouts with getaddrinfo + and AF_UNSPEC. +- Avoid timeouts with getaddrinfo, AF_UNSPEC, and certain DNS error + responses. (RHEL-18039) + * Thu Jun 05 2025 Arjun Shankar - 2.28-251.23 - Reduce spurious rebuilds while running tests (RHEL-93937)