[glibc/arm/malloc-mte-v3] aarch64: Add glibc.mem.aarch64_mte tunable
Yury Khrustalev via Glibc-cvs <[email protected]> Mon, 1 Jun 2026 11:43:32 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=ce61edbeea76c32965c4ba0ff110f38cc428e3a6 commit ce61edbeea76c32965c4ba0ff110f38cc428e3a6 Author: Yury Khrustalev <[email protected]> Date: Thu Apr 23 14:31:54 2026 +0100 aarch64: Add glibc.mem.aarch64_mte tunable Add new tunable glibc.mem.aarch64_mte of string type with supported values: none, sync, async, and auto. Use it to control prctl syscall used to send the PR_SET_TAGGED_ADDR_CTRL command. To avoid confusion, we also remove the glibc.mem.tagging tunable. The new tunable defaults to 'none' and only works of MTE is supported. Diff: --- manual/tunables.texi | 15 ++++++ sysdeps/aarch64/Makefile | 1 + sysdeps/aarch64/cpu-features.h | 8 +++ sysdeps/aarch64/dl-diagnostics-cpu.c | 1 + sysdeps/aarch64/dl-mte.c | 67 ++++++++++++++++++++++++ sysdeps/aarch64/dl-start.S | 2 + sysdeps/aarch64/dl-tunables.list | 5 ++ sysdeps/aarch64/multiarch/init-arch.h | 2 +- sysdeps/unix/sysv/linux/aarch64/cpu-features.c | 21 ++++++++ sysdeps/unix/sysv/linux/aarch64/dl-procruntime.c | 16 ++++++ sysdeps/unix/sysv/linux/aarch64/libc-start.h | 6 +++ 11 files changed, 143 insertions(+), 1 deletion(-) diff --git a/manual/tunables.texi b/manual/tunables.texi index 95b7075ae7..cfaa5ca69d 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -682,6 +682,21 @@ This tunable takes a value of 0 and 1, where 1 enables the feature. The default value is @samp{0}, which disables the decoration. @end deftp +@deftp Tunable glibc.mem.aarch64_mte +On AArch64 systems that support Memory Tagging Extension (MTE) this +tunable allows to select tag check fault mode (MTE mode). + +Supported values are: + +@itemize @bullet +@item @code{none}: (the default), memory tagging is disabled. +@item @code{auto}: enable CPU-preferred tag checking mode. +@item @code{sync}: enable synchronous tag check fault mode. +@item @code{async}: enable asynchronous tag check fault mode. +@end itemize + +@end deftp + @node gmon Tunables @section gmon Tunables @cindex gmon tunables diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile index 52ac85a75d..71e061850f 100644 --- a/sysdeps/aarch64/Makefile +++ b/sysdeps/aarch64/Makefile @@ -4,6 +4,7 @@ ifeq ($(subdir),elf) sysdep-dl-routines += \ dl-bti \ dl-gcs \ + dl-mte \ # sysdep-dl-routines tests += \ diff --git a/sysdeps/aarch64/cpu-features.h b/sysdeps/aarch64/cpu-features.h index b7dab3dff4..372df464ce 100644 --- a/sysdeps/aarch64/cpu-features.h +++ b/sysdeps/aarch64/cpu-features.h @@ -59,6 +59,13 @@ enum { BTI_CHECK_ENFORCED = 1, }; +enum { + MTE_TUNABLE_NONE = 0, + MTE_TUNABLE_AUTO = 1, + MTE_TUNABLE_SYNC = 2, + MTE_TUNABLE_ASYNC = 3, +}; + struct cpu_features { uint64_t midr_el1; @@ -69,6 +76,7 @@ struct cpu_features bool unused; bool mops; bool sve2; + bool mte; }; #endif /* _CPU_FEATURES_AARCH64_H */ diff --git a/sysdeps/aarch64/dl-diagnostics-cpu.c b/sysdeps/aarch64/dl-diagnostics-cpu.c index 4b3fbcbd7c..6a08d62239 100644 --- a/sysdeps/aarch64/dl-diagnostics-cpu.c +++ b/sysdeps/aarch64/dl-diagnostics-cpu.c @@ -47,6 +47,7 @@ _dl_diagnostics_cpu (void) print_cpu_features_value ("mops", GLRO (dl_aarch64_cpu_features).mops); 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 ("mte", GLRO (dl_aarch64_cpu_features).mte); print_cpu_features_value ("zva_size", GLRO (dl_aarch64_cpu_features).zva_size); diff --git a/sysdeps/aarch64/dl-mte.c b/sysdeps/aarch64/dl-mte.c new file mode 100644 index 0000000000..41c4a260bb --- /dev/null +++ b/sysdeps/aarch64/dl-mte.c @@ -0,0 +1,67 @@ +/* AArch64 implementation for MTE (memory tagging). + 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 <sys/cdefs.h> +#include <ldsodefs.h> + +/* For the prctl syscall. */ +#define PR_SET_TAGGED_ADDR_CTRL 55 +#define PR_MTE_TAG_SHIFT 3 +#define PR_TAGGED_ADDR_ENABLE (1UL << 0) +#define PR_MTE_TCF_SYNC (1UL << 1) +#define PR_MTE_TCF_ASYNC (1UL << 2) + +/* The maximal set of permitted tags that the MTE random tag generation + instruction may use. We exclude tag 0 because a) we want to reserve + that for the libc heap structures and b) because it makes it easier + to see when pointer have been correctly tagged. */ +#define MTE_ALLOWED_TAGS (0xfffe << PR_MTE_TAG_SHIFT) + +void __mte_init (void); +rtld_hidden_proto (__mte_init) + +void __mte_init (void) +{ + if (!GLRO (dl_aarch64_cpu_features).mte) + return; + int mode = GL (dl_aarch64_mte); + if (mode == MTE_TUNABLE_NONE) + return; + uint64_t flags = PR_TAGGED_ADDR_ENABLE | MTE_ALLOWED_TAGS; + switch (mode) + { + case MTE_TUNABLE_AUTO: + flags |= PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC; + break; + case MTE_TUNABLE_SYNC: + flags |= PR_MTE_TCF_SYNC; + break; + case MTE_TUNABLE_ASYNC: + flags |= PR_MTE_TCF_ASYNC; + break; + default: + _dl_fatal_printf ("unknown MTE mode: %d\n", mode); + __builtin_unreachable (); + } + /* We use inline system call to avoid unnecessary dependency + on the sys/prctl.h header. */ + int r = INLINE_SYSCALL_CALL (prctl, PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0); + if (r == -1) + _dl_fatal_printf ("failed to enable MTE\n"); +} +rtld_hidden_def (__mte_init) diff --git a/sysdeps/aarch64/dl-start.S b/sysdeps/aarch64/dl-start.S index c278485cd3..ab490d2460 100644 --- a/sysdeps/aarch64/dl-start.S +++ b/sysdeps/aarch64/dl-start.S @@ -66,6 +66,8 @@ ENTRY (_start) cbnz w0, L(failed_gcs_lock) L(skip_gcs_enable): + bl HIDDEN_JUMPTARGET(__mte_init) + .globl _dl_start_user .type _dl_start_user, %function _dl_start_user: diff --git a/sysdeps/aarch64/dl-tunables.list b/sysdeps/aarch64/dl-tunables.list index a2ccba0b29..e153387971 100644 --- a/sysdeps/aarch64/dl-tunables.list +++ b/sysdeps/aarch64/dl-tunables.list @@ -34,4 +34,9 @@ glibc { default: 0 } } + mem { + aarch64_mte { + type: STRING + } + } } diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h index e00d1746d8..1b87ad1d44 100644 --- a/sysdeps/aarch64/multiarch/init-arch.h +++ b/sysdeps/aarch64/multiarch/init-arch.h @@ -25,7 +25,7 @@ unsigned __attribute__((unused)) zva_size = \ GLRO(dl_aarch64_cpu_features).zva_size; \ bool __attribute__((unused)) bti = GLRO(dl_aarch64_cpu_features).bti; \ - bool __attribute__((unused)) mte = GLRO(dl_hwcap2) & HWCAP2_MTE; \ + bool __attribute__((unused)) mte = GLRO(dl_aarch64_cpu_features).mte; \ bool __attribute__((unused)) sve = GLRO(dl_aarch64_cpu_features).sve; \ bool __attribute__((unused)) sve2 = GLRO(dl_aarch64_cpu_features).sve2; \ bool __attribute__((unused)) mops = GLRO(dl_aarch64_cpu_features).mops; diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c index 0bc4addb2a..f81174ecab 100644 --- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c @@ -59,6 +59,19 @@ get_midr_from_mcpu (const struct tunable_str_t *mcpu) return UINT64_MAX; } +static void +TUNABLE_CALLBACK (set_aarch64_mte) (tunable_val_t *val) +{ + if (tunable_strcmp_cte (val, "auto")) + GL (dl_aarch64_mte) = MTE_TUNABLE_AUTO; + else if (tunable_strcmp_cte (val, "sync")) + GL (dl_aarch64_mte) = MTE_TUNABLE_SYNC; + else if (tunable_strcmp_cte (val, "async")) + GL (dl_aarch64_mte) = MTE_TUNABLE_ASYNC; + else + GL (dl_aarch64_mte) = MTE_TUNABLE_NONE; +} + static inline void init_cpu_features (struct cpu_features *cpu_features) { @@ -95,6 +108,14 @@ 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); + /* Check if MTE is supported. */ + cpu_features->mte = GLRO (dl_hwcap2) & HWCAP2_MTE; + if (cpu_features->mte) + TUNABLE_GET (glibc, mem, aarch64_mte, tunable_val_t *, + TUNABLE_CALLBACK (set_aarch64_mte)); + else + GL (dl_aarch64_mte) = MTE_TUNABLE_NONE; + /* Check if SVE is supported. */ cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE; cpu_features->sve2 = GLRO (dl_hwcap2) & HWCAP2_SVE2; diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-procruntime.c b/sysdeps/unix/sysv/linux/aarch64/dl-procruntime.c index 1f3b58d0fc..0ddba83fb1 100644 --- a/sysdeps/unix/sysv/linux/aarch64/dl-procruntime.c +++ b/sysdeps/unix/sysv/linux/aarch64/dl-procruntime.c @@ -35,3 +35,19 @@ PROCINFO_CLASS unsigned long _dl_aarch64_gcs , # endif #endif + +#if !IS_IN (ldconfig) +# if !defined PROCINFO_DECL && defined SHARED + ._dl_aarch64_mte +# else +PROCINFO_CLASS int _dl_aarch64_mte +# endif +# ifndef PROCINFO_DECL += 0 +# endif +# if !defined SHARED || defined PROCINFO_DECL +; +# else +, +# endif +#endif diff --git a/sysdeps/unix/sysv/linux/aarch64/libc-start.h b/sysdeps/unix/sysv/linux/aarch64/libc-start.h index 53683ee511..3a7422f70c 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc-start.h +++ b/sysdeps/unix/sysv/linux/aarch64/libc-start.h @@ -36,6 +36,9 @@ # define GCS_POLICY_OPTIONAL 2 # endif +void __mte_init (void); +rtld_hidden_proto (__mte_init) + /* Must be on a top-level stack frame that does not return. */ static inline void __attribute__((always_inline)) aarch64_libc_setup_tls (void) @@ -72,6 +75,9 @@ aarch64_libc_setup_tls (void) _dl_fatal_printf ("failed to lock GCS: %d\n", -ret); } } + + __mte_init (); + } # define ARCH_SETUP_IREL() apply_irel ()