support: add support_ptr_after_free

Message ID 20260506133325.3281560-1-yury.khrustalev@arm.com (mailing list archive)
State Committed
Headers
Series support: add support_ptr_after_free |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686

Commit Message

Yury Khrustalev May 6, 2026, 1:33 p.m. UTC
  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.
---
 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     |  2 +-
 sysdeps/aarch64/support-use-after-free.c   | 47 ++++++++++++++++++++++
 sysdeps/generic/Makefile                   |  1 +
 sysdeps/generic/support-address-diff.c     |  2 +-
 sysdeps/generic/support-use-after-free.c   | 24 +++++++++++
 13 files changed, 102 insertions(+), 11 deletions(-)
 rename support/{address-diff.h => test-pointer.h} (77%)
 create mode 100644 sysdeps/aarch64/support-use-after-free.c
 create mode 100644 sysdeps/generic/support-use-after-free.c
  

Comments

Andreas Schwab May 6, 2026, 1:48 p.m. UTC | #1
On Mai 06 2026, Yury Khrustalev wrote:

> diff --git a/sysdeps/aarch64/support-use-after-free.c b/sysdeps/aarch64/support-use-after-free.c
> new file mode 100644
> index 0000000000..eff5ff7c9a
> --- /dev/null
> +++ b/sysdeps/aarch64/support-use-after-free.c
> @@ -0,0 +1,47 @@
> +/* Support functions 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")));
> \ No newline at end of file

Please add the newline.
  
Wilco Dijkstra May 7, 2026, 6:55 p.m. UTC | #2
Hi Yury,

> 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.

OK with the newline fixed as Andreas pointed out.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>

Cheers,
Wilco
  

Patch

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..639d167ad4 100644
--- a/sysdeps/aarch64/support-address-diff.c
+++ b/sysdeps/aarch64/support-address-diff.c
@@ -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..eff5ff7c9a
--- /dev/null
+++ b/sysdeps/aarch64/support-use-after-free.c
@@ -0,0 +1,47 @@ 
+/* Support functions 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")));
\ No newline at end of file
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..fa48d04d95 100644
--- a/sysdeps/generic/support-address-diff.c
+++ b/sysdeps/generic/support-address-diff.c
@@ -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..e7846b16f7
--- /dev/null
+++ b/sysdeps/generic/support-use-after-free.c
@@ -0,0 +1,24 @@ 
+/* Support functions 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;
+}