[glibc/azanella/aarch64-memtag] aarch64: Add support for DT_AARCH64_MEMTAG_HEAP with USE_MTAG

Adhemerval Zanella via Glibc-cvs <[email protected]>
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=fcadc6dacc3e22cfdb14a98faa03a001e9d8d7a5

commit fcadc6dacc3e22cfdb14a98faa03a001e9d8d7a5
Author: Adhemerval Zanella <[email protected]>
Date:   Wed Apr 1 17:39:15 2026 -0300

    aarch64: Add support for DT_AARCH64_MEMTAG_HEAP with USE_MTAG
    
    This patch extends the AArch64 Memtag ABI Extension support in the
    dynamic linker by processing the DT_AARCH64_MEMTAG_HEAP dynamic tag.
    This tag enables Memory Tagging Extension (MTE) protections for the
    libc heap allocator.
    
    The DT_AARCH64_MEMTAG_HEAP is only honored if glibc is configured with
    --enable-memory-tagging (USE_MTAG).  If the ELF tag requests heap
    tagging but glibc lacks USE_MTAG support, the dynamic linker will emit
    a fatal error.
    
    The glibc.mem.tagging tunable behavior is updated to correctly mask or
    enable MTE_HEAP, and similar to stack tagging the tunable has precedence
    over the dynamic tag.
    
    If a shared object requiring MTE heap tagging is loaded via `dlopen`
    it will fail safely with an error if MTE support was not initialized
    at process startup.
    
    The patch adds a configure-time check to verify if the linker supports
    the '-z memtag-heap' option (it is used to enable the heap tests);

Diff:
---
 INSTALL                                            | 14 ++---
 NEWS                                               |  7 ++-
 manual/install.texi                                | 25 ++++----
 sysdeps/aarch64/configure                          | 37 ++++++++++++
 sysdeps/aarch64/configure.ac                       |  7 +++
 sysdeps/aarch64/dl-mte.c                           | 57 ++++++++++++------
 sysdeps/unix/sysv/linux/aarch64/Makefile           | 51 +++++++++++++++-
 .../linux/aarch64/tst-memtag-dlopen-skeleton.c     | 48 +++++++++++++++
 .../sysv/linux/aarch64/tst-memtag-heap-async.c     |  1 +
 .../sysv/linux/aarch64/tst-memtag-heap-disable.c   | 38 ++++++++++++
 .../sysv/linux/aarch64/tst-memtag-heap-dlopen.c    |  3 +
 .../sysv/linux/aarch64/tst-memtag-heap-skeleton.c  | 70 ++++++++++++++++++++++
 .../unix/sysv/linux/aarch64/tst-memtag-heap-sync.c |  1 +
 sysdeps/unix/sysv/linux/aarch64/tst-memtag-mod3.c  |  1 +
 .../sysv/linux/aarch64/tst-memtag-stack-dlopen.c   | 48 +--------------
 .../sysv/linux/aarch64/tst-memtag-test-skeleton.c  | 20 +------
 16 files changed, 324 insertions(+), 104 deletions(-)

diff --git a/INSTALL b/INSTALL
index 2c264c0b96..0a53ffabc9 100644
--- a/INSTALL
+++ b/INSTALL
@@ -301,15 +301,15 @@ passed to 'configure'.  For example:
 
 '--enable-aarch64-memtag-abi'
     Enable initial support for the AArch64 Memory Tagging Extension (MTE) ABI.
-    The option implements stack tagging (DT_AARCH64_MEMTAG_STACK) and MTE
-    execution mode configuration (DT_AARCH64_MEMTAG_MODE) as defined in the
-    Memtag ABI Extension for ELF64.
+    The option implements stack tagging (DT_AARCH64_MEMTAG_STACK), MTE
+    execution mode configuration (DT_AARCH64_MEMTAG_MODE), and heap tagging
+    (DT_AARCH64_MEMTAG_HEAP) as defined in the Memtag ABI Extension for ELF64.
 
