[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