[glibc] malloc: aarch64: Remove broken memory tagging

Yury Khrustalev via Glibc-cvs <[email protected]> Sun, 31 May 2026 15:40:52 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=70be9819b5eb7ed0050cffb45113332f96f5a55f

commit 70be9819b5eb7ed0050cffb45113332f96f5a55f
Author: Yury Khrustalev <[email protected]>
Date:   Thu May 21 11:51:57 2026 +0100

    malloc: aarch64: Remove broken memory tagging
    
    Remove the --enable-memory-tagging configure option along with
    all associated variables and macros.
    
    Removing the glibc.mem.tagging tunable.
    
    Remove the memory-tagging makefile variable.
    
    Remove the USE_MTAG macro definition and code that is conditionally
    compiled when this macro is defined.
    
    As a result, we change 'mtag_mmap_flags' to 'extra_mmap_prot' that
    is now always defined. Change of the name due to this being used
    as part of PROT options in mmap syscalls rather than part of flags.
    
    Remove 'mtag_enabled' that would become compile-time false. Also
    remove any code that would never be compiled when 'mtag_enabled'
    is false.
    
    Remove AArch64-specific code pertinent to memory tagging, that is
    currently broken, from the core malloc implementation. We keep
    the assembly code, since we are going to need it in the future. to
    preserve Git history.
    
    Reviewed-by: Wilco Dijkstra <[email protected]>

Diff:
---
 INSTALL                                            |  14 --
 config.h.in                                        |   3 -
 config.make.in                                     |   2 -
 configure                                          |  24 ---
 configure.ac                                       |  15 --
 elf/dl-tunables.list                               |   5 -
 malloc/arena.c                                     |  18 +-
 malloc/malloc-check.c                              |  40 ++--
 malloc/malloc.c                                    | 240 ++-------------------
 manual/install.texi                                |  13 --
 manual/tunables.texi                               |  29 ---
 sysdeps/aarch64/Makefile                           |   9 +-
 .../{__mtag_tag_region.S => __mte_tag_region.S}    |   7 +-
 ...g_tag_zero_region.S => __mte_tag_region_zero.S} |   7 +-
 sysdeps/aarch64/{libc-mtag.h => aarch64-mte.h}     |  73 +++----
 sysdeps/aarch64/cpu-features.h                     |   3 +-
 sysdeps/aarch64/dl-diagnostics-cpu.c               |   2 -
 sysdeps/generic/libc-mtag.h                        |  73 -------
 sysdeps/unix/sysv/linux/aarch64/cpu-features.c     |  28 ---
 19 files changed, 78 insertions(+), 527 deletions(-)

diff --git a/INSTALL b/INSTALL
index 4174c9661f..b67da640bd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -154,20 +154,6 @@ passed to 'configure'.  For example:
 
      NOTE: '--enable-cet' is only supported on x86_64 and x32.
 
-'--enable-memory-tagging'
-     Enable memory tagging support if the architecture supports it.
-     When the GNU C Library is built with this option then the resulting
-     library will be able to control the use of tagged memory when
-     hardware support is present by use of the tunable
-     'glibc.mem.tagging'.  This includes the generation of tagged memory
-     when using the 'malloc' APIs.
-
-     At present only AArch64 platforms with MTE provide this
-     functionality, although the library will still operate (without
-     memory tagging) on older versions of the architecture.
-
-     The default is to disable support for memory tagging.
-
 '--disable-profile'
      Don't build libraries with profiling information.  You may want to
      use this option if you don't plan to do profiling.
diff --git a/config.h.in b/config.h.in
index 87befaa9c6..40854de993 100644
--- a/config.h.in
+++ b/config.h.in
@@ -185,9 +185,6 @@
 /* Define if inlined system calls are available.  */
 #undef HAVE_INLINED_SYSCALLS
 
-/* Define if memory tagging support should be enabled.  */
-#undef USE_MTAG
-
 /* Package description.  */
 #undef PKGVERSION
 
diff --git a/config.make.in b/config.make.in
index 856363d0cd..12ccb55e53 100644
--- a/config.make.in
+++ b/config.make.in
@@ -78,8 +78,6 @@ multi-arch = @multi_arch@
 
 mach-interface-list = @mach_interface_list@
 
-memory-tagging = @memory_tagging@
-
 # Configuration options.
 build-shared = @shared@
 build-profile = @profile@
diff --git a/configure b/configure
index 336a93fbef..90c4b4f858 100755
--- a/configure
+++ b/configure
@@ -703,7 +703,6 @@ INSTALL_PROGRAM
 base_machine
 build_pt_chown
 build_nscd
-memory_tagging
 enable_werror
 force_install
 bindnow
@@ -811,7 +810,6 @@ enable_maintainer_mode
 enable_kernel
 enable_werror
 enable_multi_arch
-enable_memory_tagging
 enable_systemtap
 enable_build_nscd
 enable_nscd
@@ -1490,8 +1488,6 @@ Optional Features:
   --disable-werror        do not build with -Werror
   --enable-multi-arch     enable single DSO with optimizations for multiple
                           architectures
-  --enable-memory-tagging enable memory tagging if supported by the
-                          architecture [default=no]
   --enable-systemtap      enable systemtap static probe points [default=no]
   --disable-build-nscd    disable building and installing the nscd daemon
   --disable-nscd          library functions will not contact the nscd daemon
@@ -4690,26 +4686,6 @@ esac
 fi
 
 
-# Check whether --enable-memory-tagging was given.
-if test ${enable_memory_tagging+y}
-then :
-  enableval=$enable_memory_tagging; memory_tagging=$enableval
-else case e in #(
-  e) memory_tagging=no ;;
-esac
-fi
-
-if test "$memory_tagging" = yes; then
-  # Only enable this on architectures that support it.
-  case $host_cpu in
-    aarch64)
-      printf "%s\n" "#define USE_MTAG 1" >>confdefs.h
-
-      ;;
-  esac
-fi
-
-
 # Check whether --enable-systemtap was given.
 if test ${enable_systemtap+y}
 then :
