import glibc-2.34-60.el9_2.7

i9c changed/i9c/glibc-2.34-60.el9_2.7
MSVSphere Packaging Team 1 year ago
parent cd7647f325
commit ae18cd95af

2
.gitignore vendored

@ -1 +1,3 @@
SOURCES/glibc-2.34.tar.xz
SOURCES/glibc-c-utf8-locale-2.patch
SOURCES/glibc-upstream-2.34-373.patch

@ -1 +1,3 @@
7c3b8890a6346793b6334cc5f2fea5d437d307b8 SOURCES/glibc-2.34.tar.xz
47cf1a27ae2e86b37e44c49f6bf4630a1adabd9a SOURCES/glibc-c-utf8-locale-2.patch
6022f103e5596ad229f22bc966327d71208f7016 SOURCES/glibc-upstream-2.34-373.patch

@ -0,0 +1,65 @@
commit 51948fdf0fc0258feca719f6a88cbdcf82f2eafc
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Mar 17 11:16:57 2022 +0530
nss: Sort tests and tests-container and put one test per line
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit e2f68b54e8052da14680074fc5df03153216f218)
Conflicts:
nss/Makefile
(reordered tests)
diff --git a/nss/Makefile b/nss/Makefile
index beb30ac2667fe998..5192db6097457f88 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -56,22 +56,31 @@ extra-objs += $(makedb-modules:=.o)
tests-static = tst-field
tests-internal = tst-field
-tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \
- tst-nss-test1 \
- tst-nss-test2 \
- tst-nss-test4 \
- tst-nss-test5 \
- tst-nss-test_errno
-xtests = bug-erange
-
-tests-container = \
- tst-nss-compat1 \
- tst-nss-test3 \
- tst-nss-files-hosts-long \
- tst-nss-db-endpwent \
- tst-nss-db-endgrent \
- tst-nss-gai-actions \
- tst-reload1 tst-reload2
+
+tests := \
+ bug17079 \
+ test-digits-dots \
+ test-netdb \
+ tst-nss-getpwent \
+ tst-nss-test1 \
+ tst-nss-test2 \
+ tst-nss-test4 \
+ tst-nss-test5 \
+ tst-nss-test_errno \
+# tests
+
+xtests = bug-erange
+
+tests-container := \
+ tst-nss-compat1 \
+ tst-nss-db-endgrent \
+ tst-nss-db-endpwent \
+ tst-nss-files-hosts-long \
+ tst-nss-gai-actions \
+ tst-nss-test3 \
+ tst-reload1 \
+ tst-reload2 \
+# tests-container
# Tests which need libdl
ifeq (yes,$(build-shared))

