Fix CVE-2023-4806

This commit is contained in:
Mikhail Novosyolov 2023-12-11 19:48:11 +03:00
parent c785123c5e
commit 894fcbf028
2 changed files with 112 additions and 1 deletions

107
CVE-2023-4806.patch Normal file
View file

@ -0,0 +1,107 @@
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

View file

@ -102,7 +102,7 @@ Version: 2.33
#Source0: http://ftp.gnu.org/gnu/glibc/%{oname}-%{version}.tar.xz
# use ./upd.sh to make a tarball and automatically update Release
Source0: glibc-%{commit}.tar.xz
Release: 10.git%{commit_short}.2
Release: 10.git%{commit_short}.3
License: LGPLv2+ and LGPLv2+ with exceptions and GPLv2+
Group: System/Libraries
Url: http://www.gnu.org/software/libc/
@ -190,6 +190,10 @@ Patch1040: https://github.com/FireBurn/glibc/commit/2efa9591e5e8a129e7b73ad0dad3
Patch1051: glibc-2.34-select-i686.patch
# https://sourceware.org/bugzilla/show_bug.cgi?id=30843#c19
# This fix does not introduce CVE-2023-5156
Patch2001: CVE-2023-4806.patch
# do not remove this BR - it helps to bootstrap the generator
BuildRequires: devel-rpm-generators
BuildRequires: autoconf2.5