diff --git a/configure.ac b/configure.ac
index e9138a38b7..2a788c13b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -328,21 +328,6 @@ AC_ARG_ENABLE([multi-arch],
 	      [multi_arch=$enableval],
 	      [multi_arch=default])
 
-AC_ARG_ENABLE([memory-tagging],
-	      AS_HELP_STRING([--enable-memory-tagging],
-			     [enable memory tagging if supported by the architecture @<:@default=no@:>@]),
-	      [memory_tagging=$enableval],
-	      [memory_tagging=no])
-if test "$memory_tagging" = yes; then
-  # Only enable this on architectures that support it.
-  case $host_cpu in
-    aarch64)
-      AC_DEFINE(USE_MTAG)
-      ;;
-  esac
-fi
-AC_SUBST(memory_tagging)
-
 AC_ARG_ENABLE([systemtap],
               [AS_HELP_STRING([--enable-systemtap],
 	       [enable systemtap static probe points @<:@default=no@:>@])],
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 1bbf70d36f..111649f145 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -116,11 +116,6 @@ glibc {
   }
 
   mem {
-    tagging {
-      type: INT_32
-      minval: 0
-      maxval: 255
-    }
     decorate_maps {
       type: INT_32
       minval: 0
diff --git a/malloc/arena.c b/malloc/arena.c
index ddde32c712..023cb3ba06 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -252,20 +252,6 @@ __ptmalloc_init (void)
   tcache_key_initialize ();
 #endif
 
-#ifdef USE_MTAG
-  if ((TUNABLE_GET_FULL (glibc, mem, tagging, int32_t, NULL) & 1) != 0)
-    {
-      /* If the tunable says that we should be using tagged memory
-	 and that morecore does not support tagged regions, then
-	 disable it.  */
-      if (__MTAG_SBRK_UNTAGGED)
-	__always_fail_morecore = true;
-
-      mtag_enabled = true;
-      mtag_mmap_flags = __MTAG_MMAP_FLAGS;
-    }
-#endif
-
 #if defined SHARED && IS_IN (libc)
   /* In case this libc copy is in a non-default namespace, never use
      brk.  Likewise if dlopened from statically linked program.  The
@@ -417,7 +403,7 @@ alloc_new_heap  (size_t size, size_t top_pad, size_t pagesize,
             }
         }
     }
-  if (__mprotect (p2, size, mtag_mmap_flags | PROT_READ | PROT_WRITE) != 0)
+  if (__mprotect (p2, size, extra_mmap_prot | PROT_READ | PROT_WRITE) != 0)
     {
       __munmap (p2, max_size);
       return NULL;
@@ -471,7 +457,7 @@ grow_heap (heap_info *h, long diff)
     {
       if (__mprotect ((char *) h + h->mprotect_size,
                       (unsigned long) new_size - h->mprotect_size,
-                      mtag_mmap_flags | PROT_READ | PROT_WRITE) != 0)
+                      extra_mmap_prot | PROT_READ | PROT_WRITE) != 0)
         return -2;
 
       h->mprotect_size = new_size;
diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
index 49b623df12..8ed419c6e9 100644
--- a/malloc/malloc-check.c
+++ b/malloc/malloc-check.c
@@ -19,12 +19,8 @@
 #define __mremap mremap
 #include "malloc.c"
 
-/* When memory is tagged, the checking data is stored in the user part
-   of the chunk.  We can't rely on the user not having modified the
-   tags, so fetch the tag at each location before dereferencing
-   it.  */
-#define SAFE_CHAR_OFFSET(p,offset) \
-  ((unsigned char *) tag_at (((unsigned char *) p) + offset))
+#define CHAR_OFFSET(p,offset) \
+  ((unsigned char *) (((unsigned char *) p) + offset))
 
 /* A simple, standard set of debugging hooks.  Overhead is `only' one
    byte per chunk; still this will catch most cases of double frees or
@@ -58,7 +54,7 @@ malloc_check_get_size (void *mem)
   unsigned char magic = magicbyte (p);
 
   for (size = CHUNK_HDR_SZ + memsize (p) - 1;
-       (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
+       (c = *CHAR_OFFSET (p, size)) != magic;
        size -= c)
     {
       if (c <= 0 || size < (c + CHUNK_HDR_SZ))
@@ -95,9 +91,9 @@ mem2mem_check (void *ptr, size_t req_sz)
       if (block_sz == magic)
         --block_sz;
 
-      *SAFE_CHAR_OFFSET (m_ptr, i) = block_sz;
+      *CHAR_OFFSET (m_ptr, i) = block_sz;
     }
-  *SAFE_CHAR_OFFSET (m_ptr, req_sz) = magic;
+  *CHAR_OFFSET (m_ptr, req_sz) = magic;
   return (void *) m_ptr;
 }
 
@@ -131,7 +127,7 @@ mem2chunk_check (void *mem, unsigned char **magic_p)
         return NULL;
 
       for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
-	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
+	   (c = *CHAR_OFFSET (p, sz)) != magic;
 	   sz -= c)
         {
           if (c == 0 || sz < (c + CHUNK_HDR_SZ))
@@ -156,7 +152,7 @@ mem2chunk_check (void *mem, unsigned char **magic_p)
         return NULL;
 
       for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
-	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
+	   (c = *CHAR_OFFSET (p, sz)) != magic;
 	   sz -= c)
         {
           if (c == 0 || sz < (c + CHUNK_HDR_SZ))
@@ -164,7 +160,7 @@ mem2chunk_check (void *mem, unsigned char **magic_p)
         }
     }
 
-  unsigned char* safe_p = SAFE_CHAR_OFFSET (p, sz);
+  unsigned char* safe_p = CHAR_OFFSET (p, sz);
   *safe_p ^= 0xFF;
   if (magic_p)
     *magic_p = safe_p;
@@ -204,7 +200,7 @@ malloc_check (size_t sz)
   top_check ();
   victim = _int_malloc (&main_arena, nb);
   __libc_lock_unlock (main_arena.mutex);
-  return mem2mem_check (tag_new_usable (victim), sz);
+  return mem2mem_check (victim, sz);
 }
 
 static void
@@ -217,11 +213,6 @@ free_check (void *mem)
 
   int err = errno;
 
-  /* Quickly check that the freed pointer matches the tag for the memory.
-     This gives a useful double-free detection.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char *)mem;
-
   __libc_lock_lock (main_arena.mutex);
   p = mem2chunk_check (mem, NULL);
   if (!p)
@@ -233,8 +224,6 @@ free_check (void *mem)
     }
   else
     {
-      /* Mark the chunk as belonging to the library again.  */
-      (void)tag_region (chunk2mem (p), memsize (p));
       _int_free_chunk (&main_arena, p, chunksize (p), 1);
       __libc_lock_unlock (main_arena.mutex);
     }
@@ -263,11 +252,6 @@ realloc_check (void *oldmem, size_t bytes)
       return NULL;
     }
 
-  /* Quickly check that the freed pointer matches the tag for the memory.
-     This gives a useful double-free detection.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char *)oldmem;
-
   __libc_lock_lock (main_arena.mutex);
   const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
   __libc_lock_unlock (main_arena.mutex);
@@ -288,7 +272,7 @@ realloc_check (void *oldmem, size_t bytes)
 #if HAVE_MREMAP
       mchunkptr newp = mremap_chunk (oldp, chnb);
       if (newp)
-        newmem = chunk2mem_tag (newp);
+        newmem = chunk2mem (newp);
       else
 #endif
       {
@@ -323,7 +307,7 @@ invert:
 
   __libc_lock_unlock (main_arena.mutex);
 
-  return mem2mem_check (tag_new_usable (newmem), bytes);
+  return mem2mem_check (newmem, bytes);
 }
 
 static void *
@@ -365,7 +349,7 @@ memalign_check (size_t alignment, size_t bytes)
   top_check ();
   mem = _int_memalign (&main_arena, alignment, bytes + 1);
   __libc_lock_unlock (main_arena.mutex);
-  return mem2mem_check (tag_new_usable (mem), bytes);
+  return mem2mem_check (mem, bytes);
 }
 
 static void
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 5313ee68e3..18fe48e001 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -233,9 +233,7 @@
 /* For ALIGN_UP et. al.  */
 #include <libc-pointer-arith.h>
 
-/* For memory tagging.  */
-#include <libc-mtag.h>
-
+/* For internal malloc interfaces and declarations.  */
 #include <malloc/malloc-internal.h>
 
 /* For SINGLE_THREAD_P.  */
@@ -349,97 +347,7 @@ verify (PTRDIFF_MAX <= SIZE_MAX / 2);
 #define MORECORE         (*__glibc_morecore)
 #define MORECORE_FAILURE  NULL
 
-/* Memory tagging.  */
-
-/* Some systems support the concept of tagging (sometimes known as
-   coloring) memory locations on a fine grained basis.  Each memory
-   location is given a color (normally allocated randomly) and
-   pointers are also colored.  When the pointer is dereferenced, the
-   pointer's color is checked against the memory's color and if they
-   differ the access is faulted (sometimes lazily).
-
-   We use this in glibc by maintaining a single color for the malloc
-   data structures that are interleaved with the user data and then
-   assigning separate colors for each block allocation handed out.  In
-   this way simple buffer overruns will be rapidly detected.  When
-   memory is freed, the memory is recolored back to the glibc default
-   so that simple use-after-free errors can also be detected.
-
-   If memory is reallocated the buffer is recolored even if the
-   address remains the same.  This has a performance impact, but
-   guarantees that the old pointer cannot mistakenly be reused (code
-   that compares old against new will see a mismatch and will then
-   need to behave as though realloc moved the data to a new location).
-
-   Internal API for memory tagging support.
-
-   The aim is to keep the code for memory tagging support as close to
-   the normal APIs in glibc as possible, so that if tagging is not
-   enabled in the library, or is disabled at runtime then standard
-   operations can continue to be used.  Support macros are used to do
-   this:
-
-   void *tag_new_zero_region (void *ptr, size_t size)
-
-   Allocates a new tag, colors the memory with that tag, zeros the
-   memory and returns a pointer that is correctly colored for that
-   location.  The non-tagging version will simply call memset with 0.
-
-   void *tag_region (void *ptr, size_t size)
-
-   Color the region of memory pointed to by PTR and size SIZE with
-   the color of PTR.  Returns the original pointer.
-
-   void *tag_new_usable (void *ptr)
-
-   Allocate a new random color and use it to color the user region of
-   a chunk; this may include data from the subsequent chunk's header
-   if tagging is sufficiently fine grained.  Returns PTR suitably
-   recolored for accessing the memory there.
-
-   void *tag_at (void *ptr)
-
-   Read the current color of the memory at the address pointed to by
-   PTR (ignoring it's current color) and return PTR recolored to that
-   color.  PTR must be valid address in all other respects.  When
-   tagging is not enabled, it simply returns the original pointer.
-*/
-
-#ifdef USE_MTAG
-static bool mtag_enabled = false;
-static int mtag_mmap_flags = 0;
-#else
-# define mtag_enabled false
-# define mtag_mmap_flags 0
-#endif
-
-static __always_inline void *
-tag_region (void *ptr, size_t size)
-{
-  if (__glibc_unlikely (mtag_enabled))
-    return __libc_mtag_tag_region (ptr, size);
-  return ptr;
-}
-
-static __always_inline void *
-tag_new_zero_region (void *ptr, size_t size)
-{
-  if (__glibc_unlikely (mtag_enabled))
-    return __libc_mtag_tag_zero_region (__libc_mtag_new_tag (ptr), size);
-  return memset (ptr, 0, size);
-}
-
-/* Defined later.  */
-static void *
-tag_new_usable (void *ptr);
-
-static __always_inline void *
-tag_at (void *ptr)
-{
-  if (__glibc_unlikely (mtag_enabled))
-    return __libc_mtag_address_get_tag (ptr);
-  return ptr;
-}
+static int extra_mmap_prot = 0;
 
 
 /*
@@ -1194,38 +1102,15 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ---------- Size and alignment checks and conversions ----------
 */
 
-/* Conversion from malloc headers to user pointers, and back.  When
-   using memory tagging the user data and the malloc data structure
-   headers have distinct tags.  Converting fully from one to the other
-   involves extracting the tag at the other address and creating a
-   suitable pointer using it.  That can be quite expensive.  There are
-   cases when the pointers are not dereferenced (for example only used
-   for alignment check) so the tags are not relevant, and there are
-   cases when user data is not tagged distinctly from malloc headers
-   (user data is untagged because tagging is done late in malloc and
-   early in free).  User memory tagging across internal interfaces:
-
-      sysmalloc: Returns untagged memory.
-      _int_malloc: Returns untagged memory.
-      _int_memalign: Returns untagged memory.
-      _int_memalign: Returns untagged memory.
-      _mid_memalign: Returns tagged memory.
-      _int_realloc: Takes and returns tagged memory.
-*/
-
 /* The chunk header is two SIZE_SZ elements, but this is used widely, so
    we define it here for clarity later.  */
 #define CHUNK_HDR_SZ (2 * SIZE_SZ)
 
-/* Convert a chunk address to a user mem pointer without correcting
-   the tag.  */
+/* Convert a chunk address to a user mem pointer.  */
 #define chunk2mem(p) ((void*)((char*)(p) + CHUNK_HDR_SZ))
 
-/* Convert a chunk address to a user mem pointer and extract the right tag.  */
-#define chunk2mem_tag(p) ((void*)tag_at ((char*)(p) + CHUNK_HDR_SZ))
-
-/* Convert a user mem pointer to a chunk address and extract the right tag.  */
-#define mem2chunk(mem) ((mchunkptr)tag_at (((char*)(mem) - CHUNK_HDR_SZ)))
+/* Convert a user mem pointer to a chunk address.  */
+#define mem2chunk(mem) ((mchunkptr) (((char*)(mem) - CHUNK_HDR_SZ)))
 
 /* The smallest possible chunk */
 #define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))
@@ -1258,23 +1143,6 @@ checked_request2size (size_t req) __nonnull (1)
 {
   if (__glibc_unlikely (req > PTRDIFF_MAX))
     return SIZE_MAX;
-
-  /* When using tagged memory, we cannot share the end of the user
-     block with the header for the next chunk, so ensure that we
-     allocate blocks that are rounded up to the granule size.  Take
-     care not to overflow from close to MAX_SIZE_T to a small
-     number.  Ideally, this would be part of request2size(), but that
-     must be a macro that produces a compile time constant if passed
-     a constant literal.  */
-  if (__glibc_unlikely (mtag_enabled))
-    {
-      /* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551.  */
-      asm ("");
-
-      req = (req + (__MTAG_GRANULE_SIZE - 1)) &
-	    ~(size_t)(__MTAG_GRANULE_SIZE - 1);
-    }
-
   return request2size (req);
 }
 
@@ -1377,27 +1245,7 @@ checked_request2size (size_t req) __nonnull (1)
 
 /* This is the size of the real usable data in the chunk.  Not valid for
    dumped heap chunks.  */
-#define memsize(p)                                                    \
-  (__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
-    chunksize (p) - CHUNK_HDR_SZ :                                    \
-    chunksize (p) - CHUNK_HDR_SZ + SIZE_SZ)
-
-/* If memory tagging is enabled the layout changes to accommodate the granule
-   size, this is wasteful for small allocations so not done by default.
-   Both the chunk header and user data has to be granule aligned.  */
-_Static_assert (__MTAG_GRANULE_SIZE <= CHUNK_HDR_SZ,
-		"memory tagging is not supported with large granule.");
-
-static __always_inline void *
-tag_new_usable (void *ptr)
-{
-  if (__glibc_unlikely (mtag_enabled) && ptr)
-    {
-      mchunkptr cp = mem2chunk(ptr);
-      ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
-    }
-  return ptr;
-}
+#define memsize(p) (chunksize (p) - CHUNK_HDR_SZ + SIZE_SZ)
 
 /* Huge page used for an mmap chunk.  */
 #define MMAP_HP 0x1
@@ -2228,7 +2076,7 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags)
   size_t size = ALIGN_UP (nb + padding + CHUNK_HDR_SZ, pagesize);
 
   char *mm = (char *) MMAP (NULL, size,
-			    mtag_mmap_flags | PROT_READ | PROT_WRITE,
+			    extra_mmap_prot | PROT_READ | PROT_WRITE,
 			    extra_flags);
   if (mm == MAP_FAILED)
     return mm;
