[glibc] support: add support_ptr_after_free
Yury Khrustalev via Glibc-cvs <[email protected]> Fri, 8 May 2026 08:54:29 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=37ee8868dc4ba4941030881c3050e04d0435670d commit 37ee8868dc4ba4941030881c3050e04d0435670d Author: Yury Khrustalev <[email protected]> Date: Wed May 6 13:29:56 2026 +0100 support: add support_ptr_after_free Some tests use pointers after the associated memory has been freed. On targets that support memory tagging, using such pointers even for test purposes might be impossible. To work around this, we add new function that would allow to clear a pointer in a target-specific way. We modify 3 relevant malloc tests: tst-malloc-backtrace, tst-tcfree3, and tst-safe-linking. Reviewed-by: Wilco Dijkstra <[email protected]> Diff: --- malloc/tst-malloc-backtrace.c | 6 +++- malloc/tst-memalign-2.c | 2 +- malloc/tst-memalign-3.c | 2 +- malloc/tst-realloc.c | 2 +- malloc/tst-safe-linking.c | 6 +++- malloc/tst-tcfree3.c | 6 ++++ support/{address-diff.h => test-pointer.h} | 12 +++++--- sysdeps/aarch64/Makefile | 1 + sysdeps/aarch64/support-address-diff.c | 4 +-- sysdeps/aarch64/support-use-after-free.c | 47 ++++++++++++++++++++++++++++++ sysdeps/generic/Makefile | 1 + sysdeps/generic/support-address-diff.c | 4 +-- sysdeps/generic/support-use-after-free.c | 24 +++++++++++++++ 13 files changed, 104 insertions(+), 13 deletions(-) diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c index aa2e5e37cb..0d89cfd9b2 100644 --- a/malloc/tst-malloc-backtrace.c +++ b/malloc/tst-malloc-backtrace.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <support/support.h> +#include <support/test-pointer.h> #include <libc-diag.h> #include "tst-malloc-aux.h" @@ -37,7 +38,10 @@ call_free (void *ptr) by a prior call to free(). */ DIAG_IGNORE_NEEDS_COMMENT (12, "-Wuse-after-free"); #endif - *(size_t *)(ptr - sizeof (size_t)) = 1; + /* We attempt to write to the chunk header thus corrupting memory. + If memory tagging is used, we need to make sure that tag in ptr + is cleared. */ + *(size_t *)(support_ptr_after_free (ptr) - sizeof (size_t)) = 1; #if __GNUC_PREREQ (12, 0) DIAG_POP_NEEDS_COMMENT; #endif diff --git a/malloc/tst-memalign-2.c b/malloc/tst-memalign-2.c index 2dd8808236..0d4f37412f 100644 --- a/malloc/tst-memalign-2.c +++ b/malloc/tst-memalign-2.c @@ -23,7 +23,7 @@ #include <unistd.h> #include <array_length.h> #include <libc-pointer-arith.h> -#include <support/address-diff.h> +#include <support/test-pointer.h> #include <support/check.h> #include "tst-malloc-aux.h" diff --git a/malloc/tst-memalign-3.c b/malloc/tst-memalign-3.c index f1b045b095..953d18635b 100644 --- a/malloc/tst-memalign-3.c +++ b/malloc/tst-memalign-3.c @@ -24,7 +24,7 @@ #include <unistd.h> #include <array_length.h> #include <libc-pointer-arith.h> -#include <support/address-diff.h> +#include <support/test-pointer.h> #include <support/check.h> #include <support/xthread.h> #include "tst-malloc-aux.h" diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c index 0e616d3827..4d72ccf5c6 100644 --- a/malloc/tst-realloc.c +++ b/malloc/tst-realloc.c @@ -22,7 +22,7 @@ #include <string.h> #include <libc-diag.h> #include <support/check.h> -#include <support/address-diff.h> +#include <support/test-pointer.h> #include "tst-malloc-aux.h" diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c index f7e0897429..d338a6e1be 100644 --- a/malloc/tst-safe-linking.c +++ b/malloc/tst-safe-linking.c @@ -25,6 +25,7 @@ #include <stdbool.h> #include <support/capture_subprocess.h> #include <support/check.h> +#include <support/test-pointer.h> #include "tst-malloc-aux.h" @@ -93,7 +94,10 @@ test_tcache (void *closure) free (b); free (c); - /* Corrupt the pointer with a random value, and avoid optimizations. */ + /* Corrupt the pointer with a random value, and avoid optimizations. + If memory tagging is used, we need to make sure that tag in ptr + is cleared. */ + c = support_ptr_after_free (c); printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]); memset (c, mask & 0xFF, size); printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]); diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c index 8c0008ef0f..f8875414d4 100644 --- a/malloc/tst-tcfree3.c +++ b/malloc/tst-tcfree3.c @@ -19,6 +19,8 @@ #include <malloc.h> #include <string.h> +#include <support/test-pointer.h> + static int do_test (void) { @@ -36,6 +38,10 @@ do_test (void) free (a); // puts in tcache + /* If memory tagging is used, we need to make sure that tag in ptr + is cleared. */ + a = support_ptr_after_free (a); + /* A is now free and contains the key we use to detect in-tcache. Copy the key to the other chunks. */ memcpy (b, a, 32); diff --git a/support/address-diff.h b/support/test-pointer.h similarity index 77% rename from support/address-diff.h rename to support/test-pointer.h index ef58b9d8a6..f63ebb8e12 100644 --- a/support/address-diff.h +++ b/support/test-pointer.h @@ -1,4 +1,4 @@ -/* Support functions for pointer arithmetic. +/* Support functions for tests that check pointers. Copyright (C) 2026 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -16,12 +16,16 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#ifndef _POINTER_ARITH_H -#define _POINTER_ARITH_H 1 +#ifndef _SUPPORT_TEST_POINTER_H +#define _SUPPORT_TEST_POINTER_H 1 #include <stddef.h> /* Returns difference in bytes between addresses of two pointers. */ ptrdiff_t support_address_diff (const void *lhs, const void *rhs); -#endif /* _POINTER_ARITH_H */ +/* Returns pointer suitable for tests that rely on use-after-free + behaviour. */ +void *support_ptr_after_free (void *ptr); + +#endif /* _SUPPORT_TEST_POINTER_H */ diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile index 802bf40a82..a78622cc35 100644 --- a/sysdeps/aarch64/Makefile +++ b/sysdeps/aarch64/Makefile @@ -111,5 +111,6 @@ endif # malloc directory ifeq ($(subdir),support) libsupport-sysdep_routines += \ support-address-diff \ + support-use-after-free \ # libsupport-sysdep_routines endif diff --git a/sysdeps/aarch64/support-address-diff.c b/sysdeps/aarch64/support-address-diff.c index fd8d3ed920..831b9010bf 100644 --- a/sysdeps/aarch64/support-address-diff.c +++ b/sysdeps/aarch64/support-address-diff.c @@ -1,4 +1,4 @@ -/* Support functions for pointer arithmetic for AArch64. +/* Support functions for pointer arithmetic: aarch64 version. Copyright (C) 2026 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -16,7 +16,7 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#include "address-diff.h" +#include "test-pointer.h" #include <sys/ifunc.h> #include <sys/auxv.h> diff --git a/sysdeps/aarch64/support-use-after-free.c b/sysdeps/aarch64/support-use-after-free.c new file mode 100644 index 0000000000..f941cf6f39 --- /dev/null +++ b/sysdeps/aarch64/support-use-after-free.c @@ -0,0 +1,47 @@ +/* Support functions for testing malloc: aarch64 version. + Copyright (C) 2026 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 "test-pointer.h" + +#include <sys/ifunc.h> +#include <sys/auxv.h> + +/* This version clears bits 59:56 (4 bits) to remove possible + MTE tag from the pointer without trying to access memory + that this pointer points to. */ +static void *ptr_after_free_mte (void *ptr) +{ + return (void *)((uintptr_t)ptr & ~(0xfull << 56ull)); +} + +static void *ptr_after_free_generic (void *ptr) +{ + return ptr; +} + +static void * __attribute__ ((unused)) +ptr_after_free_resolver (unsigned long a0, const unsigned long *a1) +{ + unsigned long hwcap2 = __ifunc_hwcap (_IFUNC_ARG_AT_HWCAP2, a0, a1); + if (hwcap2 & HWCAP2_MTE) + return (void *)ptr_after_free_mte; + return (void *)ptr_after_free_generic; +} + +void *support_ptr_after_free (void *ptr) +__attribute__ ((ifunc ("ptr_after_free_resolver"))); diff --git a/sysdeps/generic/Makefile b/sysdeps/generic/Makefile index 933a77ffd3..e0f7056ad2 100644 --- a/sysdeps/generic/Makefile +++ b/sysdeps/generic/Makefile @@ -57,5 +57,6 @@ endif ifeq ($(subdir),support) libsupport-sysdep_routines += \ support-address-diff \ + support-use-after-free \ # libsupport-sysdep_routines endif diff --git a/sysdeps/generic/support-address-diff.c b/sysdeps/generic/support-address-diff.c index 51b5640acd..69ebf8a8c4 100644 --- a/sysdeps/generic/support-address-diff.c +++ b/sysdeps/generic/support-address-diff.c @@ -1,4 +1,4 @@ -/* Support functions for pointer arithmetic. +/* Support functions for pointer arithmetic: generic version. Copyright (C) 2026 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -16,7 +16,7 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#include "address-diff.h" +#include "test-pointer.h" #include <libc-pointer-arith.h> diff --git a/sysdeps/generic/support-use-after-free.c b/sysdeps/generic/support-use-after-free.c new file mode 100644 index 0000000000..9592e97d91 --- /dev/null +++ b/sysdeps/generic/support-use-after-free.c @@ -0,0 +1,24 @@ +/* Support functions for testing malloc: generic version. + Copyright (C) 2026 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 "test-pointer.h" + +void *support_ptr_after_free (void *ptr) +{ + return ptr; +}