-    Unsupported options (DT_AARCH64_MEMTAG_HEAP and DT_AARCH64_MEMTAG_GLOBALS)
-    triggers either startup failure or dlopen errors.
+    Unsupported options (DT_AARCH64_MEMTAG_GLOBALS) triggers either startup
+    failure or dlopen errors.
 
-    If `--enable-memory-tagging` is also uses, the `glibc.mem.tagging` tunable
-    takes precedence.
+    The heap tagging requires `--enable-memory-tagging`, and the
+    `glibc.mem.tagging` tunable takes precedence.
 
     This option is disabled by default and only support on aarch64.
 
diff --git a/NEWS b/NEWS
index ea9fc1af1f..228b3512d5 100644
--- a/NEWS
+++ b/NEWS
@@ -17,9 +17,10 @@ Major new features:
   improvements in performance.
 
 * On AArch64 now has initial support for the Memtag ABI Extension for ELF64,
-  specifically handling stack tagging (DT_AARCH64_MEMTAG_STACK) and execution
-  mode configuration (DT_AARCH64_MEMTAG_MODE).  This can be enabled using thw
-  new --enable-aarch64-memtag-abi configure option.
+  specifically handling stack tagging (DT_AARCH64_MEMTAG_STACK), execution
+  mode configuration (DT_AARCH64_MEMTAG_MODE), and head tagging
+  (DT_AARCH64_MEMTAG_HEAP).  This can be enabled using thw new
+  --enable-aarch64-memtag-abi configure option.
 
 Deprecated and removed features, and other changes affecting compatibility:
 
diff --git a/manual/install.texi b/manual/install.texi
index 99a0023664..32110d855f 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -331,18 +331,19 @@ Default is to disable SFrame support.
 
 @item --enable-aarch64-memtag-abi
 Enable initial support for the AArch64 Memory Tagging Extension (MTE) ABI.
-The option implements stack tagging (DT_AARCH64_MEMTAG_STACK) and MTE
-execution mode configuration (DT_AARCH64_MEMTAG_MODE) as defined in the
-Memtag ABI Extension for ELF64.
-
-Unsupported options (DT_AARCH64_MEMTAG_HEAP and DT_AARCH64_MEMTAG_GLOBALS)
-triggers either startup failure or dlopen errors.  If the execution mode
-is not specified, the system defaults to asynchronous mode.
-
-If @option{--enable-memory-tagging} is also uses, the @code{glibc.mem.tagging}
-tunable takes precedence.  The tunable can override the MTE mode requested by
-the MEMTAG ABI (e.g., forcing synchronous mode or deferring to the
-system-preferred auto mode) and can independently enable heap tagging.
+The option implements stack tagging (DT_AARCH64_MEMTAG_STACK), MTE
+execution mode configuration (DT_AARCH64_MEMTAG_MODE), and heap tagging
+(DT_AARCH64_MEMTAG_HEAP) as defined in the Memtag ABI Extension for ELF64.
+
+Unsupported options (DT_AARCH64_MEMTAG_GLOBALS) triggers either startup
+failure or dlopen errors.  If the execution mode is not specified, the
+system defaults to asynchronous mode.
+
+The heap tagging requires @option{--enable-memory-tagging}, and the
+@code{glibc.mem.tagging} tunable takes precedence.  The tunable can
+override the MTE mode requested by the MEMTAG ABI (e.g., forcing
+synchronous mode or deferring to the system-preferred auto mode) and
+can independently enable heap tagging.
 
 If the main executable does not enable the MTE stack at startup, any
 subsequent attempts to @code{dlopen} a shared object that requires MTE
diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure
index 8577ee69a7..02be02da43 100755
--- a/sysdeps/aarch64/configure
+++ b/sysdeps/aarch64/configure
@@ -587,3 +587,40 @@ else
 have-test-memtag-stack = no"
 fi
 
