diff options
author | Siddhesh Poyarekar <siddhesh@sourceware.org> | 2023-09-15 13:51:12 -0400 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@sourceware.org> | 2023-09-15 14:38:28 -0400 |
commit | 973fe93a5675c42798b2161c6f29c01b0e243994 (patch) | |
tree | cc0af798900de7b19816445d0a8157f52d696f30 /nss/tst-nss-gai-hv2-canonname.c | |
parent | 780adf7aeab9308c02d89260df6ffa84dc2289a5 (diff) | |
download | glibc-973fe93a5675c42798b2161c6f29c01b0e243994.tar.gz glibc-973fe93a5675c42798b2161c6f29c01b0e243994.tar.xz glibc-973fe93a5675c42798b2161c6f29c01b0e243994.zip |
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>
Diffstat (limited to 'nss/tst-nss-gai-hv2-canonname.c')
-rw-r--r-- | nss/tst-nss-gai-hv2-canonname.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c new file mode 100644 index 0000000000..d5f10c07d6 --- /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> |