@ -0,0 +1,156 @@
commit 4d59769087f2143f619b4b38bf93590a86f5c806
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 19:48:48 2022 +0530
gaih_inet: make gethosts into a function
The macro is quite a pain to debug, so make gethosts into a function to
make it easier to maintain.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit cfa3bd48cb19a70e4367a9978dbba09d9df27a72)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 145ea6fa381ad14b..6be109d07f7fcce0 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
return true;
}
-#define gethosts(_family) \
- { \
- struct hostent th; \
- char *localcanon = NULL; \
- no_data = 0; \
- while (1) \
- { \
- status = DL_CALL_FCT (fct, (name, _family, &th, \
- tmpbuf->data, tmpbuf->length, \
- &errno, &h_errno, NULL, &localcanon)); \
- if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
- || errno != ERANGE) \
- break; \
- if (!scratch_buffer_grow (tmpbuf)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_MEMORY; \
- goto out; \
- } \
- } \
- if (status == NSS_STATUS_NOTFOUND \
- || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
- { \
- if (h_errno == NETDB_INTERNAL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- if (h_errno == TRY_AGAIN) \
- no_data = EAI_AGAIN; \
- else \
- no_data = h_errno == NO_DATA; \
- } \
- else if (status == NSS_STATUS_SUCCESS) \
- { \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- \
- if (localcanon != NULL && res->canon == NULL) \
- { \
- char *canonbuf = __strdup (localcanon); \
- if (canonbuf == NULL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- res->canon = canonbuf; \
- } \
- } \
- }
+static int
+gethosts (nss_gethostbyname3_r fct, int family, const char *name,
+ const struct addrinfo *req, struct scratch_buffer *tmpbuf,
+ struct gaih_result *res, enum nss_status *statusp, int *no_datap)
+{
+ struct hostent th;
+ char *localcanon = NULL;
+ enum nss_status status;
+
+ *no_datap = 0;
+ while (1)
+ {
+ *statusp = status = DL_CALL_FCT (fct, (name, family, &th,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno, NULL,
+ &localcanon));
+ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL
+ || errno != ERANGE)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+ if (status == NSS_STATUS_NOTFOUND
+ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
+ {
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ *no_datap = EAI_AGAIN;
+ else
+ *no_datap = h_errno == NO_DATA;
+ }
+ else if (status == NSS_STATUS_SUCCESS)
+ {
+ if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
+ return -EAI_SYSTEM;
+
+ if (localcanon != NULL && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (localcanon);
+ if (canonbuf == NULL)
+ return -EAI_SYSTEM;
+ res->canon = canonbuf;
+ }
+ }
+ return 0;
+}
/* This function is called if a canonical name is requested, but if
the service function did not provide it. It tries to obtain the
@@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
- gethosts (AF_INET6);
+ if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
no_inet6_data = no_data;
inet6_status = status;
}
@@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
{
- gethosts (AF_INET);
+ if ((result = gethosts (fct, AF_INET, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
if (req->ai_family == AF_INET)
{

@ -0,0 +1,178 @@
commit 6e3fed9d20d6b7ef4b69dd7cfcdd7bbaf1c9a9cb
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 20:24:37 2022 +0530
gaih_inet: split loopback lookup into its own function
Flatten the condition nesting and replace the alloca for RET.AT/ATR with
a single array LOCAL_AT[2]. This gets rid of alloca and alloca
accounting.
`git diff -b` is probably the best way to view this change since much of
the diff is whitespace changes.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 657472b2a50f67b12e5bbe5827582c9c2bb82dc3)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 6be109d07f7fcce0..827c43b369836de9 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1004,6 +1004,32 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
return -EAI_NODATA;
}
+/* Add local address information into RES. RES->AT is assumed to have enough
+ space for two tuples and is zeroed out. */
+
+static void
+get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
+{
+ struct gaih_addrtuple *atr = res->at;
+ if (req->ai_family == AF_UNSPEC)
+ res->at->next = res->at + 1;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ res->at->family = AF_INET6;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res->at->next;
+ }
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ {
+ atr->family = AF_INET;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ atr->addr[0] = htonl (INADDR_LOOPBACK);
+ }
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1014,10 +1040,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
const char *orig_name = name;
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
-
int rc;
if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
return rc;
@@ -1027,76 +1049,51 @@ gaih_inet (const char *name, const struct gaih_service *service,
int result = 0;
struct gaih_result res = {0};
- if (name != NULL)
+ struct gaih_addrtuple local_at[2] = {0};
+
+ res.at = local_at;
+
+ if (__glibc_unlikely (name == NULL))
{
- if (req->ai_flags & AI_IDN)
- {
- char *out;
- result = __idna_to_dns_encoding (name, &out);
- if (result != 0)
- return -result;
- name = out;
- malloc_name = true;
- }
+ get_local_addresses (req, &res);
+ goto process_list;
+ }
- res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- res.at->scopeid = 0;
- res.at->next = NULL;
+ if (req->ai_flags & AI_IDN)
+ {
+ char *out;
+ result = __idna_to_dns_encoding (name, &out);
+ if (result != 0)
+ return -result;
+ name = out;
+ malloc_name = true;
+ }
- if ((result = text_to_binary_address (name, req, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
#ifdef USE_NSCD
- if ((result = get_nscd_addresses (name, req, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
#endif
- if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
-
- /* None of the lookups worked, so name not found. */
- result = -EAI_NONAME;
- goto free_and_return;
- }
- else
- {
- struct gaih_addrtuple *atr;
- atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- memset (res.at, '\0', sizeof (struct gaih_addrtuple));
-
- if (req->ai_family == AF_UNSPEC)
- {
- res.at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
- }
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- res.at->family = AF_INET6;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = res.at->next;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- atr->family = AF_INET;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- atr->addr[0] = htonl (INADDR_LOOPBACK);
- }
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
process_list:
{

@ -0,0 +1,208 @@
commit 92478a808f477480adbc5ca3d9a4a1bc27fc13ae
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 20:38:31 2022 +0530
gaih_inet: Split result generation into its own function
Simplify the loop a wee bit and clean up variable names too.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit ac4653ef503d1e87893d1a6714748a1cdf4bf7ad)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 827c43b369836de9..1008f247365ea009 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1030,6 +1030,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
}
}
+/* Generate results in PAI and its count in NADDRS. Return 0 on success or an
+ error code on failure. */
+
+static int
+generate_addrinfo (const struct addrinfo *req, struct gaih_result *res,
+ const struct gaih_servtuple *st, struct addrinfo **pai,
+ unsigned int *naddrs)
+{
+ size_t socklen;
+ sa_family_t family;
+
+ /* Buffer is the size of an unformatted IPv6 address in printable format. */
+ for (struct gaih_addrtuple *at = res->at; at != NULL; at = at->next)
+ {
+ family = at->family;
+ if (family == AF_INET6)
+ {
+ socklen = sizeof (struct sockaddr_in6);
+
+ /* If we looked up IPv4 mapped address discard them here if
+ the caller isn't interested in all address and we have
+ found at least one IPv6 address. */
+ if (res->got_ipv6
+ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ continue;
+ }
+ else
+ socklen = sizeof (struct sockaddr_in);
+
+ for (int i = 0; st[i].set; i++)
+ {
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+ return -EAI_MEMORY;
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
+ ai->ai_addrlen = socklen;
+ ai->ai_addr = (void *) (ai + 1);
+
+ /* We only add the canonical name once. */
+ ai->ai_canonname = res->canon;
+ res->canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+ ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
+ /* In case of an allocation error the list must be NULL
+ terminated. */
+ ai->ai_next = NULL;
+
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) ai->ai_addr;
+ sin6p->sin6_port = st[i].port;
+ sin6p->sin6_flowinfo = 0;
+ memcpy (&sin6p->sin6_addr, at->addr, sizeof (struct in6_addr));
+ sin6p->sin6_scope_id = at->scopeid;
+ }
+ else
+ {
+ struct sockaddr_in *sinp = (struct sockaddr_in *) ai->ai_addr;
+ sinp->sin_port = st[i].port;
+ memcpy (&sinp->sin_addr, at->addr, sizeof (struct in_addr));
+ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+ }
+
+ pai = &(ai->ai_next);
+ }
+
+ ++*naddrs;
+ }
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1096,98 +1177,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto free_and_return;
process_list:
- {
- /* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &res)) != 0)
- goto free_and_return;
-
- struct gaih_addrtuple *at2 = res.at;
- size_t socklen;
- sa_family_t family;
-
- /*
- buffer is the size of an unformatted IPv6 address in printable format.
- */
- while (at2 != NULL)
- {
- family = at2->family;
- if (family == AF_INET6)
- {
- socklen = sizeof (struct sockaddr_in6);
-
- /* If we looked up IPv4 mapped address discard them here if
- the caller isn't interested in all address and we have
- found at least one IPv6 address. */
- if (res.got_ipv6
- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
- && IN6_IS_ADDR_V4MAPPED (at2->addr))
- goto ignore;
- }
- else
- socklen = sizeof (struct sockaddr_in);
-
- for (int i = 0; st[i].set; i++)
- {
- struct addrinfo *ai;
- ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
- if (ai == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- ai->ai_flags = req->ai_flags;
- ai->ai_family = family;
- ai->ai_socktype = st[i].socktype;
- ai->ai_protocol = st[i].protocol;
- ai->ai_addrlen = socklen;
- ai->ai_addr = (void *) (ai + 1);
-
- /* We only add the canonical name once. */
- ai->ai_canonname = res.canon;
- res.canon = NULL;
-
-#ifdef _HAVE_SA_LEN
- ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
- ai->ai_addr->sa_family = family;
-
- /* In case of an allocation error the list must be NULL
- terminated. */
- ai->ai_next = NULL;
-
- if (family == AF_INET6)
- {
- struct sockaddr_in6 *sin6p =
- (struct sockaddr_in6 *) ai->ai_addr;
-
- sin6p->sin6_port = st[i].port;
- sin6p->sin6_flowinfo = 0;
- memcpy (&sin6p->sin6_addr,
- at2->addr, sizeof (struct in6_addr));
- sin6p->sin6_scope_id = at2->scopeid;
- }
- else
- {
- struct sockaddr_in *sinp =
- (struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st[i].port;
- memcpy (&sinp->sin_addr,
- at2->addr, sizeof (struct in_addr));
- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
- }
-
- pai = &(ai->ai_next);
- }
-
- ++*naddrs;
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
+ goto free_and_return;
- ignore:
- at2 = at2->next;
- }
- }
+ result = generate_addrinfo (req, &res, st, pai, naddrs);
- free_and_return:
+free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);

@ -0,0 +1,34 @@
commit cc4544ef8069a14c67a46b7e8e28eff1dc102050
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Wed Mar 2 11:45:29 2022 +0530
gethosts: Return EAI_MEMORY on allocation failure
All other cases of failures due to lack of memory return EAI_MEMORY, so
it seems wrong to return EAI_SYSTEM here. The only reason
convert_hostent_to_gaih_addrtuple could fail is on calloc failure.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit b587456c0e7b59dcfdbd2d44db000a3bc8244e57)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 1008f247365ea009..37260d6e6f292186 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
else if (status == NSS_STATUS_SUCCESS)
{
if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
if (localcanon != NULL && res->canon == NULL)
{
char *canonbuf = __strdup (localcanon);
if (canonbuf == NULL)
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
res->canon = canonbuf;
}
}

@ -0,0 +1,316 @@
commit e09ee267c03e3150c2c9ba28625ab130705a485e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Fri Sep 15 13:51:12 2023 -0400
getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806)
When an NSS plugin only implements the _gethostbyname2_r and
_getcanonname_r callbacks, getaddrinfo could use memory that was freed
during tmpbuf resizing, through h_name in a previous query response.
The backing store for res->at->name when doing a query with
gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
gethosts during the query. For AF_INET6 lookup with AI_ALL |
AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
for a v4 lookup. In this case, if the first call reallocates tmpbuf
enough number of times, resulting in a malloc, th->h_name (that
res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
Now if the second call to gethosts also causes the plugin callback to
return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
reference in res->at->name. This then gets dereferenced in the
getcanonname_r plugin call, resulting in the use after free.
Fix this by copying h_name over and freeing it at the end. This
resolves BZ #30843, which is assigned CVE-2023-4806.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 973fe93a5675c42798b2161c6f29c01b0e243994)
diff --git a/nss/Makefile b/nss/Makefile
index 5192db6097457f88..18a27d79d26f094a 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -80,6 +80,7 @@ tests-container := \
tst-nss-test3 \
tst-reload1 \
tst-reload2 \
+ tst-nss-gai-hv2-canonname \
# tests-container
# Tests which need libdl
@@ -143,7 +144,8 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
ifeq ($(build-static-nss),yes)
tests-static += tst-nss-static
endif
-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os
+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \
+ nss_test_gai_hv2_canonname.os
include ../Rules
@@ -178,12 +180,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
libof-nss_test1 = extramodules
libof-nss_test2 = extramodules
libof-nss_test_errno = extramodules
+libof-nss_test_gai_hv2_canonname = extramodules
$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
$(build-module)
+$(objpfx)/libnss_test_gai_hv2_canonname.so: \
+ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps)
+ $(build-module)
$(objpfx)nss_test2.os : nss_test1.c
# Use the nss_files suffix for these objects as well.
$(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so
@@ -193,10 +199,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so
$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
$(objpfx)/libnss_test_errno.so
$(make-link)
+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so
+ $(make-link)
$(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \
$(objpfx)/libnss_test1.so$(libnss_files.so-version) \
$(objpfx)/libnss_test2.so$(libnss_files.so-version) \
- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
ifeq (yes,$(have-thread-library))
$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
new file mode 100644
index 0000000000000000..4439c83c9f40cf43
--- /dev/null
+++ b/nss/nss_test_gai_hv2_canonname.c
@@ -0,0 +1,56 @@
+/* NSS service provider that only provides gethostbyname2_r.
+ Copyright The GNU Toolchain Authors.
+ 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 <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+/* Catch misnamed and functions. */
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname)
+
+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
+ struct hostent *, char *,
+ size_t, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *herrnop)
+{
+ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
+ herrnop);
+}
+
+enum nss_status
+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
+ size_t buflen, char **result,
+ int *errnop, int *h_errnop)
+{
+ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
+ the test. */
+ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
+ || buflen < sizeof (QUERYNAME))
+ abort ();
+
+ strncpy (buffer, name, buflen);
+ *result = buffer;
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
new file mode 100644
index 0000000000000000..d5f10c07d6a90773
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.c
@@ -0,0 +1,63 @@
+/* Test NSS query path for plugins that only implement gethostbyname2
+ (#30843).
+ Copyright The GNU Toolchain Authors.
+ 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 <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+#define PREPARE do_prepare
+
+static void do_prepare (int a, char **av)
+{
+ FILE *hosts = xfopen ("/etc/hosts", "w");
+ for (unsigned i = 2; i < 255; i++)
+ {
+ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i);
+ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i);
+ }
+ xfclose (hosts);
+}
+
+static int
+do_test (void)
+{
+ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
+
+ struct addrinfo hints = {};
+ struct addrinfo *result = NULL;
+
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME;
+
+ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result);
+
+ if (ret != 0)
+ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret));
+
+ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME);
+
+ freeaddrinfo(result);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644
index 0000000000000000..14f2a9cb0867dff9
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.h
@@ -0,0 +1 @@
+#define QUERYNAME "test.example.com"
diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
new file mode 100644
index 0000000000000000..e69de29bb2d1d643
diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
new file mode 100644
index 0000000000000000..31848b4a28524af6
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
@@ -0,0 +1,2 @@
+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
+su
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 37260d6e6f292186..10dc63542f337693 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ char *h_name;
bool free_at;
bool got_ipv6;
};
@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res)
if (res->free_at)
free (res->at);
free (res->canon);
+ free (res->h_name);
memset (res, 0, sizeof (*res));
}
@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
- is not copied, and the struct hostent object must not be deallocated
- prematurely. The new addresses are appended to the tuple array in RES. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new
+ addresses are appended to the tuple array in RES. */
static bool
convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
struct hostent *h, struct gaih_result *res)
@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
res->at = array;
res->free_at = true;
+ /* Duplicate h_name because it may get reclaimed when the underlying storage
+ is freed. */
+ if (res->h_name == NULL)
+ {
+ res->h_name = __strdup (h->h_name);
+ if (res->h_name == NULL)
+ return false;
+ }
+
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
array[i].next = array + i + 1;
@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
}
array[i].next = array + i + 1;
}
- array[0].name = h->h_name;
array[count - 1].next = NULL;
return true;
@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
memory allocation failure. The returned string is allocated on the
heap; the caller has to free it. */
static char *
-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
+getcanonname (nss_action_list nip, const char *hname, const char *name)
{
nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r");
char *s = (char *) name;
if (cfct != NULL)
{
char buf[256];
- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
+ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno,
+ &h_errno)) != NSS_STATUS_SUCCESS)
/* If the canonical name cannot be determined, use the passed
string. */
s = (char *) name;
@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if ((req->ai_flags & AI_CANONNAME) != 0
&& res->canon == NULL)
{
- char *canonbuf = getcanonname (nip, res->at, name);
+ char *canonbuf = getcanonname (nip, res->h_name, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);

@ -0,0 +1,37 @@
commit 57e349b1b0df1aee2dcd19dae1f324bde25ff8f0
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Wed Dec 8 07:02:27 2021 -0800
Disable DT_RUNPATH on NSS tests [BZ #28455]
The glibc internal NSS functions should always load NSS modules from
the system. For testing purpose, disable DT_RUNPATH on NSS tests so
that the glibc internal NSS functions can load testing NSS modules
via DT_RPATH.
This partially fixes BZ #28455.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
nss/Makefile
(different test backport order)
diff --git a/nss/Makefile b/nss/Makefile
index 18a27d79d26f094a..648adf4bb7b1ee6a 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -214,3 +214,13 @@ endif
$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
$(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so
+
+# Disable DT_RUNPATH on NSS tests so that the glibc internal NSS
+# functions can load testing NSS modules via DT_RPATH.
+LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test2 = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags

@ -0,0 +1,84 @@
commit ec6b95c3303c700eb89eebeda2d7264cc184a796
Author: Romain Geissler <romain.geissler@amadeus.com>
Date: Mon Sep 25 01:21:51 2023 +0100
Fix leak in getaddrinfo introduced by the fix for CVE-2023-4806 [BZ #30843]
This patch fixes a very recently added leak in getaddrinfo.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
diff --git a/nss/Makefile b/nss/Makefile
index 648adf4bb7b1ee6a..bfdb0fd5a9a90873 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -147,6 +147,15 @@ endif
extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \
nss_test_gai_hv2_canonname.os
+ifeq ($(run-built-tests),yes)
+ifneq (no,$(PERL))
+tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out
+endif
+endif
+
+generated += mtrace-tst-nss-gai-hv2-canonname.out \
+ tst-nss-gai-hv2-canonname.mtrace
+
include ../Rules
ifeq (yes,$(have-selinux))
@@ -215,6 +224,17 @@ endif
$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
$(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so
+tst-nss-gai-hv2-canonname-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \
+ $(objpfx)tst-nss-gai-hv2-canonname.out
+ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \
+ && $(common-objpfx)malloc/mtrace \
+ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \
+ $(evaluate-test)
+
# Disable DT_RUNPATH on NSS tests so that the glibc internal NSS
# functions can load testing NSS modules via DT_RPATH.
LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
index d5f10c07d6a90773..7db53cf09da8dcb6 100644
--- a/nss/tst-nss-gai-hv2-canonname.c
+++ b/nss/tst-nss-gai-hv2-canonname.c
@@ -21,6 +21,7 @@
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
+#include <mcheck.h>
#include <support/check.h>
#include <support/xstdio.h>
#include "nss/tst-nss-gai-hv2-canonname.h"
@@ -41,6 +42,8 @@ static void do_prepare (int a, char **av)
static int
do_test (void)
{
+ mtrace ();
+
__nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
struct addrinfo hints = {};
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 10dc63542f337693..d6046a707f1d742a 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1196,9 +1196,7 @@ free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
- if (res.free_at)
- free (res.at);
- free (res.canon);
+ gaih_result_reset (&res);
return result;
}

@ -0,0 +1,41 @@
commit 01671608a3bddde369cdd42aed12e1c019b87158
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Wed Aug 4 02:21:01 2021 +0530
gethosts: Remove unused argument _type
The generated code is unchanged.
(cherry picked from commit b17e842a60819098d2a203ecc8b8371b7e1d6c65)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index f391dc0a59849aab..702d8a50e0c218d2 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -239,7 +239,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
return true;
}
-#define gethosts(_family, _type) \
+#define gethosts(_family) \
{ \
struct hostent th; \
char *localcanon = NULL; \
@@ -864,7 +864,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
- gethosts (AF_INET6, struct in6_addr);
+ gethosts (AF_INET6);
no_inet6_data = no_data;
inet6_status = status;
}
@@ -876,7 +876,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !got_ipv6)))
{
- gethosts (AF_INET, struct in_addr);
+ gethosts (AF_INET);
if (req->ai_family == AF_INET)
{

@ -0,0 +1,248 @@
commit b195fd86c616b147dad3a63498b79e0dedb4662b
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 22:17:36 2022 +0530
gaih_inet: Simplify canon name resolution
Simplify logic for allocation of canon to remove the canonbuf variable;
canon now always points to an allocated block. Also pull the canon name
set into a separate function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit d01411f6bc61429fc027c38827bf3103b48eef2e)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 702d8a50e0c218d2..5c0d873e1d766099 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -285,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
\
if (localcanon != NULL && canon == NULL) \
{ \
- canonbuf = __strdup (localcanon); \
+ char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
@@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
return __strdup (name);
}
+/* Process looked up canonical name and if necessary, decode to IDNA. Result
+ is a new string written to CANONP and the earlier string is freed. */
+
+static int
+process_canonname (const struct addrinfo *req, const char *orig_name,
+ char **canonp)
+{
+ char *canon = *canonp;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0)
+ {
+ bool do_idn = req->ai_flags & AI_CANONIDN;
+ if (do_idn)
+ {
+ char *out;
+ int rc = __idna_from_dns_encoding (canon ?: orig_name, &out);
+ if (rc == 0)
+ {
+ free (canon);
+ canon = out;
+ }
+ else if (rc == EAI_IDN_ENCODE)
+ /* Use the punycode name as a fallback. */
+ do_idn = false;
+ else
+ return -rc;
+ }
+ if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL)
+ return -EAI_MEMORY;
+ }
+
+ *canonp = canon;
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- const char *canon = NULL;
+ char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -453,7 +488,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
- char *canonbuf = NULL;
int result = 0;
if (name != NULL)
@@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pat)->next = NULL;
if (added_canon || air->canon == NULL)
(*pat)->name = NULL;
- else if (canonbuf == NULL)
+ else if (canon == NULL)
{
- canonbuf = __strdup (air->canon);
+ char *canonbuf = __strdup (air->canon);
if (canonbuf == NULL)
{
result = -EAI_MEMORY;
@@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* Always start afresh; continue should discard previous results
and the hosts database does not support merge. */
at = NULL;
- free (canonbuf);
+ free (canon);
free (addrmem);
- canon = canonbuf = NULL;
+ canon = NULL;
addrmem = NULL;
got_ipv6 = false;
@@ -805,7 +855,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = at->name;
+ {
+ char *canonbuf = __strdup (at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
struct gaih_addrtuple **pat = &at;
@@ -893,7 +952,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
- canonbuf = getcanonname (nip, at, name);
+ char *canonbuf = getcanonname (nip, at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
@@ -1004,6 +1063,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
{
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ goto free_and_return;
+
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
@@ -1014,48 +1077,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/
while (at2 != NULL)
{
- /* Only the first entry gets the canonical name. */
- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
- {
- if (canon == NULL)
- /* If the canonical name cannot be determined, use
- the passed in string. */
- canon = orig_name;
-
- bool do_idn = req->ai_flags & AI_CANONIDN;
- if (do_idn)
- {
- char *out;
- int rc = __idna_from_dns_encoding (canon, &out);
- if (rc == 0)
- canon = out;
- else if (rc == EAI_IDN_ENCODE)
- /* Use the punycode name as a fallback. */
- do_idn = false;
- else
- {
- result = -rc;
- goto free_and_return;
- }
- }
- if (!do_idn)
- {
- if (canonbuf != NULL)
- /* We already allocated the string using malloc, but
- the buffer is now owned by canon. */
- canonbuf = NULL;
- else
- {
- canon = __strdup (canon);
- if (canon == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
- }
- }
-
family = at2->family;
if (family == AF_INET6)
{
@@ -1078,7 +1099,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
if (ai == NULL)
{
- free ((char *) canon);
result = -EAI_MEMORY;
goto free_and_return;
}
@@ -1138,7 +1158,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canonbuf);
+ free (canon);
return result;
}

@ -0,0 +1,86 @@
commit f7efb43738f255db32cfa4e84a491c09f6da66e2
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Mar 3 23:07:42 2022 +0530
getaddrinfo: Fix leak with AI_ALL [BZ #28852]
Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
the result list so that a single block is maintained for
hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
never merged with any other results, since the hosts database does not
permit merging.
Resolves BZ #28852.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 300460460706ce3ffe29a7df8966e68323ec5bf1)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 5c0d873e1d766099..ed70e6cb3944d219 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -189,19 +189,16 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects.
- h_name is not copied, and the struct hostent object must not be
- deallocated prematurely. *RESULT must be NULL or a pointer to a
- linked-list. The new addresses are appended at the end. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
+ is not copied, and the struct hostent object must not be deallocated
+ prematurely. The new addresses are appended to the tuple array in
+ RESULT. */
static bool
convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
int family,
struct hostent *h,
struct gaih_addrtuple **result)
{
- while (*result)
- result = &(*result)->next;
-
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
for (char **p = h->h_addr_list; *p != NULL; ++p)
@@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = calloc (count, sizeof (*array));
+ struct gaih_addrtuple *array = *result;
+ size_t old = 0;
+
+ while (array != NULL)
+ {
+ old++;
+ array = array->next;
+ }
+
+ array = realloc (*result, (old + count) * sizeof (*array));
+
if (array == NULL)
return false;
+ *result = array;
+
+ /* Update the next pointers on reallocation. */
+ for (size_t i = 0; i < old; i++)
+ array[i].next = array + i + 1;
+
+ array += old;
+
+ memset (array, 0, count * sizeof (*array));
+
for (size_t i = 0; i < count; ++i)
{
if (family == AF_INET && req->ai_family == AF_INET6)
@@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array[0].name = h->h_name;
array[count - 1].next = NULL;
- *result = array;
return true;
}

@ -0,0 +1,285 @@
commit e05e5889b8a307fe4be55b03bcbd7a1c62fc2f2d
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Feb 10 13:27:11 2022 +0530
gaih_inet: Simplify service resolution
Refactor the code to split out the service resolution code into a
separate function. Allocate the service tuples array just once to the
size of the typeproto array, thus avoiding the unnecessary pointer
chasing and stack allocations.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 8d6cf99f2fb81a097f9334c125e5c23604af1a98)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index ed70e6cb3944d219..8c78ef9570fe0f58 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -100,14 +100,12 @@ struct gaih_service
struct gaih_servtuple
{
- struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
+ bool set;
};
-static const struct gaih_servtuple nullserv;
-
struct gaih_typeproto
{
@@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
while (r);
- st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = s->s_port;
+ st->set = true;
return 0;
}
@@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
}
static int
-gaih_inet (const char *name, const struct gaih_service *service,
- const struct addrinfo *req, struct addrinfo **pai,
- unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
+ struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
{
+ int i;
const struct gaih_typeproto *tp = gaih_inet_typeproto;
- struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
- struct gaih_addrtuple *at = NULL;
- bool got_ipv6 = false;
- char *canon = NULL;
- const char *orig_name = name;
-
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
if (req->ai_protocol || req->ai_socktype)
{
@@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
- int port = 0;
- if (service != NULL)
+ if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ return -EAI_SERVICE;
+
+ if (service == NULL || service->num >= 0)
{
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- return -EAI_SERVICE;
+ int port = service != NULL ? htons (service->num) : 0;
- if (service->num < 0)
+ if (req->ai_socktype || req->ai_protocol)
{
- if (tp->name[0])
- {
- st = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple), alloca_used);
-
- int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- if (__glibc_unlikely (rc != 0))
- return rc;
- }
- else
- {
- struct gaih_servtuple **pst = &st;
- for (tp++; tp->name[0]; tp++)
- {
- struct gaih_servtuple *newp;
+ st[0].socktype = tp->socktype;
+ st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+ ? req->ai_protocol : tp->protocol);
+ st[0].port = port;
+ st[0].set = true;
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- continue;
+ return 0;
+ }
- if (req->ai_socktype != 0
- && req->ai_socktype != tp->socktype)
- continue;
- if (req->ai_protocol != 0
- && !(tp->protoflag & GAI_PROTO_PROTOANY)
- && req->ai_protocol != tp->protocol)
- continue;
+ /* Neither socket type nor protocol is set. Return all socket types
+ we know about. */
+ for (i = 0, ++tp; tp->name[0]; ++tp)
+ if (tp->defaultflag)
+ {
+ st[i].socktype = tp->socktype;
+ st[i].protocol = tp->protocol;
+ st[i].port = port;
+ st[i++].set = true;
+ }
- newp = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
+ return 0;
+ }
- if (gaih_inet_serv (service->name,
- tp, req, newp, tmpbuf) != 0)
- continue;
+ if (tp->name[0])
+ return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- *pst = newp;
- pst = &(newp->next);
- }
- if (st == (struct gaih_servtuple *) &nullserv)
- return -EAI_SERVICE;
- }
- }
- else
- {
- port = htons (service->num);
- goto got_port;
- }
- }
- else
+ for (i = 0, tp++; tp->name[0]; tp++)
{
- got_port:
+ if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ continue;
- if (req->ai_socktype || req->ai_protocol)
- {
- st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
- st->next = NULL;
- st->socktype = tp->socktype;
- st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
- ? req->ai_protocol : tp->protocol);
- st->port = port;
- }
- else
- {
- /* Neither socket type nor protocol is set. Return all socket types
- we know about. */
- struct gaih_servtuple **lastp = &st;
- for (++tp; tp->name[0]; ++tp)
- if (tp->defaultflag)
- {
- struct gaih_servtuple *newp;
+ if (req->ai_socktype != 0
+ && req->ai_socktype != tp->socktype)
+ continue;
+ if (req->ai_protocol != 0
+ && !(tp->protoflag & GAI_PROTO_PROTOANY)
+ && req->ai_protocol != tp->protocol)
+ continue;
- newp = alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
- newp->next = NULL;
- newp->socktype = tp->socktype;
- newp->protocol = tp->protocol;
- newp->port = port;
+ if (gaih_inet_serv (service->name,
+ tp, req, &st[i], tmpbuf) != 0)
+ continue;
- *lastp = newp;
- lastp = &newp->next;
- }
- }
+ i++;
}
+ if (!st[0].set)
+ return -EAI_SERVICE;
+
+ return 0;
+}
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+ const struct addrinfo *req, struct addrinfo **pai,
+ unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+{
+ struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
+ / sizeof (struct gaih_typeproto)] = {0};
+
+ struct gaih_addrtuple *at = NULL;
+ bool got_ipv6 = false;
+ char *canon = NULL;
+ const char *orig_name = name;
+
+ /* Reserve stack memory for the scratch buffer in the getaddrinfo
+ function. */
+ size_t alloca_used = sizeof (struct scratch_buffer);
+
+ int rc;
+ if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
+ return rc;
+
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
@@ -1083,7 +1062,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((result = process_canonname (req, orig_name, &canon)) != 0)
goto free_and_return;
- struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
sa_family_t family;
@@ -1109,7 +1087,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
socklen = sizeof (struct sockaddr_in);
- for (st2 = st; st2 != NULL; st2 = st2->next)
+ for (int i = 0; st[i].set; i++)
{
struct addrinfo *ai;
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
@@ -1121,8 +1099,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_flags = req->ai_flags;
ai->ai_family = family;
- ai->ai_socktype = st2->socktype;
- ai->ai_protocol = st2->protocol;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
ai->ai_addrlen = socklen;
ai->ai_addr = (void *) (ai + 1);
@@ -1144,7 +1122,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) ai->ai_addr;
- sin6p->sin6_port = st2->port;
+ sin6p->sin6_port = st[i].port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
@@ -1154,7 +1132,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st2->port;
+ sinp->sin_port = st[i].port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));

File diff suppressed because it is too large Load Diff

@ -0,0 +1,179 @@
commit 3b5a3e5009088a029525277f36228eeb95032358
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Fri Mar 4 14:57:12 2022 +0530
gaih_inet: Split simple gethostbyname into its own function
Add a free_at flag in gaih_result to indicate if res.at needs to be
freed by the caller.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit b44389cb7fa28a59804571dac09cc32ebfac03d1)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 57b6834c8bb3887c..3870b2dc2edc89cd 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ bool free_at;
};
/* Values for `protoflag'. */
@@ -565,6 +566,62 @@ out:
return result;
}
+/* If possible, call the simple, old functions, which do not support IPv6 scope
+ ids, nor retrieving the canonical name. */
+
+static int
+try_simple_gethostbyname (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf,
+ struct gaih_result *res)
+{
+ res->at = NULL;
+
+ if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
+ return 0;
+
+ int rc;
+ struct hostent th;
+ struct hostent *h;
+
+ while (1)
+ {
+ rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data,
+ tmpbuf->length, &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+
+ if (rc == 0)
+ {
+ if (h != NULL)
+ {
+ /* We found data, convert it. RES->AT from the conversion will
+ either be an allocated block or NULL, both of which are safe to
+ pass to free (). */
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ return -EAI_MEMORY;
+
+ res->free_at = true;
+ return 0;
+ }
+ if (h_errno == NO_DATA)
+ return -EAI_NODATA;
+
+ return -EAI_NONAME;
+ }
+
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ return -EAI_NODATA;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -610,6 +667,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (res.at != NULL)
goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -619,69 +681,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct resolv_context *res_ctx = NULL;
bool do_merge = false;
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
-
- while (1)
- {
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
-
- if (rc == 0)
- {
- if (h != NULL)
- {
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.at = addrmem;
- }
- else
- {
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
- }
- }
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_AGAIN)
- result = -EAI_AGAIN;
- else
- /* We made requests but they turned out no data.
- The name is known, though. */
- result = -EAI_NODATA;
-
- goto free_and_return;
- }
-
- goto process_list;
- }
-
#ifdef USE_NSCD
if (__nss_not_use_nscd_hosts > 0
&& ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
@@ -1165,6 +1164,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
+ if (res.free_at)
+ free (res.at);
free (res.canon);
return result;

@ -0,0 +1,328 @@
commit 5914a1d55b468ccf0fb6d997a7a4e378339df735
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 15:53:45 2022 +0530
gaih_inet: Split nscd lookup code into its own function.
Add a new member got_ipv6 to indicate if the results have an IPv6
result and use it instead of the local got_ipv6.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit e7e5315b7fa065a9c8bf525ca9a32f46fa4837e5)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 3870b2dc2edc89cd..7c497a88f8b5b9f8 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -121,6 +121,7 @@ struct gaih_result
struct gaih_addrtuple *at;
char *canon;
bool free_at;
+ bool got_ipv6;
};
/* Values for `protoflag'. */
@@ -316,7 +317,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
res.canon = canonbuf; \
} \
if (_family == AF_INET6 && *pat != NULL) \
- got_ipv6 = true; \
+ res.got_ipv6 = true; \
} \
}
@@ -467,6 +468,128 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
return 0;
}
+#ifdef USE_NSCD
+/* Query addresses from nscd cache, returning a non-zero value on error.
+ RES members have the lookup result; RES->AT is NULL if there were no errors
+ but also no results. */
+
+static int
+get_nscd_addresses (const char *name, const struct addrinfo *req,
+ struct gaih_result *res)
+{
+ if (__nss_not_use_nscd_hosts > 0
+ && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
+ __nss_not_use_nscd_hosts = 0;
+
+ res->at = NULL;
+
+ if (__nss_not_use_nscd_hosts || __nss_database_custom[NSS_DBSIDX_hosts])
+ return 0;
+
+ /* Try to use nscd. */
+ struct nscd_ai_result *air = NULL;
+ int err = __nscd_getai (name, &air, &h_errno);
+
+ if (__glibc_unlikely (air == NULL))
+ {
+ /* The database contains a negative entry. */
+ if (err == 0)
+ return -EAI_NONAME;
+ if (__nss_not_use_nscd_hosts == 0)
+ {
+ if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
+ return -EAI_MEMORY;
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+ return -EAI_SYSTEM;
+ }
+ return 0;
+ }
+
+ /* Transform into gaih_addrtuple list. */
+ int result = 0;
+ char *addrs = air->addrs;
+
+ struct gaih_addrtuple *addrfree = calloc (air->naddrs, sizeof (*addrfree));
+ struct gaih_addrtuple *at = calloc (air->naddrs, sizeof (*at));
+ if (at == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+
+ res->free_at = true;
+
+ int count = 0;
+ for (int i = 0; i < air->naddrs; ++i)
+ {
+ socklen_t size = (air->family[i] == AF_INET
+ ? INADDRSZ : IN6ADDRSZ);
+
+ if (!((air->family[i] == AF_INET
+ && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED) != 0)
+ || req->ai_family == AF_UNSPEC
+ || air->family[i] == req->ai_family))
+ {
+ /* Skip over non-matching result. */
+ addrs += size;
+ continue;
+ }
+
+ if (air->family[i] == AF_INET && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED))
+ {
+ at[count].family = AF_INET6;
+ at[count].addr[3] = *(uint32_t *) addrs;
+ at[count].addr[2] = htonl (0xffff);
+ }
+ else if (req->ai_family == AF_UNSPEC
+ || air->family[count] == req->ai_family)
+ {
+ at[count].family = air->family[count];
+ memcpy (at[count].addr, addrs, size);
+ if (air->family[count] == AF_INET6)
+ res->got_ipv6 = true;
+ }
+ at[count].next = at + count + 1;
+ count++;
+ addrs += size;
+ }
+
+ if ((req->ai_flags & AI_CANONNAME) && air->canon != NULL)
+ {
+ char *canonbuf = __strdup (air->canon);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+
+ if (count == 0)
+ {
+ result = -EAI_NONAME;
+ goto out;
+ }
+
+ at[count - 1].next = NULL;
+
+ res->at = at;
+
+out:
+ free (air);
+ if (result != 0)
+ {
+ free (at);
+ res->free_at = false;
+ }
+
+ return result;
+}
+#endif
+
/* Convert numeric addresses to binary into RES. On failure, RES->AT is set to
NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and
the function cannot determine a result, RES->AT is set to NULL and 0
@@ -630,7 +753,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
/ sizeof (struct gaih_typeproto)] = {0};
- bool got_ipv6 = false;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -672,6 +794,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (res.at != NULL)
goto process_list;
+#ifdef USE_NSCD
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+#endif
+
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -681,115 +810,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct resolv_context *res_ctx = NULL;
bool do_merge = false;
-#ifdef USE_NSCD
- if (__nss_not_use_nscd_hosts > 0
- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
- __nss_not_use_nscd_hosts = 0;
-
- if (!__nss_not_use_nscd_hosts
- && !__nss_database_custom[NSS_DBSIDX_hosts])
- {
- /* Try to use nscd. */
- struct nscd_ai_result *air = NULL;
- int err = __nscd_getai (name, &air, &h_errno);
- if (air != NULL)
- {
- /* Transform into gaih_addrtuple list. */
- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
- char *addrs = air->addrs;
-
- addrmem = calloc (air->naddrs, sizeof (*addrmem));
- if (addrmem == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- struct gaih_addrtuple *addrfree = addrmem;
- struct gaih_addrtuple **pat = &res.at;
-
- for (int i = 0; i < air->naddrs; ++i)
- {
- socklen_t size = (air->family[i] == AF_INET
- ? INADDRSZ : IN6ADDRSZ);
-
- if (!((air->family[i] == AF_INET
- && req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED) != 0)
- || req->ai_family == AF_UNSPEC
- || air->family[i] == req->ai_family))
- {
- /* Skip over non-matching result. */
- addrs += size;
- continue;
- }
-
- if (*pat == NULL)
- {
- *pat = addrfree++;
- (*pat)->scopeid = 0;
- }
- uint32_t *pataddr = (*pat)->addr;
- (*pat)->next = NULL;
- if (added_canon || air->canon == NULL)
- (*pat)->name = NULL;
- else if (res.canon == NULL)
- {
- char *canonbuf = __strdup (air->canon);
- if (canonbuf == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = (*pat)->name = canonbuf;
- }
-
- if (air->family[i] == AF_INET
- && req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED))
- {
- (*pat)->family = AF_INET6;
- pataddr[3] = *(uint32_t *) addrs;
- pataddr[2] = htonl (0xffff);
- pataddr[1] = 0;
- pataddr[0] = 0;
- pat = &((*pat)->next);
- added_canon = true;
- }
- else if (req->ai_family == AF_UNSPEC
- || air->family[i] == req->ai_family)
- {
- (*pat)->family = air->family[i];
- memcpy (pataddr, addrs, size);
- pat = &((*pat)->next);
- added_canon = true;
- if (air->family[i] == AF_INET6)
- got_ipv6 = true;
- }
- addrs += size;
- }
-
- free (air);
-
- goto process_list;
- }
- else if (err == 0)
- /* The database contains a negative entry. */
- goto free_and_return;
- else if (__nss_not_use_nscd_hosts == 0)
- {
- if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
- result = -EAI_MEMORY;
- else if (h_errno == TRY_AGAIN)
- result = -EAI_AGAIN;
- else
- result = -EAI_SYSTEM;
-
- goto free_and_return;
- }
- }
-#endif
-
no_more = !__nss_database_get (nss_database_hosts, &nip);
/* If we are looking for both IPv4 and IPv6 address we don't
@@ -897,7 +917,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 0;
if (req->ai_family == AF_INET6)
- got_ipv6 = true;
+ res.got_ipv6 = true;
}
else
*pat = ((*pat)->next);
@@ -940,7 +960,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
&& (req->ai_flags & AI_V4MAPPED)
/* Avoid generating the mapped addresses if we
know we are not going to need them. */
- && ((req->ai_flags & AI_ALL) || !got_ipv6)))
+ && ((req->ai_flags & AI_ALL) || !res.got_ipv6)))
{
gethosts (AF_INET);
@@ -1091,7 +1111,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* If we looked up IPv4 mapped address discard them here if
the caller isn't interested in all address and we have
found at least one IPv6 address. */
- if (got_ipv6
+ if (res.got_ipv6
&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
&& IN6_IS_ADDR_V4MAPPED (at2->addr))
goto ignore;

@ -0,0 +1,673 @@
commit ec71cb961121760f81e55af5489e658dc89e96e6
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Mon Mar 7 15:56:22 2022 +0530
gaih_inet: separate nss lookup loop into its own function
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 906cecbe0889e601c91d9aba738049c73ebe4dd2)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 7c497a88f8b5b9f8..145ea6fa381ad14b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -159,6 +159,14 @@ static const struct addrinfo default_hints =
.ai_next = NULL
};
+static void
+gaih_result_reset (struct gaih_result *res)
+{
+ if (res->free_at)
+ free (res->at);
+ free (res->canon);
+ memset (res, 0, sizeof (*res));
+}
static int
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
@@ -197,13 +205,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
is not copied, and the struct hostent object must not be deallocated
- prematurely. The new addresses are appended to the tuple array in
- RESULT. */
+ prematurely. The new addresses are appended to the tuple array in RES. */
static bool
-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
- int family,
- struct hostent *h,
- struct gaih_addrtuple **result)
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
+ struct hostent *h, struct gaih_result *res)
{
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
@@ -215,7 +220,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = *result;
+ struct gaih_addrtuple *array = res->at;
size_t old = 0;
while (array != NULL)
@@ -224,12 +229,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array = array->next;
}
- array = realloc (*result, (old + count) * sizeof (*array));
+ array = realloc (res->at, (old + count) * sizeof (*array));
if (array == NULL)
return false;
- *result = array;
+ res->got_ipv6 = family == AF_INET6;
+ res->at = array;
+ res->free_at = true;
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_MEMORY; \
- goto free_and_return; \
+ goto out; \
} \
} \
if (status == NSS_STATUS_NOTFOUND \
@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
if (h_errno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
else if (status == NSS_STATUS_SUCCESS) \
{ \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
+ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- *pat = addrmem; \
\
- if (localcanon != NULL && res.canon == NULL) \
+ if (localcanon != NULL && res->canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- res.canon = canonbuf; \
+ res->canon = canonbuf; \
} \
- if (_family == AF_INET6 && *pat != NULL) \
- res.got_ipv6 = true; \
} \
}
@@ -590,6 +594,260 @@ out:
}
#endif
+static int
+get_nss_addresses (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf, struct gaih_result *res)
+{
+ int no_data = 0;
+ int no_inet6_data = 0;
+ nss_action_list nip;
+ enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
+ enum nss_status status = NSS_STATUS_UNAVAIL;
+ int no_more;
+ struct resolv_context *res_ctx = NULL;
+ bool do_merge = false;
+ int result = 0;
+
+ no_more = !__nss_database_get (nss_database_hosts, &nip);
+
+ /* If we are looking for both IPv4 and IPv6 address we don't
+ want the lookup functions to automatically promote IPv4
+ addresses to IPv6 addresses, so we use the no_inet6
+ function variant. */
+ res_ctx = __resolv_context_get ();
+ if (res_ctx == NULL)
+ no_more = 1;
+
+ while (!no_more)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ gaih_result_reset (res);
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ no_data = 0;
+ nss_gethostbyname4_r *fct4 = NULL;
+
+ /* gethostbyname4_r sends out parallel A and AAAA queries and
+ is thus only suitable for PF_UNSPEC. */
+ if (req->ai_family == PF_UNSPEC)
+ fct4 = __nss_lookup_function (nip, "gethostbyname4_r");
+
+ if (fct4 != NULL)
+ {
+ while (1)
+ {
+ status = DL_CALL_FCT (fct4, (name, &res->at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res->at = NULL;
+ if (status != NSS_STATUS_TRYAGAIN
+ || errno != ERANGE || h_errno != NETDB_INTERNAL)
+ {
+ if (h_errno == TRY_AGAIN)
+ no_data = EAI_AGAIN;
+ else
+ no_data = h_errno == NO_DATA;
+ break;
+ }
+
+ if (!scratch_buffer_grow (tmpbuf))
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (res->at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+
+ struct gaih_addrtuple **pat = &res->at;
+
+ while (*pat != NULL)
+ {
+ if ((*pat)->family == AF_INET
+ && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED) != 0)
+ {
+ uint32_t *pataddr = (*pat)->addr;
+ (*pat)->family = AF_INET6;
+ pataddr[3] = pataddr[0];
+ pataddr[2] = htonl (0xffff);
+ pataddr[1] = 0;
+ pataddr[0] = 0;
+ pat = &((*pat)->next);
+ no_data = 0;
+ }
+ else if (req->ai_family == AF_UNSPEC
+ || (*pat)->family == req->ai_family)
+ {
+ pat = &((*pat)->next);
+
+ no_data = 0;
+ if (req->ai_family == AF_INET6)
+ res->got_ipv6 = true;
+ }
+ else
+ *pat = ((*pat)->next);
+ }
+ }
+
+ no_inet6_data = no_data;
+ }
+ else
+ {
+ nss_gethostbyname3_r *fct = NULL;
+ if (req->ai_flags & AI_CANONNAME)
+ /* No need to use this function if we do not look for
+ the canonical name. The function does not exist in
+ all NSS modules and therefore the lookup would
+ often fail. */
+ fct = __nss_lookup_function (nip, "gethostbyname3_r");
+ if (fct == NULL)
+ /* We are cheating here. The gethostbyname2_r
+ function does not have the same interface as
+ gethostbyname3_r but the extra arguments the
+ latter takes are added at the end. So the
+ gethostbyname2_r code will just ignore them. */
+ fct = __nss_lookup_function (nip, "gethostbyname2_r");
+
+ if (fct != NULL)
+ {
+ if (req->ai_family == AF_INET6
+ || req->ai_family == AF_UNSPEC)
+ {
+ gethosts (AF_INET6);
+ no_inet6_data = no_data;
+ inet6_status = status;
+ }
+ if (req->ai_family == AF_INET
+ || req->ai_family == AF_UNSPEC
+ || (req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED)
+ /* Avoid generating the mapped addresses if we
+ know we are not going to need them. */
+ && ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
+ {
+ gethosts (AF_INET);
+
+ if (req->ai_family == AF_INET)
+ {
+ no_inet6_data = no_data;
+ inet6_status = status;
+ }
+ }
+
+ /* If we found one address for AF_INET or AF_INET6,
+ don't continue the search. */
+ if (inet6_status == NSS_STATUS_SUCCESS
+ || status == NSS_STATUS_SUCCESS)
+ {
+ if ((req->ai_flags & AI_CANONNAME) != 0
+ && res->canon == NULL)
+ {
+ char *canonbuf = getcanonname (nip, res->at, name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ status = NSS_STATUS_SUCCESS;
+ }
+ else
+ {
+ /* We can have different states for AF_INET and
+ AF_INET6. Try to find a useful one for both. */
+ if (inet6_status == NSS_STATUS_TRYAGAIN)
+ status = NSS_STATUS_TRYAGAIN;
+ else if (status == NSS_STATUS_UNAVAIL
+ && inet6_status != NSS_STATUS_UNAVAIL)
+ status = inet6_status;
+ }
+ }
+ else
+ {
+ /* Could not locate any of the lookup functions.
+ The NSS lookup code does not consistently set
+ errno, so we need to supply our own error
+ code here. The root cause could either be a
+ resource allocation failure, or a missing
+ service function in the DSO (so it should not
+ be listed in /etc/nsswitch.conf). Assume the
+ former, and return EBUSY. */
+ status = NSS_STATUS_UNAVAIL;
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ }
+ }
+
+ if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ break;
+
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
+ nip++;
+ if (nip->module == NULL)
+ no_more = -1;
+ }
+
+ __resolv_context_put (res_ctx);
+
+ /* If we have a failure which sets errno, report it using
+ EAI_SYSTEM. */
+ if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
+ && h_errno == NETDB_INTERNAL)
+ {
+ result = -EAI_SYSTEM;
+ goto out;
+ }
+
+ if (no_data != 0 && no_inet6_data != 0)
+ {
+ /* If both requests timed out report this. */
+ if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
+ result = -EAI_AGAIN;
+ else
+ /* We made requests but they turned out no data. The name
+ is known, though. */
+ result = -EAI_NODATA;
+ }
+
+out:
+ if (result != 0)
+ gaih_result_reset (res);
+ return result;
+}
+
/* Convert numeric addresses to binary into RES. On failure, RES->AT is set to
NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and
the function cannot determine a result, RES->AT is set to NULL and 0
@@ -723,7 +981,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
/* We found data, convert it. RES->AT from the conversion will
either be an allocated block or NULL, both of which are safe to
pass to free (). */
- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res))
return -EAI_MEMORY;
res->free_at = true;
@@ -801,264 +1059,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto process_list;
#endif
- int no_data = 0;
- int no_inet6_data = 0;
- nss_action_list nip;
- enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
- enum nss_status status = NSS_STATUS_UNAVAIL;
- int no_more;
- struct resolv_context *res_ctx = NULL;
- bool do_merge = false;
-
- no_more = !__nss_database_get (nss_database_hosts, &nip);
-
- /* If we are looking for both IPv4 and IPv6 address we don't
- want the lookup functions to automatically promote IPv4
- addresses to IPv6 addresses, so we use the no_inet6
- function variant. */
- res_ctx = __resolv_context_get ();
- if (res_ctx == NULL)
- no_more = 1;
-
- while (!no_more)
- {
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- res.at = NULL;
- free (res.canon);
- free (addrmem);
- res.canon = NULL;
- addrmem = NULL;
- got_ipv6 = false;
-
- if (do_merge)
- {
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- no_data = 0;
- nss_gethostbyname4_r *fct4 = NULL;
-
- /* gethostbyname4_r sends out parallel A and AAAA queries and
- is thus only suitable for PF_UNSPEC. */
- if (req->ai_family == PF_UNSPEC)
- fct4 = __nss_lookup_function (nip, "gethostbyname4_r");
-
- if (fct4 != NULL)
- {
- while (1)
- {
- status = DL_CALL_FCT (fct4, (name, &res.at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- res.at = NULL;
- if (status != NSS_STATUS_TRYAGAIN
- || errno != ERANGE || h_errno != NETDB_INTERNAL)
- {
- if (h_errno == TRY_AGAIN)
- no_data = EAI_AGAIN;
- else
- no_data = h_errno == NO_DATA;
- break;
- }
-
- if (!scratch_buffer_grow (tmpbuf))
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
-
- if (status == NSS_STATUS_SUCCESS)
- {
- assert (!no_data);
- no_data = 1;
-
- if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL)
- {
- char *canonbuf = __strdup (res.at->name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &res.at;
-
- while (*pat != NULL)
- {
- if ((*pat)->family == AF_INET
- && req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED) != 0)
- {
- uint32_t *pataddr = (*pat)->addr;
- (*pat)->family = AF_INET6;
- pataddr[3] = pataddr[0];
- pataddr[2] = htonl (0xffff);
- pataddr[1] = 0;
- pataddr[0] = 0;
- pat = &((*pat)->next);
- no_data = 0;
- }
- else if (req->ai_family == AF_UNSPEC
- || (*pat)->family == req->ai_family)
- {
- pat = &((*pat)->next);
-
- no_data = 0;
- if (req->ai_family == AF_INET6)
- res.got_ipv6 = true;
- }
- else
- *pat = ((*pat)->next);
- }
- }
-
- no_inet6_data = no_data;
- }
- else
- {
- nss_gethostbyname3_r *fct = NULL;
- if (req->ai_flags & AI_CANONNAME)
- /* No need to use this function if we do not look for
- the canonical name. The function does not exist in
- all NSS modules and therefore the lookup would
- often fail. */
- fct = __nss_lookup_function (nip, "gethostbyname3_r");
- if (fct == NULL)
- /* We are cheating here. The gethostbyname2_r
- function does not have the same interface as
- gethostbyname3_r but the extra arguments the
- latter takes are added at the end. So the
- gethostbyname2_r code will just ignore them. */
- fct = __nss_lookup_function (nip, "gethostbyname2_r");
-
- if (fct != NULL)
- {
- struct gaih_addrtuple **pat = &res.at;
-
- if (req->ai_family == AF_INET6
- || req->ai_family == AF_UNSPEC)
- {
- gethosts (AF_INET6);
- no_inet6_data = no_data;
- inet6_status = status;
- }
- if (req->ai_family == AF_INET
- || req->ai_family == AF_UNSPEC
- || (req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED)
- /* Avoid generating the mapped addresses if we
- know we are not going to need them. */
- && ((req->ai_flags & AI_ALL) || !res.got_ipv6)))
- {
- gethosts (AF_INET);
-
- if (req->ai_family == AF_INET)
- {
- no_inet6_data = no_data;
- inet6_status = status;
- }
- }
-
- /* If we found one address for AF_INET or AF_INET6,
- don't continue the search. */
- if (inet6_status == NSS_STATUS_SUCCESS
- || status == NSS_STATUS_SUCCESS)
- {
- if ((req->ai_flags & AI_CANONNAME) != 0
- && res.canon == NULL)
- {
- char *canonbuf = getcanonname (nip, res.at, name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = canonbuf;
- }
- status = NSS_STATUS_SUCCESS;
- }
- else
- {
- /* We can have different states for AF_INET and
- AF_INET6. Try to find a useful one for both. */
- if (inet6_status == NSS_STATUS_TRYAGAIN)
- status = NSS_STATUS_TRYAGAIN;
- else if (status == NSS_STATUS_UNAVAIL
- && inet6_status != NSS_STATUS_UNAVAIL)
- status = inet6_status;
- }
- }
- else
- {
- /* Could not locate any of the lookup functions.
- The NSS lookup code does not consistently set
- errno, so we need to supply our own error
- code here. The root cause could either be a
- resource allocation failure, or a missing
- service function in the DSO (so it should not
- be listed in /etc/nsswitch.conf). Assume the
- former, and return EBUSY. */
- status = NSS_STATUS_UNAVAIL;
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- }
- }
-
- if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
- break;
-
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
-
- nip++;
- if (nip->module == NULL)
- no_more = -1;
- }
-
- __resolv_context_put (res_ctx);
-
- /* If we have a failure which sets errno, report it using
- EAI_SYSTEM. */
- if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
- && h_errno == NETDB_INTERNAL)
- {
- result = -EAI_SYSTEM;
- goto free_and_return;
- }
-
- if (no_data != 0 && no_inet6_data != 0)
- {
- /* If both requests timed out report this. */
- if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
- result = -EAI_AGAIN;
- else
- /* We made requests but they turned out no data. The name
- is known, though. */
- result = -EAI_NODATA;
-
- goto free_and_return;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- process_list:
- if (res.at == NULL)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
}
else
{
@@ -1089,6 +1097,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
+process_list:
{
/* Set up the canonical name if we need it. */
if ((result = process_canonname (req, orig_name, &res)) != 0)

@ -0,0 +1,973 @@
commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Mar 17 11:44:34 2022 +0530
Simplify allocations and fix merge and continue actions [BZ #28931]
Allocations for address tuples is currently a bit confusing because of
the pointer chasing through PAT, making it hard to observe the sequence
in which allocations have been made. Narrow scope of the pointer
chasing through PAT so that it is only used where necessary.
This also tightens actions behaviour with the hosts database in
getaddrinfo to comply with the manual text. The "continue" action
discards previous results and the "merge" action results in an immedate
lookup failure. Consequently, chaining of allocations across modules is
no longer necessary, thus opening up cleanup opportunities.
A test has been added that checks some combinations to ensure that they
work correctly.
Resolves: BZ #28931
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
nss/Makefile
(Missing tests)
diff --git a/nss/Makefile b/nss/Makefile
index 716bc8f6ef5276b0..beb30ac2667fe998 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -70,6 +70,7 @@ tests-container = \
tst-nss-files-hosts-long \
tst-nss-db-endpwent \
tst-nss-db-endgrent \
+ tst-nss-gai-actions \
tst-reload1 tst-reload2
# Tests which need libdl
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
new file mode 100644
index 0000000000000000..efca6cd1837a172a
--- /dev/null
+++ b/nss/tst-nss-gai-actions.c
@@ -0,0 +1,149 @@
+/* Test continue and merge NSS actions for getaddrinfo.
+ Copyright The GNU Toolchain Authors.
+ 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 <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+enum
+{
+ ACTION_MERGE = 0,
+ ACTION_CONTINUE,
+};
+
+static const char *
+family_str (int family)
+{
+ switch (family)
+ {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+action_str (int action)
+{
+ switch (action)
+ {
+ case ACTION_MERGE:
+ return "merge";
+ case ACTION_CONTINUE:
+ return "continue";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test (int action, int family, bool canon)
+{
+ struct addrinfo hints =
+ {
+ .ai_family = family,
+ };
+
+ struct addrinfo *ai;
+
+ if (canon)
+ hints.ai_flags = AI_CANONNAME;
+
+ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
+ action_str (action), family_str (family),
+ canon ? "AI_CANONNAME" : "");
+
+ int ret = getaddrinfo ("example.org", "80", &hints, &ai);
+
+ switch (action)
+ {
+ case ACTION_MERGE:
+ if (ret == 0)
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ printf ("merge unexpectedly succeeded:\n %s\n", formatted);
+ support_record_failure ();
+ free (formatted);
+ }
+ else
+ return;
+ case ACTION_CONTINUE:
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ /* Verify that the result appears exactly once. */
+ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
+ "address: DGRAM/UDP 192.0.0.1 80\n"
+ "address: RAW/IP 192.0.0.1 80\n";
+
+ const char *contains = strstr (formatted, expected);
+ const char *contains2 = NULL;
+
+ if (contains != NULL)
+ contains2 = strstr (contains + strlen (expected), expected);
+
+ if (contains == NULL || contains2 != NULL)
+ {
+ printf ("continue failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+
+ free (formatted);
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test_set (int action)
+{
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
+ action_str (action));
+ __nss_configure_lookup ("hosts", buf);
+
+ do_one_test (action, AF_UNSPEC, false);
+ do_one_test (action, AF_INET, false);
+ do_one_test (action, AF_INET, true);
+}
+
+static int
+do_test (void)
+{
+ do_one_test_set (ACTION_CONTINUE);
+ do_one_test_set (ACTION_MERGE);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
new file mode 100644
index 0000000000000000..d1a59f73a90f2993
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/host.conf
@@ -0,0 +1 @@
+multi on
diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
new file mode 100644
index 0000000000000000..50ce9774dc2c21d9
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/hosts
@@ -0,0 +1,508 @@
+192.0.0.1 example.org
+192.0.0.2 example.org
+192.0.0.3 example.org
+192.0.0.4 example.org
+192.0.0.5 example.org
+192.0.0.6 example.org
+192.0.0.7 example.org
+192.0.0.8 example.org
+192.0.0.9 example.org
+192.0.0.10 example.org
+192.0.0.11 example.org
+192.0.0.12 example.org
+192.0.0.13 example.org
+192.0.0.14 example.org
+192.0.0.15 example.org
+192.0.0.16 example.org
+192.0.0.17 example.org
+192.0.0.18 example.org
+192.0.0.19 example.org
+192.0.0.20 example.org
+192.0.0.21 example.org
+192.0.0.22 example.org
+192.0.0.23 example.org
+192.0.0.24 example.org
+192.0.0.25 example.org
+192.0.0.26 example.org
+192.0.0.27 example.org
+192.0.0.28 example.org
+192.0.0.29 example.org
+192.0.0.30 example.org
+192.0.0.31 example.org
+192.0.0.32 example.org
+192.0.0.33 example.org
+192.0.0.34 example.org
+192.0.0.35 example.org
+192.0.0.36 example.org
+192.0.0.37 example.org
+192.0.0.38 example.org
+192.0.0.39 example.org
+192.0.0.40 example.org
+192.0.0.41 example.org
+192.0.0.42 example.org
+192.0.0.43 example.org
+192.0.0.44 example.org
+192.0.0.45 example.org
+192.0.0.46 example.org
+192.0.0.47 example.org
+192.0.0.48 example.org
+192.0.0.49 example.org
+192.0.0.50 example.org
+192.0.0.51 example.org
+192.0.0.52 example.org
+192.0.0.53 example.org
+192.0.0.54 example.org
+192.0.0.55 example.org
+192.0.0.56 example.org
+192.0.0.57 example.org
+192.0.0.58 example.org
+192.0.0.59 example.org
+192.0.0.60 example.org
+192.0.0.61 example.org
+192.0.0.62 example.org
+192.0.0.63 example.org
+192.0.0.64 example.org
+192.0.0.65 example.org
+192.0.0.66 example.org
+192.0.0.67 example.org
+192.0.0.68 example.org
+192.0.0.69 example.org
+192.0.0.70 example.org
+192.0.0.71 example.org
+192.0.0.72 example.org
+192.0.0.73 example.org
+192.0.0.74 example.org
+192.0.0.75 example.org
+192.0.0.76 example.org
+192.0.0.77 example.org
+192.0.0.78 example.org
+192.0.0.79 example.org
+192.0.0.80 example.org
+192.0.0.81 example.org
+192.0.0.82 example.org
+192.0.0.83 example.org
+192.0.0.84 example.org
+192.0.0.85 example.org
+192.0.0.86 example.org
+192.0.0.87 example.org
+192.0.0.88 example.org
+192.0.0.89 example.org
+192.0.0.90 example.org
+192.0.0.91 example.org
+192.0.0.92 example.org
+192.0.0.93 example.org
+192.0.0.94 example.org
+192.0.0.95 example.org
+192.0.0.96 example.org
+192.0.0.97 example.org
+192.0.0.98 example.org
+192.0.0.99 example.org
+192.0.0.100 example.org
+192.0.0.101 example.org
+192.0.0.102 example.org
+192.0.0.103 example.org
+192.0.0.104 example.org
+192.0.0.105 example.org
+192.0.0.106 example.org
+192.0.0.107 example.org
+192.0.0.108 example.org
+192.0.0.109 example.org
+192.0.0.110 example.org
+192.0.0.111 example.org
+192.0.0.112 example.org
+192.0.0.113 example.org
+192.0.0.114 example.org
+192.0.0.115 example.org
+192.0.0.116 example.org
+192.0.0.117 example.org
+192.0.0.118 example.org
+192.0.0.119 example.org
+192.0.0.120 example.org
+192.0.0.121 example.org
+192.0.0.122 example.org
+192.0.0.123 example.org
+192.0.0.124 example.org
+192.0.0.125 example.org
+192.0.0.126 example.org
+192.0.0.127 example.org
+192.0.0.128 example.org
+192.0.0.129 example.org
+192.0.0.130 example.org
+192.0.0.131 example.org
+192.0.0.132 example.org
+192.0.0.133 example.org
+192.0.0.134 example.org
+192.0.0.135 example.org
+192.0.0.136 example.org
+192.0.0.137 example.org
+192.0.0.138 example.org
+192.0.0.139 example.org
+192.0.0.140 example.org
+192.0.0.141 example.org
+192.0.0.142 example.org
+192.0.0.143 example.org
+192.0.0.144 example.org
+192.0.0.145 example.org
+192.0.0.146 example.org
+192.0.0.147 example.org
+192.0.0.148 example.org
+192.0.0.149 example.org
+192.0.0.150 example.org
+192.0.0.151 example.org
+192.0.0.152 example.org
+192.0.0.153 example.org
+192.0.0.154 example.org
+192.0.0.155 example.org
+192.0.0.156 example.org
+192.0.0.157 example.org
+192.0.0.158 example.org
+192.0.0.159 example.org
+192.0.0.160 example.org
+192.0.0.161 example.org
+192.0.0.162 example.org
+192.0.0.163 example.org
+192.0.0.164 example.org
+192.0.0.165 example.org
+192.0.0.166 example.org
+192.0.0.167 example.org
+192.0.0.168 example.org
+192.0.0.169 example.org
+192.0.0.170 example.org
+192.0.0.171 example.org
+192.0.0.172 example.org
+192.0.0.173 example.org
+192.0.0.174 example.org
+192.0.0.175 example.org
+192.0.0.176 example.org
+192.0.0.177 example.org
+192.0.0.178 example.org
+192.0.0.179 example.org
+192.0.0.180 example.org
+192.0.0.181 example.org
+192.0.0.182 example.org
+192.0.0.183 example.org
+192.0.0.184 example.org
+192.0.0.185 example.org
+192.0.0.186 example.org
+192.0.0.187 example.org
+192.0.0.188 example.org
+192.0.0.189 example.org
+192.0.0.190 example.org
+192.0.0.191 example.org
+192.0.0.192 example.org
+192.0.0.193 example.org
+192.0.0.194 example.org
+192.0.0.195 example.org
+192.0.0.196 example.org
+192.0.0.197 example.org
+192.0.0.198 example.org
+192.0.0.199 example.org
+192.0.0.200 example.org
+192.0.0.201 example.org
+192.0.0.202 example.org
+192.0.0.203 example.org
+192.0.0.204 example.org
+192.0.0.205 example.org
+192.0.0.206 example.org
+192.0.0.207 example.org
+192.0.0.208 example.org
+192.0.0.209 example.org
+192.0.0.210 example.org
+192.0.0.211 example.org
+192.0.0.212 example.org
+192.0.0.213 example.org
+192.0.0.214 example.org
+192.0.0.215 example.org
+192.0.0.216 example.org
+192.0.0.217 example.org
+192.0.0.218 example.org
+192.0.0.219 example.org
+192.0.0.220 example.org
+192.0.0.221 example.org
+192.0.0.222 example.org
+192.0.0.223 example.org
+192.0.0.224 example.org
+192.0.0.225 example.org
+192.0.0.226 example.org
+192.0.0.227 example.org
+192.0.0.228 example.org
+192.0.0.229 example.org
+192.0.0.230 example.org
+192.0.0.231 example.org
+192.0.0.232 example.org
+192.0.0.233 example.org
+192.0.0.234 example.org
+192.0.0.235 example.org
+192.0.0.236 example.org
+192.0.0.237 example.org
+192.0.0.238 example.org
+192.0.0.239 example.org
+192.0.0.240 example.org
+192.0.0.241 example.org
+192.0.0.242 example.org
+192.0.0.243 example.org
+192.0.0.244 example.org
+192.0.0.245 example.org
+192.0.0.246 example.org
+192.0.0.247 example.org
+192.0.0.248 example.org
+192.0.0.249 example.org
+192.0.0.250 example.org
+192.0.0.251 example.org
+192.0.0.252 example.org
+192.0.0.253 example.org
+192.0.0.254 example.org
+192.0.1.1 example.org
+192.0.1.2 example.org
+192.0.1.3 example.org
+192.0.1.4 example.org
+192.0.1.5 example.org
+192.0.1.6 example.org
+192.0.1.7 example.org
+192.0.1.8 example.org
+192.0.1.9 example.org
+192.0.1.10 example.org
+192.0.1.11 example.org
+192.0.1.12 example.org
+192.0.1.13 example.org
+192.0.1.14 example.org
+192.0.1.15 example.org
+192.0.1.16 example.org
+192.0.1.17 example.org
+192.0.1.18 example.org
+192.0.1.19 example.org
+192.0.1.20 example.org
+192.0.1.21 example.org
+192.0.1.22 example.org
+192.0.1.23 example.org
+192.0.1.24 example.org
+192.0.1.25 example.org
+192.0.1.26 example.org
+192.0.1.27 example.org
+192.0.1.28 example.org
+192.0.1.29 example.org
+192.0.1.30 example.org
+192.0.1.31 example.org
+192.0.1.32 example.org
+192.0.1.33 example.org
+192.0.1.34 example.org
+192.0.1.35 example.org
+192.0.1.36 example.org
+192.0.1.37 example.org
+192.0.1.38 example.org
+192.0.1.39 example.org
+192.0.1.40 example.org
+192.0.1.41 example.org
+192.0.1.42 example.org
+192.0.1.43 example.org
+192.0.1.44 example.org
+192.0.1.45 example.org
+192.0.1.46 example.org
+192.0.1.47 example.org
+192.0.1.48 example.org
+192.0.1.49 example.org
+192.0.1.50 example.org
+192.0.1.51 example.org
+192.0.1.52 example.org
+192.0.1.53 example.org
+192.0.1.54 example.org
+192.0.1.55 example.org
+192.0.1.56 example.org
+192.0.1.57 example.org
+192.0.1.58 example.org
+192.0.1.59 example.org
+192.0.1.60 example.org
+192.0.1.61 example.org
+192.0.1.62 example.org
+192.0.1.63 example.org
+192.0.1.64 example.org
+192.0.1.65 example.org
+192.0.1.66 example.org
+192.0.1.67 example.org
+192.0.1.68 example.org
+192.0.1.69 example.org
+192.0.1.70 example.org
+192.0.1.71 example.org
+192.0.1.72 example.org
+192.0.1.73 example.org
+192.0.1.74 example.org
+192.0.1.75 example.org
+192.0.1.76 example.org
+192.0.1.77 example.org
+192.0.1.78 example.org
+192.0.1.79 example.org
+192.0.1.80 example.org
+192.0.1.81 example.org
+192.0.1.82 example.org
+192.0.1.83 example.org
+192.0.1.84 example.org
+192.0.1.85 example.org
+192.0.1.86 example.org
+192.0.1.87 example.org
+192.0.1.88 example.org
+192.0.1.89 example.org
+192.0.1.90 example.org
+192.0.1.91 example.org
+192.0.1.92 example.org
+192.0.1.93 example.org
+192.0.1.94 example.org
+192.0.1.95 example.org
+192.0.1.96 example.org
+192.0.1.97 example.org
+192.0.1.98 example.org
+192.0.1.99 example.org
+192.0.1.100 example.org
+192.0.1.101 example.org
+192.0.1.102 example.org
+192.0.1.103 example.org
+192.0.1.104 example.org
+192.0.1.105 example.org
+192.0.1.106 example.org
+192.0.1.107 example.org
+192.0.1.108 example.org
+192.0.1.109 example.org
+192.0.1.110 example.org
+192.0.1.111 example.org
+192.0.1.112 example.org
+192.0.1.113 example.org
+192.0.1.114 example.org
+192.0.1.115 example.org
+192.0.1.116 example.org
+192.0.1.117 example.org
+192.0.1.118 example.org
+192.0.1.119 example.org
+192.0.1.120 example.org
+192.0.1.121 example.org
+192.0.1.122 example.org
+192.0.1.123 example.org
+192.0.1.124 example.org
+192.0.1.125 example.org
+192.0.1.126 example.org
+192.0.1.127 example.org
+192.0.1.128 example.org
+192.0.1.129 example.org
+192.0.1.130 example.org
+192.0.1.131 example.org
+192.0.1.132 example.org
+192.0.1.133 example.org
+192.0.1.134 example.org
+192.0.1.135 example.org
+192.0.1.136 example.org
+192.0.1.137 example.org
+192.0.1.138 example.org
+192.0.1.139 example.org
+192.0.1.140 example.org
+192.0.1.141 example.org
+192.0.1.142 example.org
+192.0.1.143 example.org
+192.0.1.144 example.org
+192.0.1.145 example.org
+192.0.1.146 example.org
+192.0.1.147 example.org
+192.0.1.148 example.org
+192.0.1.149 example.org
+192.0.1.150 example.org
+192.0.1.151 example.org
+192.0.1.152 example.org
+192.0.1.153 example.org
+192.0.1.154 example.org
+192.0.1.155 example.org
+192.0.1.156 example.org
+192.0.1.157 example.org
+192.0.1.158 example.org
+192.0.1.159 example.org
+192.0.1.160 example.org
+192.0.1.161 example.org
+192.0.1.162 example.org
+192.0.1.163 example.org
+192.0.1.164 example.org
+192.0.1.165 example.org
+192.0.1.166 example.org
+192.0.1.167 example.org
+192.0.1.168 example.org
+192.0.1.169 example.org
+192.0.1.170 example.org
+192.0.1.171 example.org
+192.0.1.172 example.org
+192.0.1.173 example.org
+192.0.1.174 example.org
+192.0.1.175 example.org
+192.0.1.176 example.org
+192.0.1.177 example.org
+192.0.1.178 example.org
+192.0.1.179 example.org
+192.0.1.180 example.org
+192.0.1.181 example.org
+192.0.1.182 example.org
+192.0.1.183 example.org
+192.0.1.184 example.org
+192.0.1.185 example.org
+192.0.1.186 example.org
+192.0.1.187 example.org
+192.0.1.188 example.org
+192.0.1.189 example.org
+192.0.1.190 example.org
+192.0.1.191 example.org
+192.0.1.192 example.org
+192.0.1.193 example.org
+192.0.1.194 example.org
+192.0.1.195 example.org
+192.0.1.196 example.org
+192.0.1.197 example.org
+192.0.1.198 example.org
+192.0.1.199 example.org
+192.0.1.200 example.org
+192.0.1.201 example.org
+192.0.1.202 example.org
+192.0.1.203 example.org
+192.0.1.204 example.org
+192.0.1.205 example.org
+192.0.1.206 example.org
+192.0.1.207 example.org
+192.0.1.208 example.org
+192.0.1.209 example.org
+192.0.1.210 example.org
+192.0.1.211 example.org
+192.0.1.212 example.org
+192.0.1.213 example.org
+192.0.1.214 example.org
+192.0.1.215 example.org
+192.0.1.216 example.org
+192.0.1.217 example.org
+192.0.1.218 example.org
+192.0.1.219 example.org
+192.0.1.220 example.org
+192.0.1.221 example.org
+192.0.1.222 example.org
+192.0.1.223 example.org
+192.0.1.224 example.org
+192.0.1.225 example.org
+192.0.1.226 example.org
+192.0.1.227 example.org
+192.0.1.228 example.org
+192.0.1.229 example.org
+192.0.1.230 example.org
+192.0.1.231 example.org
+192.0.1.232 example.org
+192.0.1.233 example.org
+192.0.1.234 example.org
+192.0.1.235 example.org
+192.0.1.236 example.org
+192.0.1.237 example.org
+192.0.1.238 example.org
+192.0.1.239 example.org
+192.0.1.240 example.org
+192.0.1.241 example.org
+192.0.1.242 example.org
+192.0.1.243 example.org
+192.0.1.244 example.org
+192.0.1.245 example.org
+192.0.1.246 example.org
+192.0.1.247 example.org
+192.0.1.248 example.org
+192.0.1.249 example.org
+192.0.1.250 example.org
+192.0.1.251 example.org
+192.0.1.252 example.org
+192.0.1.253 example.org
+192.0.1.254 example.org
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 43dfc6739e350a58..f391dc0a59849aab 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
if (req->ai_flags & AI_IDN)
{
char *out;
@@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ uint32_t addr[4];
+ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
{
+ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- at->family = AF_INET;
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET;
+ }
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
{
- at->addr[3] = at->addr[0];
+ at->addr[3] = addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
@@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME)
canon = name;
+
+ goto process_list;
}
- else if (at->family == AF_UNSPEC)
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+ if (e > 0)
{
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, at->addr);
+ at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (addr))
+ {
+ at->addr[0] = addr[3];
+ at->addr[1] = addr[1];
+ at->addr[2] = addr[2];
+ at->addr[3] = addr[3];
+ at->family = AF_INET;
+ }
else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name,
- at->addr);
- if (e > 0)
{
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- at->family = AF_INET6;
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (at->addr))
- {
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
-
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1,
+ &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto free_and_return;
}
+
+ if (req->ai_flags & AI_CANONNAME)
+ canon = name;
+
+ goto process_list;
}
- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+ if ((req->ai_flags & AI_NUMERICHOST) == 0)
{
- struct gaih_addrtuple **pat = &at;
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -543,6 +559,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more;
struct resolv_context *res_ctx = NULL;
+ bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support
@@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
}
else
{
@@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &at;
+
for (int i = 0; i < air->naddrs; ++i)
{
socklen_t size = (air->family[i] == AF_INET
@@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
- if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
-
goto process_list;
}
else if (err == 0)
@@ -732,6 +745,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+ got_ipv6 = false;
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
no_data = 0;
nss_gethostbyname4_r *fct4 = NULL;
@@ -744,12 +773,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
while (1)
{
- status = DL_CALL_FCT (fct4, (name, pat,
+ status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length,
&errno, &h_errno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL)
{
@@ -774,7 +805,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = (*pat)->name;
+ canon = at->name;
+
+ struct gaih_addrtuple **pat = &at;
while (*pat != NULL)
{
@@ -826,6 +859,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL)
{
+ struct gaih_addrtuple **pat = &at;
+
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
@@ -899,6 +934,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
nip++;
if (nip->module == NULL)
no_more = -1;
@@ -930,7 +969,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
process_list:
- if (at->family == AF_UNSPEC)
+ if (at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;

@ -0,0 +1,164 @@
This patch was developed under embargo and cannot reference an upstream
commit. To find the associated commit please review the upstream git
log for CVE-2023-4911 to identify the relevant commits.
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date: Tue Sep 19 11:52:44 2023 -0400
tunables: Terminate if end of input is reached (CVE-2023-4911)
The string parsing routine may end up writing beyond bounds of tunestr
if the input tunable string is malformed, of the form name=name=val.
This gets processed twice, first as name=name=val and next as name=val,
resulting in tunestr being name=name=val:name=val, thus overflowing
tunestr.
Terminate the parsing loop at the first instance itself so that tunestr
does not overflow.
This also fixes up tst-env-setuid-tunables to actually handle failures
correct and add new tests to validate the fix for this CVE.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
---
Tested on x86_64.
NEWS | 5 +++++
elf/dl-tunables.c | 17 ++++++++++-------
elf/tst-env-setuid-tunables.c | 36 +++++++++++++++++++++++++++--------
3 files changed, 43 insertions(+), 15 deletions(-)
Conflicts:
NEWS
(Dropped)
elf/tst-env-setuid-tunables.c
(Trivial HAVE_TUNABLES conflict)
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 8009e54ee5db32be..837474b5044cb5d7 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -188,11 +188,7 @@ parse_tunables (char *tunestr, char *valstring)
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
- {
- if (__libc_enable_secure)
- tunestr[off] = '\0';
- return;
- }
+ break;
/* We did not find a valid name-value pair before encountering the
colon. */
@@ -252,9 +248,16 @@ parse_tunables (char *tunestr, char *valstring)
}
}
- if (p[len] != '\0')
- p += len + 1;
+ /* We reached the end while processing the tunable string. */
+ if (p[len] == '\0')
+ break;
+
+ p += len + 1;
}
+
+ /* Terminate tunestr before we leave. */
+ if (__libc_enable_secure)
+ tunestr[off] = '\0';
}
#endif
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 05619c9adc8b2698..cd4e84364074c613 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -52,6 +52,8 @@ const char *teststrings[] =
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.check=2",
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
":glibc.malloc.garbage=2:glibc.malloc.check=1",
@@ -70,6 +72,8 @@ const char *resultstrings[] =
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "",
"",
"",
"",
@@ -84,11 +88,18 @@ test_child (int off)
const char *val = getenv ("GLIBC_TUNABLES");
#if HAVE_TUNABLES
+ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val);
+ fflush (stdout);
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
+ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n",
+ off, val, resultstrings[off]);
+ else
+ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off);
+
+ fflush (stdout);
return 1;
#else
@@ -117,21 +128,26 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
- exit (EXIT_SUCCESS);
+ /* Special return code to make sure that the child executed all the way
+ through. */
+ exit (42);
}
else
{
- int ret = 0;
-
/* Spawn tests. */
for (int i = 0; i < array_length (teststrings); i++)
{
char buf[INT_BUFSIZE_BOUND (int)];
- printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+ printf ("[%d] Spawned test for %s\n", i, teststrings[i]);
snprintf (buf, sizeof (buf), "%d\n", i);
+ fflush (stdout);
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
- exit (1);
+ {
+ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i);
+ support_record_failure ();
+ continue;
+ }
int status = support_capture_subprogram_self_sgid (buf);
@@ -139,9 +155,14 @@ do_test (int argc, char **argv)
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
- ret |= status;
+ if (WEXITSTATUS (status) != 42)
+ {
+ printf (" [%d] child failed with status %d\n", i,
+ WEXITSTATUS (status));
+ support_record_failure ();
+ }
}
- return ret;
+ return 0;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,187 @@
commit bd77dd7e73e3530203be1c52c8a29d08270cb25d
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Sep 13 14:10:56 2023 +0200
CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode
Without passing alt_dns_packet_buffer, __res_context_search can only
store 2048 bytes (what fits into dns_packet_buffer). However,
the function returns the total packet size, and the subsequent
DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end
of the stack-allocated buffer.
Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa
stub resolver option") and bug 30842.
Conflits:
resolv/Makefile
(missing tests)
diff --git a/resolv/Makefile b/resolv/Makefile
index ea1518ec2da860c1..2c43d52122ef4343 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -102,6 +102,7 @@ tests += \
tst-resolv-invalid-cname \
tst-resolv-network \
tst-resolv-noaaaa \
+ tst-resolv-noaaaa-vc \
tst-resolv-nondecimal \
tst-resolv-res_init-multi \
tst-resolv-search \
@@ -280,6 +281,7 @@ $(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-noaaaa-vc: $(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)
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 36789965c06757d0..3d261b6810bba5c9 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -428,7 +428,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
{
n = __res_context_search (ctx, name, C_IN, T_A,
dns_packet_buffer, sizeof (dns_packet_buffer),
- NULL, NULL, NULL, NULL, NULL);
+ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
if (n >= 0)
status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
&abuf, pat, errnop, herrnop, ttlp);
diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c
new file mode 100644
index 0000000000000000..9f5aebd99f2d74a2
--- /dev/null
+++ b/resolv/tst-resolv-noaaaa-vc.c
@@ -0,0 +1,129 @@
+/* Test the RES_NOAAAA resolver option with a large response.
+ Copyright (C) 2022-2023 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 <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* Used to keep track of the number of queries. */
+static volatile unsigned int queries;
+
+/* If true, add a large TXT record at the start of the answer section. */
+static volatile bool stuff_txt;
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ /* If not using TCP, just force its use. */
+ if (!ctx->tcp)
+ {
+ struct resolv_response_flags flags = {.tc = true};
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+ return;
+ }
+
+ /* The test needs to send four queries, the first three are used to
+ grow the NSS buffer via the ERANGE handshake. */
+ ++queries;
+ TEST_VERIFY (queries <= 4);
+
+ /* AAAA queries are supposed to be disabled. */
+ TEST_COMPARE (qtype, T_A);
+ TEST_COMPARE (qclass, C_IN);
+ TEST_COMPARE_STRING (qname, "example.com");
+
+ 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);
+
+ if (stuff_txt)
+ {
+ resolv_response_open_record (b, qname, qclass, T_TXT, 60);
+ int zero = 0;
+ for (int i = 0; i <= 15000; ++i)
+ resolv_response_add_data (b, &zero, sizeof (zero));
+ resolv_response_close_record (b);
+ }
+
+ for (int i = 0; i < 200; ++i)
+ {
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
+ char ipv4[4] = {192, 0, 2, i + 1};
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+ resolv_response_close_record (b);
+ }
+}
+
+static int
+do_test (void)
+{
+ struct resolv_test *obj = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response
+ });
+
+ _res.options |= RES_NOAAAA;
+
+ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt)
+ {
+ queries = 0;
+ stuff_txt = do_stuff_txt;
+
+ struct addrinfo *ai = NULL;
+ int ret;
+ ret = getaddrinfo ("example.com", "80",
+ &(struct addrinfo)
+ {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ }, &ai);
+
+ char *expected_result;
+ {
+ struct xmemstream mem;
+ xopen_memstream (&mem);
+ for (int i = 0; i < 200; ++i)
+ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1);
+ xfclose_memstream (&mem);
+ expected_result = mem.buffer;
+ }
+
+ check_addrinfo ("example.com", ai, ret, expected_result);
+
+ free (expected_result);
+ freeaddrinfo (ai);
+ }
+
+ resolv_test_end (obj);
+ return 0;
+}
+
+#include <support/test-driver.c>