+# Check if linker supports Memtag Heap support
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z memtag-heap" >&5
+printf %s "checking for linker that supports -z memtag-heap... " >&6; }
+libc_linker_feature=no
+cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
+		  -Wl,--fatal-warnings -Wl,-z,memtag-heap -nostdlib -nostartfiles
+		  -fPIC -shared -o conftest.so conftest.c
+		  1>&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+then
+  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,--fatal-warnings -Wl,-z,memtag-heap -nostdlib \
+      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
+      | grep "warning: -z memtag-heap ignored" > /dev/null 2>&1; then
+    true
+  else
+    libc_linker_feature=yes
+  fi
+fi
+rm -f conftest*
+if test $libc_linker_feature = yes; then
+  libc_cv_ld_memtag_heap=yes
+else
+  libc_cv_ld_memtag_heap=no
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
+printf "%s\n" "$libc_linker_feature" >&6; }
+config_vars="$config_vars
+have-test-memtag-heap = $libc_cv_ld_memtag_heap"
+
diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac
index 7d6e8c0815..38de7642cd 100644
--- a/sysdeps/aarch64/configure.ac
+++ b/sysdeps/aarch64/configure.ac
@@ -130,3 +130,10 @@ then
 else
    LIBC_CONFIG_VAR([have-test-memtag-stack], [no])
 fi
+
+# Check if linker supports Memtag Heap support
+LIBC_LINKER_FEATURE(
+  [-z memtag-heap], [-Wl,--fatal-warnings -Wl,-z,memtag-heap],
+  [libc_cv_ld_memtag_heap=yes], [libc_cv_ld_memtag_heap=no]
+)
+LIBC_CONFIG_VAR([have-test-memtag-heap], [$libc_cv_ld_memtag_heap])
diff --git a/sysdeps/aarch64/dl-mte.c b/sysdeps/aarch64/dl-mte.c
index cb8ec64d88..fbfa83e49c 100644
--- a/sysdeps/aarch64/dl-mte.c
+++ b/sysdeps/aarch64/dl-mte.c
@@ -32,22 +32,39 @@
 
 # define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
 
+typedef enum
+{
+  MTE_ERROR_SUPPORT,
+  MTE_ERROR_STACK,
+  MTE_ERROR_HEAP,
+  MTE_ERROR_GLOBALS,
+} mte_error_mode;
+
 static void
-fail (const struct link_map *l, const char *program, const char *mode)
+fail (const struct link_map *l, const char *program, mte_error_mode mode)
 {
   if (program != NULL)
     {
+      const char *modestr;
+      switch (mode)
+	{
+	case MTE_ERROR_STACK: modestr = "stack"; break;
+	case MTE_ERROR_HEAP: modestr = "heap"; break;
+	case MTE_ERROR_GLOBALS: modestr = "global"; break;
+	default: __builtin_unreachable ();
+	}
+
       if (program[0] != '\0' && l->l_name[0] != '\0')
-	_dl_fatal_printf ("%s: %s: MTE protection %s is not supported\n",
-			  program, l->l_name, mode);
+	_dl_fatal_printf ("%s: %s: MTE %s protection is not supported\n",
+			  program, l->l_name, modestr);
       if (program[0] != '\0')
-        _dl_fatal_printf ("%s: MTE protection %s is not supported\n",
-			  program, mode);
-      _dl_fatal_printf ("error: MTE protection %s is not supported\n",
-			mode);
+        _dl_fatal_printf ("%s: MTE %s protection is not supported\n",
+			  program, modestr);
+      _dl_fatal_printf ("error: MTE %s protection is not supported\n",
+			modestr);
   }
   else
-    _dl_signal_error (0, l->l_name, "dlopen", "MTE is not enabled");
+    _dl_signal_error (0, l->l_name, "dlopen", "MTE support is not enabled");
 }
 
 static void
@@ -111,9 +128,13 @@ static void check_mte (const struct link_map *l, const char *program)
   if (requires_mte_stack (l))
     GL(dl_aarch64_mte) |= MTE_STACK;
   if (requires_mte_heap (l))
-    fail (l, program, "heap");
+# ifdef USE_MTAG
+    GL(dl_aarch64_mte) |= MTE_HEAP;
+# else
+    fail (l, program, MTE_ERROR_HEAP);
+# endif
   if (requires_mte_globals (l))
