glibc40/CVE-2023-4806.patch
Mikhail Novosyolov 894fcbf028 Fix CVE-2023-4806
2023-12-11 20:12:29 +03:00

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