@@ -2269,7 +2117,7 @@ sysmalloc_mmap_fallback (size_t *s, size_t size, size_t minsize,
     size = minsize;
 
   char *mbrk = (char *) (MMAP (NULL, size,
-			       mtag_mmap_flags | PROT_READ | PROT_WRITE,
+			       extra_mmap_prot | PROT_READ | PROT_WRITE,
 			       extra_flags));
   if (mbrk == MAP_FAILED)
     return MAP_FAILED;
@@ -3106,7 +2954,7 @@ tcache_get_align (size_t nb, size_t alignment)
       if (te != NULL
 	  && csize == nb
 	  && PTR_IS_ALIGNED (te, alignment))
-	return tag_new_usable (tcache_get_n (tc_idx, tep, mangled));
+	return tcache_get_n (tc_idx, tep, mangled);
     }
   return NULL;
 }
@@ -3224,7 +3072,7 @@ __libc_malloc2 (size_t bytes)
 
   if (SINGLE_THREAD_P)
     {
-      victim = tag_new_usable (_int_malloc (&main_arena, bytes));
+      victim = _int_malloc (&main_arena, bytes);
       assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
 	      &main_arena == arena_for_chunk (mem2chunk (victim)));
       return victim;
@@ -3245,8 +3093,6 @@ __libc_malloc2 (size_t bytes)
   if (ar_ptr != NULL)
     __libc_lock_unlock (ar_ptr->mutex);
 
