File gai-merge-continue-actions.patch of Package glibc.29706
From d7c9af9a371712c83ce6cb54142f586339e9392d Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu, 17 Mar 2022 11:44:34 +0530
Subject: [PATCH] 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>
(cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215)
---
sysdeps/posix/getaddrinfo.c | 199 ++++++++++++++++++++----------------
1 file changed, 110 insertions(+), 89 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 715e85823e..98bab210c3 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -442,11 +442,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
int result = 0;
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
#ifdef HAVE_LIBIDN
if (req->ai_flags & AI_IDN)
{
@@ -477,13 +472,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
#endif
- 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;
@@ -497,102 +500,110 @@ 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;
- {
- bool malloc_namebuf = false;
- char *namebuf = (char *) name;
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ {
+ bool malloc_namebuf = false;
+ char *namebuf = (char *) name;
- if (__glibc_unlikely (scope_delim != NULL))
+ if (__glibc_unlikely (scope_delim != NULL))
+ {
+ if (malloc_name)
+ *scope_delim = '\0';
+ else
{
- if (malloc_name)
- *scope_delim = '\0';
+ if (__libc_use_alloca (alloca_used
+ + scope_delim - name + 1))
+ {
+ namebuf = alloca_account (scope_delim - name + 1,
+ alloca_used);
+ *((char *) __mempcpy (namebuf, name,
+ scope_delim - name)) = '\0';
+ }
else
{
- if (__libc_use_alloca (alloca_used
- + scope_delim - name + 1))
+ namebuf = strndup (name, scope_delim - name);
+ if (namebuf == NULL)
{
- namebuf = alloca_account (scope_delim - name + 1,
- alloca_used);
- *((char *) __mempcpy (namebuf, name,
- scope_delim - name)) = '\0';
- }
- else
- {
- namebuf = strndup (name, scope_delim - name);
- if (namebuf == NULL)
- {
- assert (!malloc_name);
- return -EAI_MEMORY;
- }
- malloc_namebuf = true;
+ assert (!malloc_name);
+ return -EAI_MEMORY;
}
+ malloc_namebuf = true;
}
}
+ }
- e = inet_pton (AF_INET6, namebuf, at->addr);
+ e = inet_pton (AF_INET6, namebuf, addr);
- if (malloc_namebuf)
- free (namebuf);
- else if (scope_delim != NULL && malloc_name)
- /* Undo what we did above. */
- *scope_delim = SCOPE_DELIMITER;
- }
- if (e > 0)
+ if (malloc_namebuf)
+ free (namebuf);
+ else if (scope_delim != NULL && malloc_name)
+ /* Undo what we did above. */
+ *scope_delim = SCOPE_DELIMITER;
+ }
+ if (e > 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_INET6)
{
- 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))
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ {
+ at->addr[0] = addr[3];
+ at->family = AF_INET;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
+
+ if (scope_delim != NULL)
+ {
+ int try_numericscope = 0;
+ if (IN6_IS_ADDR_LINKLOCAL (at->addr)
+ || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
{
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
+ at->scopeid = if_nametoindex (scope_delim + 1);
+ if (at->scopeid == 0)
+ try_numericscope = 1;
}
else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ try_numericscope = 1;
- if (scope_delim != NULL)
+ if (try_numericscope != 0)
{
- int try_numericscope = 0;
- if (IN6_IS_ADDR_LINKLOCAL (at->addr)
- || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
+ char *end;
+ assert (sizeof (uint32_t) <= sizeof (unsigned long));
+ at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
+ 10);
+ if (*end != '\0')
{
- at->scopeid = if_nametoindex (scope_delim + 1);
- if (at->scopeid == 0)
- try_numericscope = 1;
- }
- else
- try_numericscope = 1;
-
- if (try_numericscope != 0)
- {
- char *end;
- assert (sizeof (uint32_t) <= sizeof (unsigned long));
- at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
- 10);
- if (*end != '\0')
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_NONAME;
+ goto free_and_return;
}
}
-
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
}
+
+ 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;
service_user *nip;
@@ -655,7 +666,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
/* The conversion uses malloc unconditionally. */
malloc_addrmem = true;
}
@@ -716,6 +727,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
@@ -788,12 +801,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)
@@ -852,6 +859,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+ got_ipv6 = false;
+
no_data = 0;
nss_gethostbyname4_r fct4 = NULL;
@@ -867,11 +882,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (1)
{
rc = 0;
- status = DL_CALL_FCT (fct4, (name, pat, tmpbuf,
+ status = DL_CALL_FCT (fct4, (name, &at, tmpbuf,
tmpbuflen, &rc, &herrno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| rc != ERANGE || herrno != NETDB_INTERNAL)
{
@@ -909,7 +926,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)
{
@@ -961,6 +980,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)
{
@@ -1099,7 +1120,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;
--
2.42.0