[PATCH v3 1/2] rtld: Enable MTE for stack when specified in .dynamic
Yury Khrustalev
yury.khrustalev@arm.com
Wed Mar 11 10:36:04 GMT 2026
On Tue, Mar 10, 2026 at 04:11:06PM +0200, claudiu.zissulescu-ianculescu@oracle.com wrote:
> From: Cupertino Miranda <cupertino.miranda@oracle.com>
>
> This patch enables Memory Tag Extension (MTE) for stack tagging in the
> rtld. Parse DT_AARCH64_MEMTAG_STACK and DT_AARCH64_MEMTAG_MODE from
> the main program and enable stack memory tagging in the dynamic
> loader, as described in ARM's ABI [1] documentation.
>
> Ref:
> [1] https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst
> ---
> elf/elf.h | 7 +-
> sysdeps/aarch64/Makefile | 1 +
> sysdeps/aarch64/cpu-features.h | 12 +++
> sysdeps/aarch64/dl-mte.c | 85 +++++++++++++++++++
> sysdeps/aarch64/dl-prop.h | 4 +
> sysdeps/unix/sysv/linux/aarch64/Makefile | 4 +
> .../unix/sysv/linux/aarch64/dl-mte-stack.c | 45 ++++++++++
> 7 files changed, 157 insertions(+), 1 deletion(-)
> create mode 100644 sysdeps/aarch64/dl-mte.c
> create mode 100644 sysdeps/unix/sysv/linux/aarch64/dl-mte-stack.c
>
This patch should have at least one test checking that the added
functionality works as intended for each supported mode of stack
tagging. Ideally, we should check both statically-linked and
dynamically-linked cases.
Some notes below. In a nutshell, I think this experimental functionality
should be hidden behind a configure flag or at least a tunable.
Note that there already is a configure flag "--enable-memory-tagging"
which adds -DUSE_MTAG macro and unlock heap tagging in malloc which is
why it's probably not a good idea to use the same guard for stack
tagging.
Whatever way to disable stack tagging is chosen, it should somehow
co-exist with the "--enable-memory-tagging" configure flag and the
corresponding tunable "glibc.mem.tagging". Both of these two things
may change soon to make memory tagging in malloc more usable. For this
reason I would encourage a conversation about how these two things
(tagging of heap and stack) can be controlled independently.
> diff --git a/elf/elf.h b/elf/elf.h
> index 46a01281cb..02c4125cb1 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
>
> ...
>
> diff --git a/sysdeps/aarch64/cpu-features.h b/sysdeps/aarch64/cpu-features.h
> index 1fe35d986b..91e0ce9a90 100644
> --- a/sysdeps/aarch64/cpu-features.h
> +++ b/sysdeps/aarch64/cpu-features.h
> @@ -74,4 +74,16 @@ struct cpu_features
> bool mops;
> };
>
> +#define ARCH_MTE_MODE_SYNC (1 << 1)
> +#define ARCH_MTE_MODE_ASYNC (1 << 2)
These two macros seem to be unused. If they are meant for the possible
values of DT_AARCH64_MEMTAG_MODE, then they would be incorrect because
possible values are 0 for sync and 1 for async mode.
> +#define AARCH64_CPU_FEATURE_MTE_STATE_STACK (1 << 3)
> +
>
> ...
>
> diff --git a/sysdeps/aarch64/dl-mte.c b/sysdeps/aarch64/dl-mte.c
> new file mode 100644
> index 0000000000..e73c5311a6
> --- /dev/null
> +++ b/sysdeps/aarch64/dl-mte.c
>
> ...
>
> +
> +void
> +_dl_mte_stack_check (struct link_map *l,
> + const char *program __attribute__((unused)))
> +{
Shouldn't there be a check for
GLRO(dl_hwcap2) & HWCAP2_MTE
somewhere (not necessarily here)?
> + ElfW (Dyn) *d;
> + bool mte_enabled = false;
> + bool mte_mode_selected = false;
> +
> + for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
> + {
> + if (d->d_tag == DT_AARCH64_MEMTAG_STACK)
> + {
> + GLRO (dl_aarch64_cpu_features).mte_state
> + |= AARCH64_CPU_FEATURE_MTE_STATE_STACK;
This and...
> + mte_enabled = true;
> + }
> + else if (d->d_tag == DT_AARCH64_MEMTAG_MODE)
> + {
> + GLRO (dl_aarch64_cpu_features).mte_state
> + &= ~AARCH64_CPU_FEATURE_MTE_STATE_MODE_MASK;
this conflicts with use of GLRO (dl_aarch64_cpu_features).mte_state for
heap memory tagging in malloc.
I think we should think about combination of these two features: how
will they co-exist and interact.
> + if (d->d_un.d_val == 1)
> + GLRO (dl_aarch64_cpu_features).mte_state
> + |= AARCH64_CPU_FEATURE_MTE_STATE_MODE_ASYNC;
> + else
> + GLRO (dl_aarch64_cpu_features).mte_state
> + |= AARCH64_CPU_FEATURE_MTE_STATE_MODE_SYNC;
> + mte_mode_selected = true;
> + }
> + }
> +
>
> ...
>
> diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-mte-stack.c b/sysdeps/unix/sysv/linux/aarch64/dl-mte-stack.c
> new file mode 100644
> index 0000000000..c93ca6a670
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/aarch64/dl-mte-stack.c
>
> ...
>
> +#define MTE_ALLOWED_TAGS (0xfffe << PR_MTE_TAG_SHIFT)
> +
> +int
> +_dl_mte_mode (void)
> +{
> + int err = 0;
> +
> + if (GLRO (dl_aarch64_cpu_features).mte_state
> + & AARCH64_CPU_FEATURE_MTE_STATE_MODE_SYNC)
> + err = __prctl (PR_SET_TAGGED_ADDR_CTRL,
> + (PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | MTE_ALLOWED_TAGS),
> + 0, 0, 0);
> + else if (GLRO (dl_aarch64_cpu_features).mte_state
> + & AARCH64_CPU_FEATURE_MTE_STATE_MODE_ASYNC)
> + err = __prctl (PR_SET_TAGGED_ADDR_CTRL,
> + (PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC
> + | MTE_ALLOWED_TAGS),
> + 0, 0, 0);
> +
> + return (err != 0
> + && (GLRO (dl_aarch64_cpu_features).mte_state
> + & AARCH64_CPU_FEATURE_MTE_STATE_MODE_MASK) != 0);
Return value is currently unused. What's the model for a failure
returned from the prctl syscall?
> +}
> --
> 2.53.0
>
Kind regards,
Yury
More information about the Libc-alpha
mailing list