mirror of
https://abf.rosa.ru/djam/glibc.git
synced 2025-02-23 15:02:47 +00:00
107 lines
4.4 KiB
Diff
107 lines
4.4 KiB
Diff
From 74d98fb3d9e489666195d69efff04b5760632312 Mon Sep 17 00:00:00 2001
|
|
From: Mikhail Novosyolov <m.novosyolov@rosalinux.ru>
|
|
Date: Mon, 11 Dec 2023 20:09:59 +0300
|
|
Subject: [PATCH] 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.
|
|
|
|
Minimal port of https://git.almalinux.org/rpms/glibc/src/branch/c8/SOURCES/glibc-RHEL-2423.patch
|
|
into glibc-2.33 by mikhailnov
|
|
Original author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
|
---
|
|
sysdeps/posix/getaddrinfo.c | 21 +++++++++++++++++----
|
|
1 file changed, 17 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
|
|
index 92d2a1c284..2e26a98050 100644
|
|
--- a/sysdeps/posix/getaddrinfo.c
|
|
+++ b/sysdeps/posix/getaddrinfo.c
|
|
@@ -232,7 +232,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
|
}
|
|
array[i].next = array + i + 1;
|
|
}
|
|
- array[0].name = h->h_name;
|
|
array[count - 1].next = NULL;
|
|
|
|
*result = array;
|
|
@@ -283,6 +282,18 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
|
} \
|
|
*pat = addrmem; \
|
|
\
|
|
+ /* Store h_name so that it survives accidental deallocation when \
|
|
+ gethosts is called again and tmpbuf gets reallocated. */ \
|
|
+ if (h_name == NULL && th.h_name != NULL) \
|
|
+ { \
|
|
+ h_name = __strdup (th.h_name); \
|
|
+ if (h_name == NULL) \
|
|
+ { \
|
|
+ __resolv_context_put (res_ctx); \
|
|
+ result = -EAI_SYSTEM; \
|
|
+ goto free_and_return; \
|
|
+ } \
|
|
+ } \
|
|
if (localcanon != NULL && canon == NULL) \
|
|
{ \
|
|
canonbuf = __strdup (localcanon); \
|
|
@@ -307,14 +318,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
|
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),
|
|
+ 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. */
|
|
@@ -333,6 +344,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
struct gaih_addrtuple *at = NULL;
|
|
bool got_ipv6 = false;
|
|
const char *canon = NULL;
|
|
+ char *h_name = NULL;
|
|
const char *orig_name = name;
|
|
|
|
/* Reserve stack memory for the scratch buffer in the getaddrinfo
|
|
@@ -860,7 +872,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);
|
|
+ canonbuf = getcanonname (nip, h_name, name);
|
|
if (canonbuf == NULL)
|
|
{
|
|
__resolv_context_put (res_ctx);
|
|
@@ -1102,6 +1114,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
free ((char *) name);
|
|
free (addrmem);
|
|
free (canonbuf);
|
|
+ free (h_name);
|
|
|
|
return result;
|
|
}
|
|
--
|
|
2.40.1
|
|
|