-  victim = tag_new_usable (victim);
-
   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
           ar_ptr == arena_for_chunk (mem2chunk (victim)));
   return victim;
@@ -3265,14 +3111,14 @@ __libc_malloc (size_t bytes)
       if (__glibc_likely (tc_idx < TCACHE_SMALL_BINS))
         {
 	  if (tcache->entries[tc_idx] != NULL)
-	    return tag_new_usable (tcache_get (tc_idx));
+	    return tcache_get (tc_idx);
 	}
       else
         {
 	  tc_idx = large_csize2tidx (nb);
 	  void *victim = tcache_get_large (tc_idx, nb);
 	  if (victim != NULL)
-	    return tag_new_usable (victim);
+	    return victim;
 	}
     }
 #endif
@@ -3296,16 +3142,8 @@ __libc_free (void *mem)
   if (mem == NULL)                              /* free(0) has no effect */
     return;
 
-  /* Quickly check that the freed pointer matches the tag for the memory.
-     This gives a useful double-free detection.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char *)mem;
-
   p = mem2chunk (mem);
 
-  /* Mark the chunk as belonging to the library again.  */
-  tag_region (chunk2mem (p), memsize (p));
-
   INTERNAL_SIZE_T size = chunksize (p);
 
   if (__glibc_unlikely (misaligned_chunk (p)))