-    fail (l, program, "globals");
+    fail (l, program, MTE_ERROR_GLOBALS);
 }
 #endif
 
@@ -133,8 +154,8 @@ static inline bool enable_mte_stack (void)
 
 static inline bool enable_mte_heap (void)
 {
-#ifdef USE_MTAB
-  return GL(dl_aarch64_mte) & MTE_HEAD;
+#if defined USE_MTAB || defined USE_AARCH64_MEMTAG_ABI
+  return GL(dl_aarch64_mte) & MTE_HEAP;
 #else
   return false;
 #endif
@@ -155,13 +176,13 @@ _dl_mte_check (struct link_map *l, const char *program)
   for (unsigned int i = 0; i < l->l_searchlist.r_nlist; i++)
     check_mte (l->l_searchlist.r_list[i], program);
 
-  /* For dlopen, if program has not enabled MTE stack at the startup, signal
-     that the module can not be loaded.  */
-  if (enable_mte_stack () && program == NULL)
+  /* For dlopen, if program has not enabled MTE at the startup, signal that
+     the module can not be loaded.  */
+  if ((enable_mte_stack () || enable_mte_heap()) && program == NULL)
     {
-      GL(dl_aarch64_mte) &= ~MTE_STACK;
+      GL(dl_aarch64_mte) &= ~(MTE_STACK | MTE_HEAP);
 
-      fail (l, program, "stack");
+      fail (l, program, MTE_ERROR_SUPPORT);
     }
 #endif
 }
@@ -188,6 +209,8 @@ _dl_mte_init (void)
 					      NULL);
       if (mte_tunable & 0x1)
 	GL(dl_aarch64_mte) |= MTE_HEAP;
