core/glibc/glibc-2.38-1.patch

1913 lines
62 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff --git a/NEWS b/NEWS
index 872bc8907b..f117874e34 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,38 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
+
+Version 2.38.1
+
+Security related changes:
+
+ CVE-2023-4527: If the system is configured in no-aaaa mode via
+ /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address
+ family, and a DNS response is received over TCP that is larger than
+ 2048 bytes, getaddrinfo may potentially disclose stack contents via
+ the returned address data, or crash.
+
+ CVE-2023-4806: When an NSS plugin only implements the
+ _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use
+ memory that was freed during buffer resizing, potentially causing a
+ crash or read or write to arbitrary memory.
+
+ CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when
+ an application calls getaddrinfo for AF_INET6 with AI_CANONNAME,
+ AI_ALL and AI_V4MAPPED flags set.
+
+ CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the
+ environment of a setuid program and NAME is valid, it may result in a
+ buffer overflow, which could be exploited to achieve escalated
+ privileges. This flaw was introduced in glibc 2.34.
+
+The following bugs are resolved with this release:
+
+ [30723] posix_memalign repeatedly scans long bin lists
+ [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with
+ -D_FILE_OFFSET_BITS=64
+ [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527)
+
Version 2.38
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 5b0732590f..ba4d2fdc85 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -25,10 +25,14 @@
static void
call_init (struct link_map *l, int argc, char **argv, char **env)
{
+ /* Do not run constructors for proxy objects. */
+ if (l != l->l_real)
+ return;
+
/* If the object has not been relocated, this is a bug. The
function pointers are invalid in this case. (Executables do not
- need relocation, and neither do proxy objects.) */
- assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
+ need relocation.) */
+ assert (l->l_relocated || l->l_type == lt_executable);
if (l->l_init_called)
/* This object is all done. */
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 62b7332d95..cae67efa0a 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -180,11 +180,7 @@ parse_tunables (char *tunestr, char *valstring)
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
- {
- if (__libc_enable_secure)
- tunestr[off] = '\0';
- return;
- }
+ break;
/* We did not find a valid name-value pair before encountering the
colon. */
@@ -244,9 +240,16 @@ parse_tunables (char *tunestr, char *valstring)
}
}
- if (p[len] != '\0')
- p += len + 1;
+ /* We reached the end while processing the tunable string. */
+ if (p[len] == '\0')
+ break;
+
+ p += len + 1;
}
+
+ /* Terminate tunestr before we leave. */
+ if (__libc_enable_secure)
+ tunestr[off] = '\0';
}
/* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 7dfb0e073a..f0b92c97e7 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -50,6 +50,8 @@ const char *teststrings[] =
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.check=2",
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
":glibc.malloc.garbage=2:glibc.malloc.check=1",
@@ -68,6 +70,8 @@ const char *resultstrings[] =
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "",
"",
"",
"",
@@ -81,11 +85,18 @@ test_child (int off)
{
const char *val = getenv ("GLIBC_TUNABLES");
+ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val);
+ fflush (stdout);
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
+ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n",
+ off, val, resultstrings[off]);
+ else
+ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off);
+
+ fflush (stdout);
return 1;
}
@@ -106,21 +117,26 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
- exit (EXIT_SUCCESS);
+ /* Special return code to make sure that the child executed all the way
+ through. */
+ exit (42);
}
else
{
- int ret = 0;
-
/* Spawn tests. */
for (int i = 0; i < array_length (teststrings); i++)
{
char buf[INT_BUFSIZE_BOUND (int)];
- printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+ printf ("[%d] Spawned test for %s\n", i, teststrings[i]);
snprintf (buf, sizeof (buf), "%d\n", i);
+ fflush (stdout);
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
- exit (1);
+ {
+ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i);
+ support_record_failure ();
+ continue;
+ }
int status = support_capture_subprogram_self_sgid (buf);
@@ -128,9 +144,14 @@ do_test (int argc, char **argv)
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
- ret |= status;
+ if (WEXITSTATUS (status) != 42)
+ {
+ printf (" [%d] child failed with status %d\n", i,
+ WEXITSTATUS (status));
+ support_record_failure ();
+ }
}
- return ret;
+ return 0;
}
}
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index bee898c63c..cf32cf9b44 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -187,7 +187,7 @@ main (int argc, char *argv[])
if (res != __GCONV_OK)
{
- if (errno == EINVAL)
+ if (res == __GCONV_NOCONV || res == __GCONV_NODB)
{
/* Try to be nice with the user and tell her which of the
two encoding names is wrong. This is possible because
diff --git a/include/ifaddrs.h b/include/ifaddrs.h
index 416118f1b3..19a3afb19f 100644
--- a/include/ifaddrs.h
+++ b/include/ifaddrs.h
@@ -34,9 +34,5 @@ extern void __check_native (uint32_t a1_index, int *a1_native,
uint32_t a2_index, int *a2_native)
attribute_hidden;
-#if IS_IN (nscd)
-extern uint32_t __bump_nl_timestamp (void) attribute_hidden;
-#endif
-
# endif /* !_ISOMAC */
#endif /* ifaddrs.h */
diff --git a/include/link.h b/include/link.h
index 1d74feb2bd..69bda3ed17 100644
--- a/include/link.h
+++ b/include/link.h
@@ -278,6 +278,10 @@ struct link_map
/* List of object in order of the init and fini calls. */
struct link_map **l_initfini;
+ /* Linked list of objects in reverse ELF constructor execution
+ order. Head of list is stored in _dl_init_called_list. */
+ struct link_map *l_init_called_next;
+
/* List of the dependencies introduced through symbol binding. */
struct link_map_reldeps
{
diff --git a/inet/check_pf.c b/inet/check_pf.c
index 5310c99121..6d1475920f 100644
--- a/inet/check_pf.c
+++ b/inet/check_pf.c
@@ -60,12 +60,3 @@ __free_in6ai (struct in6addrinfo *in6ai)
{
/* Nothing to do. */
}
-
-
-#if IS_IN (nscd)
-uint32_t
-__bump_nl_timestamp (void)
-{
- return 0;
-}
-#endif
diff --git a/io/Makefile b/io/Makefile
index 6ccc0e8691..8a3c83a3bb 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -192,6 +192,7 @@ tests := \
tst-fchownat \
tst-fcntl \
tst-fcntl-lock \
+ tst-fcntl-lock-lfs \
tst-fstatat \
tst-fts \
tst-fts-lfs \
diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c
new file mode 100644
index 0000000000..f2a909fb02
--- /dev/null
+++ b/io/tst-fcntl-lock-lfs.c
@@ -0,0 +1,2 @@
+#define _FILE_OFFSET_BITS 64
+#include <io/tst-fcntl-lock.c>
diff --git a/libio/vtables.c b/libio/vtables.c
index 1d8ad612e9..34f7e15f1c 100644
--- a/libio/vtables.c
+++ b/libio/vtables.c
@@ -20,6 +20,7 @@
#include <libioP.h>
#include <stdio.h>
#include <ldsodefs.h>
+#include <array_length.h>
#include <pointer_guard.h>
#include <libio-macros.h>
@@ -88,7 +89,7 @@
# pragma weak __wprintf_buffer_as_file_xsputn
#endif
-const struct _IO_jump_t __io_vtables[IO_VTABLES_LEN] attribute_relro =
+const struct _IO_jump_t __io_vtables[] attribute_relro =
{
/* _IO_str_jumps */
[IO_STR_JUMPS] =
@@ -485,6 +486,8 @@ const struct _IO_jump_t __io_vtables[IO_VTABLES_LEN] attribute_relro =
},
#endif
};
+_Static_assert (array_length (__io_vtables) == IO_VTABLES_NUM,
+ "initializer count");
#ifdef SHARED
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e2f1a615a4..d0bbbf3710 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1086,6 +1086,11 @@ typedef struct malloc_chunk* mchunkptr;
static void* _int_malloc(mstate, size_t);
static void _int_free(mstate, mchunkptr, int);
+static void _int_free_merge_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
+static INTERNAL_SIZE_T _int_free_create_chunk (mstate,
+ mchunkptr, INTERNAL_SIZE_T,
+ mchunkptr, INTERNAL_SIZE_T);
+static void _int_free_maybe_consolidate (mstate, INTERNAL_SIZE_T);
static void* _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
INTERNAL_SIZE_T);
static void* _int_memalign(mstate, size_t, size_t);
@@ -4483,12 +4488,6 @@ _int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
- mchunkptr nextchunk; /* next contiguous chunk */
- INTERNAL_SIZE_T nextsize; /* its size */
- int nextinuse; /* true if nextchunk is used */
- INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr fwd; /* misc temp for linking */
size = chunksize (p);
@@ -4637,31 +4636,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
if (!have_lock)
__libc_lock_lock (av->mutex);
- nextchunk = chunk_at_offset(p, size);
-
- /* Lightweight tests: check whether the block is already the
- top block. */
- if (__glibc_unlikely (p == av->top))
- malloc_printerr ("double free or corruption (top)");
- /* Or whether the next chunk is beyond the boundaries of the arena. */
- if (__builtin_expect (contiguous (av)
- && (char *) nextchunk
- >= ((char *) av->top + chunksize(av->top)), 0))
- malloc_printerr ("double free or corruption (out)");
- /* Or whether the block is actually not marked used. */
- if (__glibc_unlikely (!prev_inuse(nextchunk)))
- malloc_printerr ("double free or corruption (!prev)");
-
- nextsize = chunksize(nextchunk);
- if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
- || __builtin_expect (nextsize >= av->system_mem, 0))
- malloc_printerr ("free(): invalid next size (normal)");
+ _int_free_merge_chunk (av, p, size);
- free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
+ if (!have_lock)
+ __libc_lock_unlock (av->mutex);
+ }
+ /*
+ If the chunk was allocated via mmap, release via munmap().
+ */
- /* consolidate backward */
- if (!prev_inuse(p)) {
- prevsize = prev_size (p);
+ else {
+ munmap_chunk (p);
+ }
+}
+
+/* Try to merge chunk P of SIZE bytes with its neighbors. Put the
+ resulting chunk on the appropriate bin list. P must not be on a
+ bin list yet, and it can be in use. */
+static void
+_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
+{
+ mchunkptr nextchunk = chunk_at_offset(p, size);
+
+ /* Lightweight tests: check whether the block is already the
+ top block. */
+ if (__glibc_unlikely (p == av->top))
+ malloc_printerr ("double free or corruption (top)");
+ /* Or whether the next chunk is beyond the boundaries of the arena. */
+ if (__builtin_expect (contiguous (av)
+ && (char *) nextchunk
+ >= ((char *) av->top + chunksize(av->top)), 0))
+ malloc_printerr ("double free or corruption (out)");
+ /* Or whether the block is actually not marked used. */
+ if (__glibc_unlikely (!prev_inuse(nextchunk)))
+ malloc_printerr ("double free or corruption (!prev)");
+
+ INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
+ if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
+ || __builtin_expect (nextsize >= av->system_mem, 0))
+ malloc_printerr ("free(): invalid next size (normal)");
+
+ free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
+
+ /* Consolidate backward. */
+ if (!prev_inuse(p))
+ {
+ INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
@@ -4669,9 +4689,25 @@ _int_free (mstate av, mchunkptr p, int have_lock)
unlink_chunk (av, p);
}
- if (nextchunk != av->top) {
+ /* Write the chunk header, maybe after merging with the following chunk. */
+ size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
+ _int_free_maybe_consolidate (av, size);
+}
+
+/* Create a chunk at P of SIZE bytes, with SIZE potentially increased
+ to cover the immediately following chunk NEXTCHUNK of NEXTSIZE
+ bytes (if NEXTCHUNK is unused). The chunk at P is not actually
+ read and does not have to be initialized. After creation, it is
+ placed on the appropriate bin list. The function returns the size
+ of the new chunk. */
+static INTERNAL_SIZE_T
+_int_free_create_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size,
+ mchunkptr nextchunk, INTERNAL_SIZE_T nextsize)
+{
+ if (nextchunk != av->top)
+ {
/* get and clear inuse bit */
- nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ bool nextinuse = inuse_bit_at_offset (nextchunk, nextsize);
/* consolidate forward */
if (!nextinuse) {
@@ -4686,8 +4722,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
been given one chance to be used in malloc.
*/
- bck = unsorted_chunks(av);
- fwd = bck->fd;
+ mchunkptr bck = unsorted_chunks (av);
+ mchunkptr fwd = bck->fd;
if (__glibc_unlikely (fwd->bk != bck))
malloc_printerr ("free(): corrupted unsorted chunks");
p->fd = fwd;
@@ -4706,61 +4742,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
check_free_chunk(av, p);
}
- /*
- If the chunk borders the current high end of memory,
- consolidate into top
- */
-
- else {
+ else
+ {
+ /* If the chunk borders the current high end of memory,
+ consolidate into top. */
size += nextsize;
set_head(p, size | PREV_INUSE);
av->top = p;
check_chunk(av, p);
}
- /*
- If freeing a large space, consolidate possibly-surrounding
- chunks. Then, if the total unused topmost memory exceeds trim
- threshold, ask malloc_trim to reduce top.
-
- Unless max_fast is 0, we don't know if there are fastbins
- bordering top, so we cannot tell for sure whether threshold
- has been reached unless fastbins are consolidated. But we
- don't want to consolidate on each free. As a compromise,
- consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
- is reached.
- */
+ return size;
+}
- if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
+/* If freeing a large space, consolidate possibly-surrounding
+ chunks. Then, if the total unused topmost memory exceeds trim
+ threshold, ask malloc_trim to reduce top. */
+static void
+_int_free_maybe_consolidate (mstate av, INTERNAL_SIZE_T size)
+{
+ /* Unless max_fast is 0, we don't know if there are fastbins
+ bordering top, so we cannot tell for sure whether threshold has
+ been reached unless fastbins are consolidated. But we don't want
+ to consolidate on each free. As a compromise, consolidation is
+ performed if FASTBIN_CONSOLIDATION_THRESHOLD is reached. */
+ if (size >= FASTBIN_CONSOLIDATION_THRESHOLD)
+ {
if (atomic_load_relaxed (&av->have_fastchunks))
malloc_consolidate(av);
- if (av == &main_arena) {
+ if (av == &main_arena)
+ {
#ifndef MORECORE_CANNOT_TRIM
- if ((unsigned long)(chunksize(av->top)) >=
- (unsigned long)(mp_.trim_threshold))
- systrim(mp_.top_pad, av);
+ if (chunksize (av->top) >= mp_.trim_threshold)
+ systrim (mp_.top_pad, av);
#endif
- } else {
- /* Always try heap_trim(), even if the top chunk is not
- large, because the corresponding heap might go away. */
- heap_info *heap = heap_for_ptr(top(av));
+ }
+ else
+ {
+ /* Always try heap_trim, even if the top chunk is not large,
+ because the corresponding heap might go away. */
+ heap_info *heap = heap_for_ptr (top (av));
- assert(heap->ar_ptr == av);
- heap_trim(heap, mp_.top_pad);
- }
+ assert (heap->ar_ptr == av);
+ heap_trim (heap, mp_.top_pad);
+ }
}
-
- if (!have_lock)
- __libc_lock_unlock (av->mutex);
- }
- /*
- If the chunk was allocated via mmap, release via munmap().
- */
-
- else {
- munmap_chunk (p);
- }
}
/*
@@ -4999,42 +5026,6 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
------------------------------ memalign ------------------------------
*/
-/* Returns 0 if the chunk is not and does not contain the requested
- aligned sub-chunk, else returns the amount of "waste" from
- trimming. NB is the *chunk* byte size, not the user byte
- size. */
-static size_t
-chunk_ok_for_memalign (mchunkptr p, size_t alignment, size_t nb)
-{
- void *m = chunk2mem (p);
- INTERNAL_SIZE_T size = chunksize (p);
- void *aligned_m = m;
-
- if (__glibc_unlikely (misaligned_chunk (p)))
- malloc_printerr ("_int_memalign(): unaligned chunk detected");
-
- aligned_m = PTR_ALIGN_UP (m, alignment);
-
- INTERNAL_SIZE_T front_extra = (intptr_t) aligned_m - (intptr_t) m;
-
- /* We can't trim off the front as it's too small. */
- if (front_extra > 0 && front_extra < MINSIZE)
- return 0;
-
- /* If it's a perfect fit, it's an exception to the return value rule
- (we would return zero waste, which looks like "not usable"), so
- handle it here by returning a small non-zero value instead. */
- if (size == nb && front_extra == 0)
- return 1;
-
- /* If the block we need fits in the chunk, calculate total waste. */
- if (size > nb + front_extra)
- return size - nb;
-
- /* Can't use this chunk. */
- return 0;
-}
-
/* BYTES is user requested bytes, not requested chunksize bytes. */
static void *
_int_memalign (mstate av, size_t alignment, size_t bytes)
@@ -5049,7 +5040,6 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
mchunkptr remainder; /* spare room at end to split off */
unsigned long remainder_size; /* its size */
INTERNAL_SIZE_T size;
- mchunkptr victim;
nb = checked_request2size (bytes);
if (nb == 0)
@@ -5068,129 +5058,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
we don't find anything in those bins, the common malloc code will
scan starting at 2x. */
- /* This will be set if we found a candidate chunk. */
- victim = NULL;
+ /* Call malloc with worst case padding to hit alignment. */
+ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
- /* Fast bins are singly-linked, hard to remove a chunk from the middle
- and unlikely to meet our alignment requirements. We have not done
- any experimentation with searching for aligned fastbins. */
-
- if (av != NULL)
- {
- int first_bin_index;
- int first_largebin_index;
- int last_bin_index;
-
- if (in_smallbin_range (nb))
- first_bin_index = smallbin_index (nb);
- else
- first_bin_index = largebin_index (nb);
+ if (m == 0)
+ return 0; /* propagate failure */
- if (in_smallbin_range (nb * 2))
- last_bin_index = smallbin_index (nb * 2);
- else
- last_bin_index = largebin_index (nb * 2);
-
- first_largebin_index = largebin_index (MIN_LARGE_SIZE);
-
- int victim_index; /* its bin index */
-
- for (victim_index = first_bin_index;
- victim_index < last_bin_index;
- victim_index ++)
- {
- victim = NULL;
-
- if (victim_index < first_largebin_index)
- {
- /* Check small bins. Small bin chunks are doubly-linked despite
- being the same size. */
-
- mchunkptr fwd; /* misc temp for linking */
- mchunkptr bck; /* misc temp for linking */
-
- bck = bin_at (av, victim_index);
- fwd = bck->fd;
- while (fwd != bck)
- {
- if (chunk_ok_for_memalign (fwd, alignment, nb) > 0)
- {
- victim = fwd;
-
- /* Unlink it */
- victim->fd->bk = victim->bk;
- victim->bk->fd = victim->fd;
- break;
- }
-
- fwd = fwd->fd;
- }
- }
- else
- {
- /* Check large bins. */
- mchunkptr fwd; /* misc temp for linking */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr best = NULL;
- size_t best_size = 0;
-
- bck = bin_at (av, victim_index);
- fwd = bck->fd;
-
- while (fwd != bck)
- {
- int extra;
-
- if (chunksize (fwd) < nb)
- break;
- extra = chunk_ok_for_memalign (fwd, alignment, nb);
- if (extra > 0
- && (extra <= best_size || best == NULL))
- {
- best = fwd;
- best_size = extra;
- }
-
- fwd = fwd->fd;
- }
- victim = best;
-
- if (victim != NULL)
- {
- unlink_chunk (av, victim);
- break;
- }
- }
-
- if (victim != NULL)
- break;
- }
- }
-
- /* Strategy: find a spot within that chunk that meets the alignment
- request, and then possibly free the leading and trailing space.
- This strategy is incredibly costly and can lead to external
- fragmentation if header and footer chunks are unused. */
-
- if (victim != NULL)
- {
- p = victim;
- m = chunk2mem (p);
- set_inuse (p);
- if (av != &main_arena)
- set_non_main_arena (p);
- }
- else
- {
- /* Call malloc with worst case padding to hit alignment. */
-
- m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
-
- if (m == 0)
- return 0; /* propagate failure */
-
- p = mem2chunk (m);
- }
+ p = mem2chunk (m);
if ((((unsigned long) (m)) % alignment) != 0) /* misaligned */
{
@@ -5221,7 +5095,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_inuse_bit_at_offset (newp, newsize);
set_head_size (p, leadsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
- _int_free (av, p, 1);
+ _int_free_merge_chunk (av, p, leadsize);
p = newp;
assert (newsize >= nb &&
@@ -5232,15 +5106,27 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
if (!chunk_is_mmapped (p))
{
size = chunksize (p);
- if ((unsigned long) (size) > (unsigned long) (nb + MINSIZE))
+ mchunkptr nextchunk = chunk_at_offset(p, size);
+ INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
+ if (size > nb)
{
remainder_size = size - nb;
- remainder = chunk_at_offset (p, nb);
- set_head (remainder, remainder_size | PREV_INUSE |
- (av != &main_arena ? NON_MAIN_ARENA : 0));
- set_head_size (p, nb);
- _int_free (av, remainder, 1);
- }
+ if (remainder_size >= MINSIZE
+ || nextchunk == av->top
+ || !inuse_bit_at_offset (nextchunk, nextsize))
+ {
+ /* We can only give back the tail if it is larger than
+ MINSIZE, or if the following chunk is unused (top
+ chunk or unused in-heap chunk). Otherwise we would
+ create a chunk that is smaller than MINSIZE. */
+ remainder = chunk_at_offset (p, nb);
+ set_head_size (p, nb);
+ remainder_size = _int_free_create_chunk (av, remainder,
+ remainder_size,
+ nextchunk, nextsize);
+ _int_free_maybe_consolidate (av, remainder_size);
+ }
+ }
}
check_inuse_chunk (av, p);
diff --git a/malloc/tst-memalign-2.c b/malloc/tst-memalign-2.c
index f229283dbf..ecd6fa249e 100644
--- a/malloc/tst-memalign-2.c
+++ b/malloc/tst-memalign-2.c
@@ -86,7 +86,8 @@ do_test (void)
TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
}
- /* Test for non-head tcache hits. */
+ /* Test for non-head tcache hits. This exercises the memalign
+ scanning code to find matching allocations. */
for (i = 0; i < array_length (ptr); ++ i)
{
if (i == 4)
@@ -113,7 +114,9 @@ do_test (void)
free (p);
TEST_VERIFY (count > 0);
- /* Large bins test. */
+ /* Large bins test. This verifies that the over-allocated parts
+ that memalign releases for future allocations can be reused by
+ memalign itself at least in some cases. */
for (i = 0; i < LN; ++ i)
{
diff --git a/manual/job.texi b/manual/job.texi
index 42cb9fb26d..8157f13a1c 100644
--- a/manual/job.texi
+++ b/manual/job.texi
@@ -1133,6 +1133,7 @@ following @code{errno} error conditions are defined for this function:
@table @code
@item ESRCH
There is no process with the given process ID @var{pid}.
+@item EPERM
The calling process and the process specified by @var{pid} are in
different sessions, and the implementation doesn't allow to access the
process group ID of the process with ID @var{pid} from the calling
diff --git a/nscd/Makefile b/nscd/Makefile
index 2a0489f4cf..16b6460ee9 100644
--- a/nscd/Makefile
+++ b/nscd/Makefile
@@ -35,7 +35,7 @@ nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
getsrvbynm_r getsrvbypt_r servicescache \
dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
- xmalloc xstrdup aicache initgrcache gai res_hconf \
+ xmalloc xstrdup aicache initgrcache res_hconf \
netgroupcache cachedumper
ifeq ($(build-nscd)$(have-thread-library),yesyes)
diff --git a/nscd/connections.c b/nscd/connections.c
index a405a44a9b..15693e5090 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -256,6 +256,17 @@ int inotify_fd = -1;
#ifdef HAVE_NETLINK
/* Descriptor for netlink status updates. */
static int nl_status_fd = -1;
+
+static uint32_t
+__bump_nl_timestamp (void)
+{
+ static uint32_t nl_timestamp;
+
+ if (atomic_fetch_add_relaxed (&nl_timestamp, 1) + 1 == 0)
+ atomic_fetch_add_relaxed (&nl_timestamp, 1);
+
+ return nl_timestamp;
+}
#endif
/* Number of times clients had to wait. */
diff --git a/nscd/gai.c b/nscd/gai.c
deleted file mode 100644
index e29f3fe583..0000000000
--- a/nscd/gai.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2004-2023 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <https://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <sys/stat.h>
-
-/* This file uses the getaddrinfo code but it compiles it without NSCD
- support. We just need a few symbol renames. */
-#define __ioctl ioctl
-#define __getsockname getsockname
-#define __socket socket
-#define __recvmsg recvmsg
-#define __bind bind
-#define __sendto sendto
-#define __strchrnul strchrnul
-#define __getline getline
-#define __qsort_r qsort_r
-/* nscd uses 1MB or 2MB thread stacks. */
-#define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
-#define __getifaddrs getifaddrs
-#define __freeifaddrs freeifaddrs
-#undef __fstat64
-#define __fstat64 fstat64
-#undef __stat64
-#define __stat64 stat64
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <getaddrinfo.c>
-
-/* Support code. */
-#include <check_pf.c>
-#include <check_native.c>
-
-/* Some variables normally defined in libc. */
-nss_action_list __nss_hosts_database attribute_hidden;
diff --git a/nss/Makefile b/nss/Makefile
index 06fcdc450f..668ba34b18 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -82,6 +82,7 @@ tests-container := \
tst-nss-test3 \
tst-reload1 \
tst-reload2 \
+ tst-nss-gai-hv2-canonname \
# tests-container
# Tests which need libdl
@@ -145,7 +146,17 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
ifeq ($(build-static-nss),yes)
tests-static += tst-nss-static
endif
-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os
+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \
+ nss_test_gai_hv2_canonname.os
+
+ifeq ($(run-built-tests),yes)
+ifneq (no,$(PERL))
+tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out
+endif
+endif
+
+generated += mtrace-tst-nss-gai-hv2-canonname.out \
+ tst-nss-gai-hv2-canonname.mtrace
include ../Rules
@@ -180,12 +191,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
libof-nss_test1 = extramodules
libof-nss_test2 = extramodules
libof-nss_test_errno = extramodules
+libof-nss_test_gai_hv2_canonname = extramodules
$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
$(build-module)
+$(objpfx)/libnss_test_gai_hv2_canonname.so: \
+ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps)
+ $(build-module)
$(objpfx)nss_test2.os : nss_test1.c
# Use the nss_files suffix for these objects as well.
$(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so
@@ -195,10 +210,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so
$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
$(objpfx)/libnss_test_errno.so
$(make-link)
+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so
+ $(make-link)
$(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \
$(objpfx)/libnss_test1.so$(libnss_files.so-version) \
$(objpfx)/libnss_test2.so$(libnss_files.so-version) \
- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
ifeq (yes,$(have-thread-library))
$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
@@ -207,6 +226,17 @@ endif
$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
$(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so
+tst-nss-gai-hv2-canonname-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \
+ $(objpfx)tst-nss-gai-hv2-canonname.out
+ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \
+ && $(common-objpfx)malloc/mtrace \
+ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \
+ $(evaluate-test)
+
# Disable DT_RUNPATH on NSS tests so that the glibc internal NSS
# functions can load testing NSS modules via DT_RPATH.
LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags
@@ -215,3 +245,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags
LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags
LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags
LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags
diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
new file mode 100644
index 0000000000..4439c83c9f
--- /dev/null
+++ b/nss/nss_test_gai_hv2_canonname.c
@@ -0,0 +1,56 @@
+/* NSS service provider that only provides gethostbyname2_r.
+ 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 <stdlib.h>
+#include <string.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+/* Catch misnamed and functions. */
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname)
+
+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
+ struct hostent *, char *,
+ size_t, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *herrnop)
+{
+ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
+ herrnop);
+}
+
+enum nss_status
+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
+ size_t buflen, char **result,
+ int *errnop, int *h_errnop)
+{
+ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
+ the test. */
+ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
+ || buflen < sizeof (QUERYNAME))
+ abort ();
+
+ strncpy (buffer, name, buflen);
+ *result = buffer;
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
new file mode 100644
index 0000000000..7db53cf09d
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.c
@@ -0,0 +1,66 @@
+/* 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 <mcheck.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)
+{
+ mtrace ();
+
+ __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>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644
index 0000000000..14f2a9cb08
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.h
@@ -0,0 +1 @@
+#define QUERYNAME "test.example.com"
diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
new file mode 100644
index 0000000000..31848b4a28
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
@@ -0,0 +1,2 @@
+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
+su
diff --git a/resolv/Makefile b/resolv/Makefile
index 054b1fa36c..2f99eb3862 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -102,6 +102,7 @@ tests += \
tst-resolv-invalid-cname \
tst-resolv-network \
tst-resolv-noaaaa \
+ tst-resolv-noaaaa-vc \
tst-resolv-nondecimal \
tst-resolv-res_init-multi \
tst-resolv-search \
@@ -293,6 +294,7 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 1d60c51f5e..5d0ab30de6 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -427,7 +427,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
{
n = __res_context_search (ctx, name, C_IN, T_A,
dns_packet_buffer, sizeof (dns_packet_buffer),
- NULL, NULL, NULL, NULL, NULL);
+ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
if (n >= 0)
status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
&abuf, pat, errnop, herrnop, ttlp);
diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c
new file mode 100644
index 0000000000..9f5aebd99f
--- /dev/null
+++ b/resolv/tst-resolv-noaaaa-vc.c
@@ -0,0 +1,129 @@
+/* Test the RES_NOAAAA resolver option with a large response.
+ Copyright (C) 2022-2023 Free Software Foundation, Inc.
+ 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 <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* Used to keep track of the number of queries. */
+static volatile unsigned int queries;
+
+/* If true, add a large TXT record at the start of the answer section. */
+static volatile bool stuff_txt;
+
+static void
+response (const struct resolv_response_context *ctx,
+ struct resolv_response_builder *b,
+ const char *qname, uint16_t qclass, uint16_t qtype)
+{
+ /* If not using TCP, just force its use. */
+ if (!ctx->tcp)
+ {
+ struct resolv_response_flags flags = {.tc = true};
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+ return;
+ }
+
+ /* The test needs to send four queries, the first three are used to
+ grow the NSS buffer via the ERANGE handshake. */
+ ++queries;
+ TEST_VERIFY (queries <= 4);
+
+ /* AAAA queries are supposed to be disabled. */
+ TEST_COMPARE (qtype, T_A);
+ TEST_COMPARE (qclass, C_IN);
+ TEST_COMPARE_STRING (qname, "example.com");
+
+ struct resolv_response_flags flags = {};
+ resolv_response_init (b, flags);
+ resolv_response_add_question (b, qname, qclass, qtype);
+
+ resolv_response_section (b, ns_s_an);
+
+ if (stuff_txt)
+ {
+ resolv_response_open_record (b, qname, qclass, T_TXT, 60);
+ int zero = 0;
+ for (int i = 0; i <= 15000; ++i)
+ resolv_response_add_data (b, &zero, sizeof (zero));
+ resolv_response_close_record (b);
+ }
+
+ for (int i = 0; i < 200; ++i)
+ {
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
+ char ipv4[4] = {192, 0, 2, i + 1};
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+ resolv_response_close_record (b);
+ }
+}
+
+static int
+do_test (void)
+{
+ struct resolv_test *obj = resolv_test_start
+ ((struct resolv_redirect_config)
+ {
+ .response_callback = response
+ });
+
+ _res.options |= RES_NOAAAA;
+
+ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt)
+ {
+ queries = 0;
+ stuff_txt = do_stuff_txt;
+
+ struct addrinfo *ai = NULL;
+ int ret;
+ ret = getaddrinfo ("example.com", "80",
+ &(struct addrinfo)
+ {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ }, &ai);
+
+ char *expected_result;
+ {
+ struct xmemstream mem;
+ xopen_memstream (&mem);
+ for (int i = 0; i < 200; ++i)
+ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1);
+ xfclose_memstream (&mem);
+ expected_result = mem.buffer;
+ }
+
+ check_addrinfo ("example.com", ai, ret, expected_result);
+
+ free (expected_result);
+ freeaddrinfo (ai);
+ }
+
+ resolv_test_end (obj);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-realpath.c b/stdlib/tst-realpath.c
index f325c95a44..3694ecd8af 100644
--- a/stdlib/tst-realpath.c
+++ b/stdlib/tst-realpath.c
@@ -24,6 +24,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
@@ -50,7 +51,11 @@ void dealloc (void *p)
char* alloc (void)
{
- return (char *)malloc (8);
+#ifdef PATH_MAX
+ return (char *)malloc (PATH_MAX);
+#else
+ return (char *)malloc (4096);
+#endif
}
static int
diff --git a/string/tester.c b/string/tester.c
index f7d4bac5a8..824cf315ff 100644
--- a/string/tester.c
+++ b/string/tester.c
@@ -34,6 +34,14 @@
DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
#endif
+/* When building with fortify enabled, GCC < 12 issues a warning on the
+ fortify strncat wrapper might overflow the destination buffer (the
+ failure is tied to -Werror).
+ Triggered by strncat fortify wrapper when it is enabled. */
+#if __GNUC_PREREQ (11, 0)
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
+#endif
+
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
@@ -52,9 +60,6 @@ DIAG_IGNORE_NEEDS_COMMENT (5.0, "-Wmemset-transposed-args");
DIAG_IGNORE_NEEDS_COMMENT (9, "-Wrestrict");
DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
#endif
-#if __GNUC_PREREQ (11, 0)
-DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
-#endif
#define STREQ(a, b) (strcmp((a), (b)) == 0)
diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h
index 81397fb90b..8278c50a84 100644
--- a/sysdeps/generic/unsecvars.h
+++ b/sysdeps/generic/unsecvars.h
@@ -4,7 +4,6 @@
#define UNSECURE_ENVVARS \
"GCONV_PATH\0" \
"GETCONF_DIR\0" \
- "GLIBC_TUNABLES\0" \
"HOSTALIASES\0" \
"LD_AUDIT\0" \
"LD_DEBUG\0" \
diff --git a/sysdeps/i386/i686/memcpy.S b/sysdeps/i386/i686/memcpy.S
index 9b48ec0ea1..b86af4aac9 100644
--- a/sysdeps/i386/i686/memcpy.S
+++ b/sysdeps/i386/i686/memcpy.S
@@ -27,7 +27,7 @@
#define LEN SRC+4
.text
-#if defined PIC && IS_IN (libc)
+#if defined SHARED && IS_IN (libc)
ENTRY_CHK (__memcpy_chk)
movl 12(%esp), %eax
cmpl %eax, 16(%esp)
diff --git a/sysdeps/i386/i686/mempcpy.S b/sysdeps/i386/i686/mempcpy.S
index 26f8501e7d..14d9dd681a 100644
--- a/sysdeps/i386/i686/mempcpy.S
+++ b/sysdeps/i386/i686/mempcpy.S
@@ -27,7 +27,7 @@
#define LEN SRC+4
.text
-#if defined PIC && IS_IN (libc)
+#if defined SHARED && IS_IN (libc)
ENTRY_CHK (__mempcpy_chk)
movl 12(%esp), %eax
cmpl %eax, 16(%esp)
diff --git a/sysdeps/i386/i686/multiarch/memcpy_chk.c b/sysdeps/i386/i686/multiarch/memcpy_chk.c
index ec945dc91f..c3a8aeaf18 100644
--- a/sysdeps/i386/i686/multiarch/memcpy_chk.c
+++ b/sysdeps/i386/i686/multiarch/memcpy_chk.c
@@ -32,4 +32,6 @@ libc_ifunc_redirected (__redirect_memcpy_chk, __memcpy_chk,
__hidden_ver1 (__memcpy_chk, __GI___memcpy_chk, __redirect_memcpy_chk)
__attribute__ ((visibility ("hidden"))) __attribute_copy__ (__memcpy_chk);
# endif
+#else
+# include <debug/memcpy_chk.c>
#endif
diff --git a/sysdeps/i386/i686/multiarch/memmove_chk.c b/sysdeps/i386/i686/multiarch/memmove_chk.c
index 55c7601d5d..070dde083a 100644
--- a/sysdeps/i386/i686/multiarch/memmove_chk.c
+++ b/sysdeps/i386/i686/multiarch/memmove_chk.c
@@ -32,4 +32,6 @@ libc_ifunc_redirected (__redirect_memmove_chk, __memmove_chk,
__hidden_ver1 (__memmove_chk, __GI___memmove_chk, __redirect_memmove_chk)
__attribute__ ((visibility ("hidden"))) __attribute_copy__ (__memmove_chk);
# endif
+#else
+# include <debug/memmove_chk.c>
#endif
diff --git a/sysdeps/i386/i686/multiarch/mempcpy_chk.c b/sysdeps/i386/i686/multiarch/mempcpy_chk.c
index 83569cf9d9..14360f1828 100644
--- a/sysdeps/i386/i686/multiarch/mempcpy_chk.c
+++ b/sysdeps/i386/i686/multiarch/mempcpy_chk.c
@@ -32,4 +32,6 @@ libc_ifunc_redirected (__redirect_mempcpy_chk, __mempcpy_chk,
__hidden_ver1 (__mempcpy_chk, __GI___mempcpy_chk, __redirect_mempcpy_chk)
__attribute__ ((visibility ("hidden"))) __attribute_copy__ (__mempcpy_chk);
# endif
+#else
+# include <debug/mempcpy_chk.c>
#endif
diff --git a/sysdeps/i386/i686/multiarch/memset_chk.c b/sysdeps/i386/i686/multiarch/memset_chk.c
index 1a7503858d..8179ef7c0b 100644
--- a/sysdeps/i386/i686/multiarch/memset_chk.c
+++ b/sysdeps/i386/i686/multiarch/memset_chk.c
@@ -32,4 +32,6 @@ libc_ifunc_redirected (__redirect_memset_chk, __memset_chk,
__hidden_ver1 (__memset_chk, __GI___memset_chk, __redirect_memset_chk)
__attribute__ ((visibility ("hidden"))) __attribute_copy__ (__memset_chk);
# endif
+#else
+# include <debug/memset_chk.c>
#endif
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 0356b622be..13082305d3 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ char *h_name;
bool free_at;
bool got_ipv6;
};
@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res)
if (res->free_at)
free (res->at);
free (res->canon);
+ free (res->h_name);
memset (res, 0, sizeof (*res));
}
@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
- is not copied, and the struct hostent object must not be deallocated
- prematurely. The new addresses are appended to the tuple array in RES. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new
+ addresses are appended to the tuple array in RES. */
static bool
convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
struct hostent *h, struct gaih_result *res)
@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
res->at = array;
res->free_at = true;
+ /* Duplicate h_name because it may get reclaimed when the underlying storage
+ is freed. */
+ if (res->h_name == NULL)
+ {
+ res->h_name = __strdup (h->h_name);
+ if (res->h_name == NULL)
+ return false;
+ }
+
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
array[i].next = array + i + 1;
@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
}
array[i].next = array + i + 1;
}
- array[0].name = h->h_name;
array[count - 1].next = NULL;
return true;
@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
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),
- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
+ 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. */
s = (char *) name;
@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if ((req->ai_flags & AI_CANONNAME) != 0
&& res->canon == NULL)
{
- char *canonbuf = getcanonname (nip, res->at, name);
+ char *canonbuf = getcanonname (nip, res->h_name, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
@@ -1187,9 +1196,7 @@ free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
- if (res.free_at)
- free (res.at);
- free (res.canon);
+ gaih_result_reset (&res);
return result;
}
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index 2b0b8b6368..3aa6a00348 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -66,25 +66,10 @@ static struct cached_data *cache;
__libc_lock_define_initialized (static, lock);
-#if IS_IN (nscd)
-static uint32_t nl_timestamp;
-
-uint32_t
-__bump_nl_timestamp (void)
-{
- if (atomic_fetch_add_relaxed (&nl_timestamp, 1) + 1 == 0)
- atomic_fetch_add_relaxed (&nl_timestamp, 1);
-
- return nl_timestamp;
-}
-#endif
-
static inline uint32_t
get_nl_timestamp (void)
{
-#if IS_IN (nscd)
- return nl_timestamp;
-#elif defined USE_NSCD
+#if defined USE_NSCD
return __nscd_get_nl_timestamp ();
#else
return 0;
diff --git a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
index 51d4a1b082..822c41fceb 100644
--- a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
+++ b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
@@ -52,7 +52,14 @@ xset_thread_area (struct user_desc *u_info)
static void
xmodify_ldt (int func, const void *ptr, unsigned long bytecount)
{
- TEST_VERIFY_EXIT (syscall (SYS_modify_ldt, 1, ptr, bytecount) == 0);
+ long ret = syscall (SYS_modify_ldt, func, ptr, bytecount);
+
+ if (ret == -1)
+ {
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("modify_ldt not supported");
+ FAIL_EXIT1 ("modify_ldt failed (errno=%d)", errno);
+ }
}
static int
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
index f7615a447e..d8a291a331 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
@@ -33,7 +33,7 @@
# define __O_LARGEFILE 0200000
#endif
-#if __WORDSIZE == 64
+#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64
# define F_GETLK 5
# define F_SETLK 6
# define F_SETLKW 7
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index cd4d0351ae..5ddb35c9d9 100644
--- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h
@@ -315,40 +315,206 @@ handle_amd (int name)
{
unsigned int eax;
unsigned int ebx;
- unsigned int ecx;
+ unsigned int ecx = 0;
unsigned int edx;
- unsigned int count = 0x1;
+ unsigned int max_cpuid = 0;
+ unsigned int fn = 0;
/* No level 4 cache (yet). */
if (name > _SC_LEVEL3_CACHE_LINESIZE)
return 0;
- if (name >= _SC_LEVEL3_CACHE_SIZE)
- count = 0x3;
- else if (name >= _SC_LEVEL2_CACHE_SIZE)
- count = 0x2;
- else if (name >= _SC_LEVEL1_DCACHE_SIZE)
- count = 0x0;
+ __cpuid (0x80000000, max_cpuid, ebx, ecx, edx);
+
+ if (max_cpuid >= 0x8000001D)
+ /* Use __cpuid__ '0x8000_001D' to compute cache details. */
+ {
+ unsigned int count = 0x1;
+
+ if (name >= _SC_LEVEL3_CACHE_SIZE)
+ count = 0x3;
+ else if (name >= _SC_LEVEL2_CACHE_SIZE)
+ count = 0x2;
+ else if (name >= _SC_LEVEL1_DCACHE_SIZE)
+ count = 0x0;
+
+ __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx);
+
+ if (ecx != 0)
+ {
+ switch (name)
+ {
+ case _SC_LEVEL1_ICACHE_ASSOC:
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ case _SC_LEVEL2_CACHE_ASSOC:
+ case _SC_LEVEL3_CACHE_ASSOC:
+ return ((ebx >> 22) & 0x3ff) + 1;
+ case _SC_LEVEL1_ICACHE_LINESIZE:
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ case _SC_LEVEL3_CACHE_LINESIZE:
+ return (ebx & 0xfff) + 1;
+ case _SC_LEVEL1_ICACHE_SIZE:
+ case _SC_LEVEL1_DCACHE_SIZE:
+ case _SC_LEVEL2_CACHE_SIZE:
+ case _SC_LEVEL3_CACHE_SIZE:
+ return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1);
+ default:
+ __builtin_unreachable ();
+ }
+ return -1;
+ }
+ }
+
+ /* Legacy cache computation for CPUs prior to Bulldozer family.
+ This is also a fail-safe mechanism for some hypervisors that
+ accidentally configure __cpuid__ '0x8000_001D' to Zero. */
+
+ fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE);
+
+ if (max_cpuid < fn)
+ return 0;
+
+ __cpuid (fn, eax, ebx, ecx, edx);
- __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx);
+ if (name < _SC_LEVEL1_DCACHE_SIZE)
+ {
+ name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE;
+ ecx = edx;
+ }
switch (name)
{
- case _SC_LEVEL1_ICACHE_ASSOC:
- case _SC_LEVEL1_DCACHE_ASSOC:
- case _SC_LEVEL2_CACHE_ASSOC:
+ case _SC_LEVEL1_DCACHE_SIZE:
+ return (ecx >> 14) & 0x3fc00;
+
+ case _SC_LEVEL1_DCACHE_ASSOC:
+ ecx >>= 16;
+ if ((ecx & 0xff) == 0xff)
+ {
+ /* Fully associative. */
+ return (ecx << 2) & 0x3fc00;
+ }
+ return ecx & 0xff;
+
+ case _SC_LEVEL1_DCACHE_LINESIZE:
+ return ecx & 0xff;
+
+ case _SC_LEVEL2_CACHE_SIZE:
+ return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00;
+
+ case _SC_LEVEL2_CACHE_ASSOC:
+ switch ((ecx >> 12) & 0xf)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ return (ecx >> 12) & 0xf;
+ case 6:
+ return 8;
+ case 8:
+ return 16;
+ case 10:
+ return 32;
+ case 11:
+ return 48;
+ case 12:
+ return 64;
+ case 13:
+ return 96;
+ case 14:
+ return 128;
+ case 15:
+ return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff);
+ default:
+ return 0;
+ }
+
+ case _SC_LEVEL2_CACHE_LINESIZE:
+ return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff;
+
+ case _SC_LEVEL3_CACHE_SIZE:
+ {
+ long int total_l3_cache = 0, l3_cache_per_thread = 0;
+ unsigned int threads = 0;
+ const struct cpu_features *cpu_features;
+
+ if ((edx & 0xf000) == 0)
+ return 0;
+
+ total_l3_cache = (edx & 0x3ffc0000) << 1;
+ cpu_features = __get_cpu_features ();
+
+ /* Figure out the number of logical threads that share L3. */
+ if (max_cpuid >= 0x80000008)
+ {
+ /* Get width of APIC ID. */
+ __cpuid (0x80000008, eax, ebx, ecx, edx);
+ threads = (ecx & 0xff) + 1;
+ }
+
+ if (threads == 0)
+ {
+ /* If APIC ID width is not available, use logical
+ processor count. */
+ __cpuid (0x00000001, eax, ebx, ecx, edx);
+ if ((edx & (1 << 28)) != 0)
+ threads = (ebx >> 16) & 0xff;
+ }
+
+ /* Cap usage of highest cache level to the number of
+ supported threads. */
+ if (threads > 0)
+ l3_cache_per_thread = total_l3_cache/threads;
+
+ /* Get shared cache per ccx for Zen architectures. */
+ if (cpu_features->basic.family >= 0x17)
+ {
+ long int l3_cache_per_ccx = 0;
+ /* Get number of threads share the L3 cache in CCX. */
+ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
+ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
+ l3_cache_per_ccx = l3_cache_per_thread * threads_per_ccx;
+ return l3_cache_per_ccx;
+ }
+ else
+ {
+ return l3_cache_per_thread;
+ }
+ }
+
case _SC_LEVEL3_CACHE_ASSOC:
- return ecx ? ((ebx >> 22) & 0x3ff) + 1 : 0;
- case _SC_LEVEL1_ICACHE_LINESIZE:
- case _SC_LEVEL1_DCACHE_LINESIZE:
- case _SC_LEVEL2_CACHE_LINESIZE:
+ switch ((edx >> 12) & 0xf)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ return (edx >> 12) & 0xf;
+ case 6:
+ return 8;
+ case 8:
+ return 16;
+ case 10:
+ return 32;
+ case 11:
+ return 48;
+ case 12:
+ return 64;
+ case 13:
+ return 96;
+ case 14:
+ return 128;
+ case 15:
+ return ((edx & 0x3ffc0000) << 1) / (edx & 0xff);
+ default:
+ return 0;
+ }
+
case _SC_LEVEL3_CACHE_LINESIZE:
- return ecx ? (ebx & 0xfff) + 1 : 0;
- case _SC_LEVEL1_ICACHE_SIZE:
- case _SC_LEVEL1_DCACHE_SIZE:
- case _SC_LEVEL2_CACHE_SIZE:
- case _SC_LEVEL3_CACHE_SIZE:
- return ecx ? (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1): 0;
+ return (edx & 0xf000) == 0 ? 0 : edx & 0xff;
+
default:
__builtin_unreachable ();
}
@@ -604,11 +770,10 @@ get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, u
level. */
threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16)
& 0xff);
-
- /* Get per-thread size of highest level cache. */
- if (shared_per_thread > 0 && threads > 0)
- shared_per_thread /= threads;
}
+ /* Get per-thread size of highest level cache. */
+ if (shared_per_thread > 0 && threads > 0)
+ shared_per_thread /= threads;
}
/* Account for non-inclusive L2 and L3 caches. */
@@ -703,7 +868,6 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
data = handle_amd (_SC_LEVEL1_DCACHE_SIZE);
core = handle_amd (_SC_LEVEL2_CACHE_SIZE);
shared = handle_amd (_SC_LEVEL3_CACHE_SIZE);
- shared_per_thread = shared;
level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE);
level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE);
@@ -716,13 +880,20 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
level3_cache_size = shared;
level3_cache_assoc = handle_amd (_SC_LEVEL3_CACHE_ASSOC);
level3_cache_linesize = handle_amd (_SC_LEVEL3_CACHE_LINESIZE);
+ level4_cache_size = handle_amd (_SC_LEVEL4_CACHE_SIZE);
if (shared <= 0)
- /* No shared L3 cache. All we have is the L2 cache. */
- shared = core;
+ {
+ /* No shared L3 cache. All we have is the L2 cache. */
+ shared = core;
+ }
+ else if (cpu_features->basic.family < 0x17)
+ {
+ /* Account for exclusive L2 and L3 caches. */
+ shared += core;
+ }
- if (shared_per_thread <= 0)
- shared_per_thread = shared;
+ shared_per_thread = shared;
}
cpu_features->level1_icache_size = level1_icache_size;
diff --git a/sysdeps/x86_64/memcpy.S b/sysdeps/x86_64/memcpy.S
index d98500a78a..4922cba657 100644
--- a/sysdeps/x86_64/memcpy.S
+++ b/sysdeps/x86_64/memcpy.S
@@ -1 +1 @@
-/* Implemented in memcpy.S. */
+/* Implemented in memmove.S. */
diff --git a/sysdeps/x86_64/memmove.S b/sysdeps/x86_64/memmove.S
index f0b84e3b52..c3c08165e1 100644
--- a/sysdeps/x86_64/memmove.S
+++ b/sysdeps/x86_64/memmove.S
@@ -46,6 +46,9 @@ weak_alias (__mempcpy, mempcpy)
#ifndef USE_MULTIARCH
libc_hidden_builtin_def (memmove)
+libc_hidden_builtin_def (__memmove_chk)
+libc_hidden_builtin_def (__memcpy_chk)
+libc_hidden_builtin_def (__mempcpy_chk)
# if defined SHARED && IS_IN (libc)
strong_alias (memmove, __memcpy)
libc_hidden_ver (memmove, memcpy)
diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S
index 7c99df36db..c6df24e8de 100644
--- a/sysdeps/x86_64/memset.S
+++ b/sysdeps/x86_64/memset.S
@@ -32,6 +32,7 @@
#include "isa-default-impl.h"
libc_hidden_builtin_def (memset)
+libc_hidden_builtin_def (__memset_chk)
#if IS_IN (libc)
libc_hidden_def (__wmemset)