@@ -3368,11 +3206,6 @@ __libc_realloc (void *oldmem, size_t bytes)
     }
 #endif
 
-  /* Perform a quick check to ensure that the pointer's tag matches the
-     memory's tag.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char*) oldmem;
-
   /* chunk corresponding to oldmem */
   const mchunkptr oldp = mem2chunk (oldmem);
 
@@ -3414,15 +3247,7 @@ __libc_realloc (void *oldmem, size_t bytes)
 #if HAVE_MREMAP
       newp = mremap_chunk (oldp, nb);
       if (newp)
-	{
-	  void *newmem = chunk2mem_tag (newp);
-	  /* Give the new block a different tag.  This helps to ensure
-	     that stale handles to the previous mapping are not
-	     reused.  There's a performance hit for both us and the
-	     caller for doing this, so we might want to
-	     reconsider.  */
-	  return tag_new_usable (newmem);
-	}
+	return chunk2mem (newp);
 #endif
       /* Return if shrinking and mremap was unsuccessful.  */
       if (bytes <= usable)
@@ -3464,10 +3289,8 @@ __libc_realloc (void *oldmem, size_t bytes)
       newp = __libc_malloc (bytes);
       if (newp != NULL)
         {
-	  size_t sz = memsize (oldp);
-	  memcpy (newp, oldmem, sz);
-	  (void) tag_region (chunk2mem (oldp), sz);
-          _int_free_chunk (ar_ptr, oldp, chunksize (oldp), 0);
+	  memcpy (newp, oldmem, memsize (oldp));
+	  _int_free_chunk (ar_ptr, oldp, chunksize (oldp), 0);
         }
     }
 
@@ -3551,7 +3374,7 @@ _mid_memalign (size_t alignment, size_t bytes)
 #if USE_TCACHE
   void *victim = tcache_get_align (checked_request2size (bytes), alignment);
   if (victim != NULL)
-    return tag_new_usable (victim);
+    return victim;
 #endif
 
   if (SINGLE_THREAD_P)
@@ -3559,7 +3382,7 @@ _mid_memalign (size_t alignment, size_t bytes)
       p = _int_memalign (&main_arena, alignment, bytes);
       assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
 	      &main_arena == arena_for_chunk (mem2chunk (p)));
-      return tag_new_usable (p);
+      return p;
     }
 
   arena_get (ar_ptr, bytes + alignment + MINSIZE);
@@ -3577,7 +3400,7 @@ _mid_memalign (size_t alignment, size_t bytes)
 
   assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
           ar_ptr == arena_for_chunk (mem2chunk (p)));
-  return tag_new_usable (p);
+  return p;
 }
 
 void *
@@ -3668,12 +3491,6 @@ __libc_calloc2 (size_t sz)
 
   p = mem2chunk (mem);
 
-  /* If we are using memory tagging, then we need to set the tags
-     regardless of MORECORE_CLEARS, so we zero the whole block while
-     doing so.  */
-  if (__glibc_unlikely (mtag_enabled))
-    return tag_new_zero_region (mem, memsize (p));
-
   csz = chunksize (p);
 
   /* Two optional cases in which clearing not necessary */
@@ -3720,9 +3537,6 @@ __libc_calloc (size_t n, size_t elem_size)
 	  if (tcache->entries[tc_idx] != NULL)
 	    {
 	      void *mem = tcache_get (tc_idx);
-	      if (__glibc_unlikely (mtag_enabled))
-		return tag_new_zero_region (mem, memsize (mem2chunk (mem)));
-
 	      return clear_memory ((INTERNAL_SIZE_T *) mem, tidx2usize (tc_idx));
 	    }
 	}
@@ -3731,12 +3545,7 @@ __libc_calloc (size_t n, size_t elem_size)
 	  tc_idx = large_csize2tidx (nb);
 	  void *mem = tcache_get_large (tc_idx, nb);
 	  if (mem != NULL)
-	    {
-	      if (__glibc_unlikely (mtag_enabled))
-	        return tag_new_zero_region (mem, memsize (mem2chunk (mem)));
-
-	      return memset (mem, 0, memsize (mem2chunk (mem)));
-	    }
+	    return memset (mem, 0, memsize (mem2chunk (mem)));
 	}
     }
 #endif