+      else
+	GL(dl_aarch64_mte) &= ~MTE_HEAP;
       if (mte_tunable & 0x2)
 	{
 	  GL(dl_aarch64_mte) &= ~MTE_MODE_ASYNC;
diff --git a/sysdeps/unix/sysv/linux/aarch64/Makefile b/sysdeps/unix/sysv/linux/aarch64/Makefile
index 1a686e3994..e928f5b90b 100644
--- a/sysdeps/unix/sysv/linux/aarch64/Makefile
+++ b/sysdeps/unix/sysv/linux/aarch64/Makefile
@@ -381,10 +381,26 @@ tests-special += \
   $(objpfx)tst-memtag-stack-sync-tunable.out \
   # tests-special
 
+ifeq ($(have-test-memtag-heap),yes)
+tests += \
+  tst-memtag-heap-async \
+  tst-memtag-heap-disable \
+  tst-memtag-heap-dlopen \
+  tst-memtag-heap-sync \
+  # tests
+
+tests-special += \
+  $(objpfx)tst-memtag-heap-sync.out \
+  $(objpfx)tst-memtag-heap-async.out \
+  $(objpfx)tst-memtag-heap-disable.out \
+  # tests
+endif
+
 modules-names += \
   tst-memtag-mod1 \
   tst-memtag-mod2 \
-  # modules-names
+  tst-memtag-mod3 \
+ # modules-names
 
 # Disable stack protector for stack tagging tests.  Some GCC versions have a
 # a bug where the stack frame untagging at the function epiloge is done before
@@ -419,6 +435,39 @@ $(objpfx)tst-memtag-stack-sync-tunable.out: $(objpfx)tst-memtag-stack-async
 		$(test-program-cmd-after-env) sync $< \
 		> $@ 2>&1; echo "status: $$?" >> $@; \
 	$(evaluate-test)
+
+LDFLAGS-tst-memtag-heap-sync += -Wl,-z,memtag-heap -Wl,-z,memtag-mode=sync
+$(objpfx)tst-memtag-heap-sync.out: $(objpfx)tst-memtag-heap-sync
+	$(test-program-cmd-before-env) \
+		$(run-program-env) \
+		$(test-program-cmd-after-env) $< \
+		> $@ 2>&1; echo "status: $$?" >> $@; \
+	grep -q 'MTE heap protection is not supported' $@ \
+	|| grep -q '^status: 79$$' $@; \
+	$(evaluate-test)
+
+CFLAGS-tst-memtag-heap-async.c += -DMEMTAG_MODE_ASYNC
+LDFLAGS-tst-memtag-heap-async += -Wl,-z,memtag-heap -Wl,-z,memtag-mode=async
+$(objpfx)tst-memtag-heap-async.out: $(objpfx)tst-memtag-heap-async
+	$(test-program-cmd-before-env) \
+		$(run-program-env) \
+		$(test-program-cmd-after-env) $< \
+		> $@ 2>&1; echo "status: $$?" >> $@; \
+	grep -q 'MTE heap protection is not supported' $@ \
+	|| grep -q '^status: 79$$' $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-memtag-heap-dlopen.out: $(objpfx)tst-memtag-mod3.so
+LDFLAGS-tst-memtag-mod3.so += -Wl,-z,memtag-heap
+
+LDFLAGS-tst-memtag-heap-disable += -Wl,-z,memtag-heap
+$(objpfx)tst-memtag-heap-disable.out: $(objpfx)tst-memtag-heap-disable
+	$(test-program-cmd-before-env) \
+		$(run-program-env) \
+		GLIBC_TUNABLES=glibc.mem.tagging=0 \
+		$(test-program-cmd-after-env) $< \
+		> $@ 2>&1; echo "status: $$?" >> $@; \
+	$(evaluate-test)
 endif # ifeq ($(aarch64-memtag-abi)$(have-test-memtag-stack),yesyes)
 
 endif # ifeq ($(subdir),misc)
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-dlopen-skeleton.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-dlopen-skeleton.c
new file mode 100644
index 0000000000..161cca911b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-dlopen-skeleton.c
@@ -0,0 +1,48 @@
+/* Tests for MEMTAG dleopn support.
+   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 <stdio.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <support/check.h>
+
+#include "tst-mte-helper.h"
+
+static int
+do_test (void)
+{
+  /* Not strickly required to check for MTE capability.  */
+  if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
+    FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
+
+  TEST_VERIFY_EXIT (!mte_enable ());
+
+  /* Verify that if MTE is not enabled at startup, trying to load a DSO that
+     requires MTE should fail.  */
+  void *h = dlopen (MEMTAG_MOD_NAME, RTLD_NOW);
+  TEST_VERIFY (h == NULL);
+  const char *message = dlerror ();
+  printf ("debug: %s\n", message);
+  if (strstr (message, DLERROR_MSG) == 0)
+    FAIL_EXIT1 ("invalid dlopen error message");
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-async.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-async.c
new file mode 100644
index 0000000000..23059dbb2b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-async.c
@@ -0,0 +1 @@
+#include "tst-memtag-heap-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-disable.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-disable.c
new file mode 100644
index 0000000000..e58e9d1cf4
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-disable.c
@@ -0,0 +1,38 @@
+/* Tests for MEMTAG heap support.
+   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 <libc-diag.h>
+#include <sys/auxv.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+#include "tst-mte-helper.h"
+
+static int
+do_test (void)
+{
+  if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
+    FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
+
+  TEST_VERIFY_EXIT (!mte_enable ());
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-dlopen.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-dlopen.c
new file mode 100644
index 0000000000..a705c55250
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-dlopen.c
@@ -0,0 +1,3 @@
+#define MEMTAG_MOD_NAME "tst-memtag-mod3.so"
+#define DLERROR_MSG     "MTE support is not enabled"
+#include "tst-memtag-dlopen-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-skeleton.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-skeleton.c
new file mode 100644
index 0000000000..ab8753e877
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-skeleton.c
@@ -0,0 +1,70 @@
+/* Tests for MEMTAG heap support.
+   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 <libc-diag.h>
+#include <sys/auxv.h>
+
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/xsignal.h>
+#include <support/support.h>
+
+#include "tst-mte-helper.h"
+
+static void
+__attribute_noinline__
+__attribute_optimization_barrier__
+trigger_mte_fault (void)
+{
+  DIAG_PUSH_NEEDS_COMMENT;
+  DIAG_IGNORE_NEEDS_COMMENT_GCC (16, "-Warray-bounds");
+
+  sigset_t mask;
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGSEGV);
+
+  volatile char *ptr = xmalloc (MTE_GRANULE_SIZE);
+  /* Access memory strictly outside the allocated chunk.  Adding
+     MTE_GRANULE_SIZE bytes pushes us into the next granule, which
+     will have a different tag.  */
+  ptr[16] = 0xFF;
+}
+
+static int
+do_test (void)
+{
+  if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
+    FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
+
+  TEST_VERIFY_EXIT (mte_enable ());
+  TEST_VERIFY_EXIT (mte_mode () ==
+#ifdef MEMTAG_MODE_ASYNC
+		    PR_MTE_TCF_ASYNC
+#else
+		    PR_MTE_TCF_SYNC
+#endif
+		    );
+
+  install_sigsegv_handler ();
+
+  trigger_mte_fault ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-sync.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-sync.c
new file mode 100644
index 0000000000..23059dbb2b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-heap-sync.c
@@ -0,0 +1 @@
+#include "tst-memtag-heap-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-mod3.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-mod3.c
new file mode 100644
index 0000000000..07f2a2d7ba
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-mod3.c
@@ -0,0 +1 @@
+int foo (void) { return 0; }
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-stack-dlopen.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-stack-dlopen.c
index ad103356e9..bc4c26191a 100644
--- a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-stack-dlopen.c
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-stack-dlopen.c
@@ -1,45 +1,3 @@
-/* Tests for MEMTAG support.
-   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 <dlfcn.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include <support/check.h>
-
-#include "tst-mte-helper.h"
-
-static int
-do_test (void)
-{
-  if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
-    FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
-
-  TEST_VERIFY_EXIT (!mte_enable ());
-
-  /* Verify that if MTE is not enabled at startup, trying to load a DSO that
-     requires MTE should fail.  */
-  void *h = dlopen ("tst-memtag-mod2.so", RTLD_NOW);
-  TEST_VERIFY (h == NULL);
-  const char *message = dlerror ();
-  if (strstr (message, "MTE is not enabled") == 0)
-    FAIL_EXIT1 ("invalid dlopen error message");
-
-  return 0;
-}
-
-#include <support/test-driver.c>
+#define MEMTAG_MOD_NAME   "tst-memtag-mod2.so"
+#define DLERROR_MSG       "MTE support is not enabled"
+#include "tst-memtag-dlopen-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-test-skeleton.c b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-test-skeleton.c
index 52e4f9fc31..29192b305f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/tst-memtag-test-skeleton.c
+++ b/sysdeps/unix/sysv/linux/aarch64/tst-memtag-test-skeleton.c
@@ -19,22 +19,11 @@
 #include <stdlib.h>
 #include <libc-diag.h>
 #include <support/check.h>
-#include <support/xsignal.h>
 #include <support/xthread.h>
 #include <unistd.h>
 
 #include "tst-mte-helper.h"
 
-static void
-sigsegv_handler (int signum, siginfo_t *si, void *context)
-{
-  if (si->si_signo == SIGSEGV
-      && (si->si_code == SEGV_MTESERR || si->si_code == SEGV_MTEAERR))
-    _exit (EXIT_MTESERR);
-  else
-    _exit (EXIT_FAILURE);
-}
-
 /* Prevent inlining so the stack frame is definitively constructed to
    trigger a stack frame, and optimization to avoid compiler optimize
    away the invalid stack operation.  */
@@ -64,14 +53,7 @@ run_mte_test (void *closure)
 {
   test_mode mode = (test_mode)(uintptr_t)closure;
 
-  {
-    struct sigaction sa = {
-      .sa_sigaction = sigsegv_handler,
-      .sa_flags = SA_NODEFER | SA_SIGINFO,
-    };
-    sigemptyset (&sa.sa_mask);
-    xsigaction (SIGSEGV, &sa, NULL);
-  }
+  install_sigsegv_handler ();
 
   if (mode == TEST_MAIN)
     trigger_mte_fault (NULL);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.