@ -155,7 +155,7 @@ end \
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: 60%{?dist}
Release: 60%{?dist}.7
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@ -700,6 +700,26 @@ Patch468: glibc-upstream-2.34-386.patch
# glibc-upstream-2.34-387.patch is a NEWS-only update. Skipped downstream.
Patch469: glibc-upstream-2.34-388.patch
Patch470: glibc-upstream-2.34-389.patch
# (Reverted fixes for RHEL-3385 were here.)
Patch476: glibc-rh2234715.patch
Patch477: glibc-RHEL-2437.patch
Patch478: glibc-RHEL-2425-1.patch
Patch479: glibc-RHEL-2425-2.patch
Patch480: glibc-RHEL-2425-3.patch
Patch481: glibc-RHEL-2425-4.patch
Patch482: glibc-RHEL-2425-5.patch
Patch483: glibc-RHEL-2425-6.patch
Patch484: glibc-RHEL-2425-7.patch
Patch485: glibc-RHEL-2425-8.patch
Patch486: glibc-RHEL-2425-9.patch
Patch487: glibc-RHEL-2425-10.patch
Patch488: glibc-RHEL-2425-11.patch
Patch489: glibc-RHEL-2425-12.patch
Patch490: glibc-RHEL-2425-13.patch
Patch491: glibc-RHEL-2425-14.patch
Patch492: glibc-RHEL-2999.patch
Patch493: glibc-RHEL-2425-15.patch
Patch494: glibc-RHEL-2425-16.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2859,6 +2879,27 @@ fi
%endif
%changelog
* Mon Sep 25 2023 Florian Weimer <fweimer@redhat.com> - 2.34-60.7
- Fix memory leak regression in getaddrinfo (RHEL-2425)
* Tue Sep 19 2023 Carlos O'Donell <carlos@redhat.com> - 2.34-60.6
- CVE-2023-4911 glibc: buffer overflow in ld.so leading to privilege escalation (RHEL-2999)
* Tue Sep 19 2023 Carlos O'Donell <carlos@redhat.com> - 2.34-60.5
- Revert: Always call destructors in reverse constructor order (RHEL-3385)
* Mon Sep 18 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.34-60.4
- CVE-2023-4806 glibc: potential use-after-free in getaddrinfo (RHEL-2425)
* Fri Sep 15 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.34-60.3
- CVE-2023-4813: potential use-after-free in gaih_inet (RHEL-2437)
* Fri Sep 15 2023 Carlos O'Donell <carlos@redhat.com> - 2.34-60.2
- CVE-2023-4527: Stack read overflow in getaddrinfo in no-aaaa mode (#2234715)
* Wed Sep 13 2023 Florian Weimer <fweimer@redhat.com> - 2.34-60.1
- Always call destructors in reverse constructor order (RHEL-3385)
* Wed Mar 15 2023 MSVSphere Packaging Team <packager@msvsphere.ru> - 2.34-40
- Rebuilt for MSVSphere 9.1.

Loading…
Cancel
Save