@@ -4494,7 +4303,7 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
           av->top = chunk_at_offset (oldp, nb);
           set_head (av->top, (newsize - nb) | PREV_INUSE);
           check_inuse_chunk (av, oldp);
-          return tag_new_usable (chunk2mem (oldp));
+          return chunk2mem (oldp);
         }
 
       /* Try to expand forward into next chunk;  split off remainder below */
@@ -4528,10 +4337,7 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
           else
             {
 	      void *oldmem = chunk2mem (oldp);
-	      size_t sz = memsize (oldp);
-	      (void) tag_region (oldmem, sz);
-	      newmem = tag_new_usable (newmem);
-	      memcpy (newmem, oldmem, sz);
+	      memcpy (newmem, oldmem, memsize (oldp));
 	      _int_free_chunk (av, oldp, chunksize (oldp), 1);
 	      check_inuse_chunk (av, newp);
 	      return newmem;
@@ -4553,8 +4359,6 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
   else   /* split remainder */
     {
       remainder = chunk_at_offset (newp, nb);
-      /* Clear any user-space tags before writing the header.  */
-      remainder = tag_region (remainder, remainder_size);
       set_head_size (newp, nb | (av != &main_arena ? NON_MAIN_ARENA : 0));
       set_head (remainder, remainder_size | PREV_INUSE |
                 (av != &main_arena ? NON_MAIN_ARENA : 0));
@@ -4564,7 +4368,7 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
     }
 
   check_inuse_chunk (av, newp);
-  return tag_new_usable (chunk2mem (newp));
+  return chunk2mem (newp);
 }
 
 /*
diff --git a/manual/install.texi b/manual/install.texi
index 073cda0530..4094baa259 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -185,19 +185,6 @@ non CET enabled shared library in CET enabled application.
 
 NOTE: @option{--enable-cet} is only supported on x86_64 and x32.
 
-@item --enable-memory-tagging
-Enable memory tagging support if the architecture supports it.  When
-@theglibc{} is built with this option then the resulting library will
-be able to control the use of tagged memory when hardware support is
-present by use of the tunable @samp{glibc.mem.tagging}.  This includes
-the generation of tagged memory when using the @code{malloc} APIs.
-
-At present only AArch64 platforms with MTE provide this functionality,
-although the library will still operate (without memory tagging) on
-older versions of the architecture.
-
-The default is to disable support for memory tagging.
-
 @item --disable-profile
 Don't build libraries with profiling information.  You may want to use
 this option if you don't plan to do profiling.
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 12b515c628..95b7075ae7 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -40,7 +40,6 @@ glibc.malloc.perturb: 0 (min: 0, max: 255)
 glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff)
 glibc.pthread.rseq: 1 (min: 0, max: 1)
 glibc.cpu.prefer_map_32bit_exec: 0 (min: 0, max: 1)
-glibc.mem.tagging: 0 (min: 0, max: 255)
 glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0xffffffffffffffff)
 glibc.cpu.x86_rep_movsb_threshold: 0x2000 (min: 0x100, max: 0xffffffffffffffff)
 glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff)
@@ -666,34 +665,6 @@ This tunable namespace supports operations that affect the way @theglibc{}
 and the process manage memory.
 @end deftp
 
-@deftp Tunable glibc.mem.tagging
-If the hardware supports memory tagging, this tunable can be used to
-control the way @theglibc{} uses this feature.  At present this is only
-supported on AArch64 systems with the MTE extension; it is ignored for
-all other systems.
-
-This tunable takes a value between 0 and 255 and acts as a bitmask
-that enables various capabilities.
-
-Bit 0 (the least significant bit) causes the @code{malloc}
-subsystem to allocate
-tagged memory, with each allocation being assigned a random tag.
-
-Bit 1 enables precise faulting mode for tag violations on systems that
-support deferred tag violation reporting.  This may cause programs
-to run more slowly.
-
-Bit 2 enables either precise or deferred faulting mode for tag violations
-whichever is preferred by the system.
-
-Other bits are currently reserved.
-
-@Theglibc{} startup code will automatically enable memory tagging
-support in the kernel if this tunable has any non-zero value.
-
-The default value is @samp{0}, which disables all memory tagging.
-@end deftp
-
 @deftp Tunable glibc.mem.decorate_maps
 If the kernel supports naming anonymous virtual memory areas (since
 Linux version 5.17, although not always enabled by some kernel
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index 2cf2903021..52ac85a75d 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -82,8 +82,8 @@ sysdep_headers += \
 sysdep_routines += \
   __alloc_gcs \
   __arm_za_disable \
-  __mtag_tag_region \
-  __mtag_tag_zero_region \
+  __mte_tag_region \
+  __mte_tag_region_zero \
   # sysdep_routines
 
 tests += \
@@ -104,10 +104,7 @@ $(objpfx)tst-sme-za-disable-fail: $(objpfx)__arm_za_disable.o
 endif
 
 ifeq ($(subdir),malloc)
-sysdep_malloc_debug_routines = \
-  __mtag_tag_region \
-  __mtag_tag_zero_region \
-  # sysdep_malloc_debug_routines
+
 endif # malloc directory
 
 ifeq ($(subdir),support)
diff --git a/sysdeps/aarch64/__mtag_tag_region.S b/sysdeps/aarch64/__mte_tag_region.S
similarity index 96%
rename from sysdeps/aarch64/__mtag_tag_region.S
rename to sysdeps/aarch64/__mte_tag_region.S
index bad3193bfe..1698489fc2 100644
--- a/sysdeps/aarch64/__mtag_tag_region.S
+++ b/sysdeps/aarch64/__mte_tag_region.S
@@ -18,8 +18,6 @@
 
 #include <sysdep.h>
 
-#ifdef USE_MTAG
-
 /* Assumptions:
  *
  * ARMv8-a, AArch64, MTE, LP64 ABI.
@@ -39,7 +37,7 @@
 #define tmp	x4
 #define zva_val	x4
 
-ENTRY (__libc_mtag_tag_region)
+ENTRY (__mte_tag_region)
 	add	dstend, dstin, count
 
 	cmp	count, 96
@@ -106,5 +104,4 @@ L(no_zva_loop):
 	st2g	dstin, [dstend, -32]
 	ret
 
-END (__libc_mtag_tag_region)
-#endif /* USE_MTAG */
+END (__mte_tag_region)
diff --git a/sysdeps/aarch64/__mtag_tag_zero_region.S b/sysdeps/aarch64/__mte_tag_region_zero.S
similarity index 95%
rename from sysdeps/aarch64/__mtag_tag_zero_region.S
rename to sysdeps/aarch64/__mte_tag_region_zero.S
index 3bc6e7301f..2f506c9ee8 100644
--- a/sysdeps/aarch64/__mtag_tag_zero_region.S
+++ b/sysdeps/aarch64/__mte_tag_region_zero.S
@@ -18,8 +18,6 @@
 
 #include <sysdep.h>
 
-#ifdef USE_MTAG
-
 /* Assumptions:
  *
  * ARMv8-a, AArch64, MTE, LP64 ABI.
@@ -39,7 +37,7 @@
 #define tmp	x4
 #define zva_val	x4
 
-ENTRY (__libc_mtag_tag_zero_region)
+ENTRY (__mte_tag_region_zero)
 	add	dstend, dstin, count
 
 	cmp	count, 96
@@ -106,5 +104,4 @@ L(no_zva_loop):
 	stz2g	dstin, [dstend, -32]
 	ret
 
-END (__libc_mtag_tag_zero_region)
-#endif /* USE_MTAG */
+END (__mte_tag_region_zero)
diff --git a/sysdeps/aarch64/libc-mtag.h b/sysdeps/aarch64/aarch64-mte.h
similarity index 55%
rename from sysdeps/aarch64/libc-mtag.h
rename to sysdeps/aarch64/aarch64-mte.h
index 1d7368b806..f42564f528 100644
--- a/sysdeps/aarch64/libc-mtag.h
+++ b/sysdeps/aarch64/aarch64-mte.h
@@ -1,4 +1,4 @@
-/* libc-internal interface for tagged (colored) memory support.
+/* AArch64 MTE (Memory Tagging Extension) declarations.
    Copyright (C) 2020-2026 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -16,54 +16,49 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef _AARCH64_LIBC_MTAG_H
-#define _AARCH64_LIBC_MTAG_H 1
+#ifndef _AARCH64_MTE_H
+#define _AARCH64_MTE_H 1
 
-#ifndef USE_MTAG
-/* Generic bindings for systems that do not support memory tagging.  */
-#include_next "libc-mtag.h"
-#else
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
 
-/* Used to ensure additional alignment when objects need to have distinct
-   tags.  */
-#define __MTAG_GRANULE_SIZE 16
-
-/* Non-zero if memory obtained via morecore (sbrk) is not tagged.  */
-#define __MTAG_SBRK_UNTAGGED 1
-
-/* Extra flags to pass to mmap to get tagged pages.  */
-#define __MTAG_MMAP_FLAGS PROT_MTE
-
-/* Set the tags for a region of memory, which must have size and alignment
-   that are multiples of __MTAG_GRANULE_SIZE.  Size cannot be zero.  */
-void *__libc_mtag_tag_region (void *, size_t);
-
-/* Optimized equivalent to __libc_mtag_tag_region followed by memset to 0.  */
-void *__libc_mtag_tag_zero_region (void *, size_t);
-
-/* Convert address P to a pointer that is tagged correctly for that
-   location.  */
-static __always_inline void *
-__libc_mtag_address_get_tag (void *p)
+/* Assign a new (random) tag to a pointer P (does not adjust the
+   allocation tag on the memory addressed).  */
+static __always_inline __attribute_maybe_unused__ void *
+__mte_new_tag (void *p)
 {
   register void *x0 asm ("x0") = p;
-  asm (".inst 0xd9600000 /* ldg x0, [x0] */" : "+r" (x0));
+  register uintptr_t x1 asm ("x1");
+  /* Guarantee that the new tag is not the same as now.  */
+  asm (".inst 0x9adf1401 /* gmi x1, x0, xzr */\n"
+       ".inst 0x9ac11000 /* irg x0, x0, x1 */" : "+r" (x0), "=r" (x1));
   return x0;
 }
 
-/* Assign a new (random) tag to a pointer P (does not adjust the tag on
-   the memory addressed).  */
-static __always_inline void *
-__libc_mtag_new_tag (void *p)
+/* Clears logical tag in the input pointer.  */
+static __always_inline __attribute_maybe_unused__ void *
+__mte_clear_tag (void *p)
+{
+  return (void *)((uintptr_t)p & ~(0xfull << 56ull));
+}
+
+/* Convert address P to a pointer that is tagged correctly for that
+   location (logical tag in the returned pointer will be the same
+   as the allocation tag in the addressed memory).  */
+static __always_inline __attribute_maybe_unused__ void *
+__mte_get_tag (void *p)
 {
   register void *x0 asm ("x0") = p;
-  register unsigned long x1 asm ("x1");
-  /* Guarantee that the new tag is not the same as now.  */
-  asm (".inst 0x9adf1401 /* gmi x1, x0, xzr */\n"
-       ".inst 0x9ac11000 /* irg x0, x0, x1 */" : "+r" (x0), "=r" (x1));
+  asm (".inst 0xd9600000 /* ldg x0, [x0] */" : "+r" (x0));
   return x0;
 }
 
-#endif /* USE_MTAG */
+/* Set the tags for a region of memory, which must have size and alignment
+   that are multiples of MTE_GRANULE_SIZE.  Size cannot be zero.  */
+void *__mte_tag_region (void *, size_t);
+
+/* Optimized equivalent to __mte_tag_region followed by memset to 0.  */
+void *__mte_tag_region_zero (void *, size_t);
 
-#endif /* _AARCH64_LIBC_MTAG_H */
+#endif /* _AARCH64_MTE_H */
diff --git a/sysdeps/aarch64/cpu-features.h b/sysdeps/aarch64/cpu-features.h
index d1377c0dca..b7dab3dff4 100644
--- a/sysdeps/aarch64/cpu-features.h
+++ b/sysdeps/aarch64/cpu-features.h
@@ -64,8 +64,7 @@ struct cpu_features
   uint64_t midr_el1;
   unsigned zva_size;
   bool bti;
-  /* Currently, the GLIBC memory tagging tunable only defines 8 bits.  */
-  uint8_t mte_state;
+  uint8_t reserved;
   bool sve;
   bool unused;
   bool mops;
diff --git a/sysdeps/aarch64/dl-diagnostics-cpu.c b/sysdeps/aarch64/dl-diagnostics-cpu.c
index cbc2645f56..4b3fbcbd7c 100644
--- a/sysdeps/aarch64/dl-diagnostics-cpu.c
+++ b/sysdeps/aarch64/dl-diagnostics-cpu.c
@@ -45,8 +45,6 @@ _dl_diagnostics_cpu (void)
   print_cpu_features_value ("midr_el1",
                             GLRO (dl_aarch64_cpu_features).midr_el1);
   print_cpu_features_value ("mops", GLRO (dl_aarch64_cpu_features).mops);
-  print_cpu_features_value ("mte_state",
-                            GLRO (dl_aarch64_cpu_features).mte_state);
   print_cpu_features_value ("sve", GLRO (dl_aarch64_cpu_features).sve);
   print_cpu_features_value ("sve2", GLRO (dl_aarch64_cpu_features).sve2);
   print_cpu_features_value ("zva_size",
diff --git a/sysdeps/generic/libc-mtag.h b/sysdeps/generic/libc-mtag.h
deleted file mode 100644
index 5477bfa17f..0000000000
--- a/sysdeps/generic/libc-mtag.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* libc-internal interface for tagged (colored) memory support.
-   Copyright (C) 2020-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
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _GENERIC_LIBC_MTAG_H
-#define _GENERIC_LIBC_MTAG_H 1
-
-/* Generic bindings for systems that do not support memory tagging.  */
-
-/* Used to ensure additional alignment when objects need to have distinct
-   tags.  */
-#define __MTAG_GRANULE_SIZE 1
-
-/* Non-zero if memory obtained via morecore (sbrk) is not tagged.  */
-#define __MTAG_SBRK_UNTAGGED 0
-
-/* Extra flags to pass to mmap() to request a tagged region of memory.  */
-#define __MTAG_MMAP_FLAGS 0
-
-/* Memory tagging target hooks are only called when memory tagging is
-   enabled at runtime.  The generic definitions here must not be used.  */
-void __libc_mtag_link_error (void);
-
-/* Set the tags for a region of memory, which must have size and alignment
-   that are multiples of __MTAG_GRANULE_SIZE.  Size cannot be zero.  */
-static inline void *
-__libc_mtag_tag_region (void *p, size_t n)
-{
-  __libc_mtag_link_error ();
-  return p;
-}
-
-/* Optimized equivalent to __libc_mtag_tag_region followed by memset to 0.  */
-static inline void *
-__libc_mtag_tag_zero_region (void *p, size_t n)
-{
-  __libc_mtag_link_error ();
-  return memset (p, 0, n);
-}
-
-/* Convert address P to a pointer that is tagged correctly for that
-   location.  */
-static inline void *
-__libc_mtag_address_get_tag (void *p)
-{
-  __libc_mtag_link_error ();
-  return p;
-}
-
-/* Assign a new (random) tag to a pointer P (does not adjust the tag on
-   the memory addressed).  */
-static inline void *
-__libc_mtag_new_tag (void *p)
-{
-  __libc_mtag_link_error ();
-  return p;
-}
-
-#endif /* _GENERIC_LIBC_MTAG_H */
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 2e8887ce23..0bc4addb2a 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -20,7 +20,6 @@
 #include <cpu-features.h>
 #include <sys/auxv.h>
 #include <elf/dl-hwcaps.h>
-#include <sys/prctl.h>
 #include <sys/utsname.h>
 #include <dl-tunables-parse.h>
 #include <dl-symbol-redir-ifunc.h>
@@ -96,33 +95,6 @@ init_cpu_features (struct cpu_features *cpu_features)
   if (cpu_features->bti)
     GLRO (dl_aarch64_bti) = TUNABLE_GET (glibc, cpu, aarch64_bti, uint64_t, 0);
 
-  /* Setup memory tagging support if the HW and kernel support it, and if
-     the user has requested it.  */
-  cpu_features->mte_state = 0;
-
-#ifdef USE_MTAG
-  int mte_state = TUNABLE_GET (glibc, mem, tagging, unsigned, 0);
-  cpu_features->mte_state = (GLRO (dl_hwcap2) & HWCAP2_MTE) ? mte_state : 0;
-  /* If we lack the MTE feature, disable the tunable, since it will
-     otherwise cause instructions that won't run on this CPU to be used.  */
-  TUNABLE_SET (glibc, mem, tagging, cpu_features->mte_state);
-
-  if (cpu_features->mte_state & 4)
-    /* Enable choosing system-preferred faulting mode.  */
-    __prctl (PR_SET_TAGGED_ADDR_CTRL,
-	     (PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC
-	      | MTE_ALLOWED_TAGS),
-	     0, 0, 0);
-  else if (cpu_features->mte_state & 2)
-    __prctl (PR_SET_TAGGED_ADDR_CTRL,
-	     (PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | MTE_ALLOWED_TAGS),
-	     0, 0, 0);
-  else if (cpu_features->mte_state)
-    __prctl (PR_SET_TAGGED_ADDR_CTRL,
-	     (PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC | MTE_ALLOWED_TAGS),
-	     0, 0, 0);
-#endif
-
   /* Check if SVE is supported.  */
   cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE;
   cpu_features->sve2 = GLRO (dl_hwcap2) & HWCAP2_SVE2;