[v3,1/2] rtld: Enable MTE for stack when specified in .dynamic
Checks
| Context |
Check |
Description |
| redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
| linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_glibc_check--master-arm |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
fail
|
Test failed
|
Commit Message
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
Comments
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
>
> 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.
A test is provided in the second patch. I can add it to this one.
>
> 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.
I am open for suggestions. A tunable may be a solution, let's see others
input on this topic too.
>> +#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.
Noted.
>> +
>> +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)?
AFAIK, the checking for the MTE capability is done before calling this
function. I'll double check this.
>
>> + 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.
The user application can set it's own MTE behavior, sync or
asynchronous. I can understand this may impact other setting. Shall we
remove this feature from user control, or shall we have it as tunable?
Any other suggestions?
>> +
>> + 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?
>
Any suggestion is welcome here.
Best wishes,
Claudiu
On 11/03/26 07:36, Yury Khrustalev wrote:
> 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.
>
It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
and, given that this is an opt-in feature, I am also not sure whether
adding a configure check would be really worth it here.
A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
use MTE instruction, so running them on hardware without HWCAP2_MTE
is expected to trigger SIGILL (with exceptions for possible
misconfigured environments like qemu with -cpu max and -m virt,mte=off,
and I am not sure how proper hardware is supported to work when MTE
is not enabled by the kernel).
So, the most sensible behavior from the loader standpoint is to abort
startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
the kernel does not support HWCAP2_MTE. A tunable will only mask this
off and not prevent the SIGILL.
The --enable-memory-tagging option differs because glibc can control
whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
be used on hardware without MTE support. I would expect that
DT_AARCH64_MEMTAG_HEAP would enforce its usage.
And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
play along with dlopen. The current approach will:
1. On hardware without MTE, triggers a SIGILL when a binary without
MEMTAG_STACK dlopen a library with MEMTAG_STACK
2. On hardware with MTE, dlopen a MTE will succeed without enabling
MTE on the stack.
For 1. dlopen requires failing similarly to how we do for GCS. The 2.
is technically possible, but implementing it properly requires either
stop-the-work mode (as sanitizers use with ptrace) or some synchronization
between pthread_create and dlopen to change all thread stacks during
process execution without any thread or dlopen altering the global
thread state.
Android does something like that [1] (with
__pthread_internal_remap_stack_with_mte), with a global lock for
pthread/dlopen. I am not sure if we should follow the same semantics.
[1] https://android.googlesource.com/platform/bionic/+/main/docs/mte.md
>
>> 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
On 10/03/26 11:11, 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
>
> diff --git a/elf/elf.h b/elf/elf.h
> index 46a01281cb..02c4125cb1 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -3039,7 +3039,12 @@ enum
> #define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
> #define DT_AARCH64_PAC_PLT (DT_LOPROC + 3)
> #define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
> -#define DT_AARCH64_NUM 6
> +#define DT_AARCH64_MEMTAG_MODE (DT_LOPROC + 9)
> +#define DT_AARCH64_MEMTAG_HEAP (DT_LOPROC + 11)
> +#define DT_AARCH64_MEMTAG_STACK (DT_LOPROC + 12)
> +#define DT_AARCH64_MEMTAG_GLOBALS (DT_LOPROC + 13)
> +#define DT_AARCH64_MEMTAG_GLOBALSSZ (DT_LOPROC + 15)
> +#define DT_AARCH64_NUM 16
>
> /* AArch64 specific values for the st_other field. */
> #define STO_AARCH64_VARIANT_PCS 0x80
> diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
> index d6c5cc96ca..dfbc33d2f4 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 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)
> +#define AARCH64_CPU_FEATURE_MTE_STATE_STACK (1 << 3)
> +
> +#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_MASK (0x3)
> +#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_ASYNC (1)
> +#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_SYNC (1 << 1)
> +
> +#ifndef ARCH_INIT_MEMORY_STACK_TAGGING
> +# define ARCH_INIT_MEMORY_STACK_TAGGING _dl_mte_stack_protect
> +#endif
> +
> #endif /* _CPU_FEATURES_AARCH64_H */
> 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
> @@ -0,0 +1,85 @@
> +/* AArch64 MTE Stack functions.
> + Copyright (C) 2026 Free Software Foundation, Inc.
> +
> + 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 <errno.h>
> +#include <ldsodefs.h>
> +#include <libintl.h>
> +#include <stackinfo.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +
> +extern int _dl_mte_mode (void);
> +
> +void
> +_dl_mte_stack_check (struct link_map *l,
> + const char *program __attribute__((unused)))
> +{
> + 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;
> + 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;
> + 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;
> + }
> + }
This is already done by elf_get_dynamic_info on _dl_map_object_from_fd,
I think it would be better to add a arch-specific hook to set a the
expected mode and enable on dl-procruntime.c instead of parsing this
against here.
> +
> + if (mte_enabled && mte_mode_selected)
> + {
> + int errval = 0;
> + _dl_mte_mode ();
> + GL (dl_stack_prot_flags) |= PROT_MTE;
> +
> + uintptr_t page = ((uintptr_t) __libc_stack_end
> + & -(uintptr_t) GLRO (dl_pagesize));
> +
> + if (__mprotect ((void *) page, GLRO (dl_pagesize),
> + GL (dl_stack_prot_flags)
> +#if _STACK_GROWS_DOWN
> + | PROT_GROWSDOWN
> +#elif _STACK_GROWS_UP
> + | PROT_GROWSUP
> +#endif
This a arch-specific file and aarch64 only supports _STACK_GROWS_DOWN,
there is no need to specify neither flag.
> + ) != 0)
> + errval = errno;
> +
> + if (errval != 0)
> + {
> + const char *name = "MTE Stack";
> + struct dl_exception exception;
> + _dl_exception_create (&exception, name,
> + N_("cannot set stack with PROT_MTE"));
> + _dl_signal_exception (errval, &exception, NULL);
> + }
> + }
> +}
> diff --git a/sysdeps/aarch64/dl-prop.h b/sysdeps/aarch64/dl-prop.h
> index cf236df59b..2ca0fd0f62 100644
> --- a/sysdeps/aarch64/dl-prop.h
> +++ b/sysdeps/aarch64/dl-prop.h
> @@ -27,11 +27,15 @@ extern void _dl_bti_check (struct link_map *, const char *)
> extern void _dl_gcs_check (struct link_map *, const char *, int)
> attribute_hidden;
>
> +extern void _dl_mte_stack_check (struct link_map *, const char *)
> + attribute_hidden;
> +
> static inline void __attribute__ ((always_inline))
> _rtld_main_check (struct link_map *m, const char *program)
> {
> _dl_bti_check (m, program);
> _dl_gcs_check (m, program, 0);
> + _dl_mte_stack_check (m, program);
> }
>
How MTE play with GCS shadow stack? Is is handled transparent by the kernel
or does it need extra userland handling?
> static inline void __attribute__ ((always_inline))
> diff --git a/sysdeps/unix/sysv/linux/aarch64/Makefile b/sysdeps/unix/sysv/linux/aarch64/Makefile
> index 57461fded7..a2e79cf3d6 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/Makefile
> +++ b/sysdeps/unix/sysv/linux/aarch64/Makefile
> @@ -9,6 +9,10 @@ modules-names += \
> LDFLAGS-tst-tlsdesc-pac = -rdynamic
>
> $(objpfx)tst-tlsdesc-pac.out: $(objpfx)tst-tlsdesc-pac-mod.so
> +
> +sysdep-dl-routines += \
> + dl-mte-stack \
> + # sysdep-dl-routines
> endif
>
> ifeq ($(subdir),misc)
> 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
> @@ -0,0 +1,45 @@
> +/* Memory tagging handling for GNU dynamic linker. AArch64 version.
> + 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 <cpu-features.h>
> +#include <ldsodefs.h>
> +#include <sys/prctl.h>
> +
> +#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);
> +}
* Adhemerval
On Fri, Mar 13, 2026 at 03:51:10PM -0300, Adhemerval Zanella Netto wrote:
>
> On 11/03/26 07:36, Yury Khrustalev wrote:
> > 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.
> >
>
> It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
> and, given that this is an opt-in feature, I am also not sure whether
> adding a configure check would be really worth it here.
>
> A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
> use MTE instruction, so running them on hardware without HWCAP2_MTE
> is expected to trigger SIGILL (with exceptions for possible
> misconfigured environments like qemu with -cpu max and -m virt,mte=off,
> and I am not sure how proper hardware is supported to work when MTE
> is not enabled by the kernel).
>
> So, the most sensible behavior from the loader standpoint is to abort
> startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
> the kernel does not support HWCAP2_MTE. A tunable will only mask this
> off and not prevent the SIGILL.
>
> The --enable-memory-tagging option differs because glibc can control
> whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
> be used on hardware without MTE support. I would expect that
> DT_AARCH64_MEMTAG_HEAP would enforce its usage.
>
> And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
> play along with dlopen. The current approach will:
>
> 1. On hardware without MTE, triggers a SIGILL when a binary without
> MEMTAG_STACK dlopen a library with MEMTAG_STACK
>
> 2. On hardware with MTE, dlopen a MTE will succeed without enabling
> MTE on the stack.
>
> For 1. dlopen requires failing similarly to how we do for GCS. The 2.
> is technically possible, but implementing it properly requires either
> stop-the-work mode (as sanitizers use with ptrace) or some synchronization
> between pthread_create and dlopen to change all thread stacks during
> process execution without any thread or dlopen altering the global
> thread state.
>
> Android does something like that [1] (with
> __pthread_internal_remap_stack_with_mte), with a global lock for
> pthread/dlopen. I am not sure if we should follow the same semantics.
>
> [1] https://android.googlesource.com/platform/bionic/+/main/docs/mte.md
Hi Adhemerval, thanks for this input, you raise important points here
but I think you've misunderstood my point entirely here.
Ideally, there should be no --enable-memory-tagging configure option
(and right now we're looking into the best way to remove it) and as for
the glibc.mem.tagging tunable, it should either be gone or do something
else.
The 2nd patch in this series misuses the --enable-memory-tagging configure
option without offering a clear path to separately controlling stack and
heap tagging. I think this is not going to work well.
The question that you are raising above is important one but it is out
of scope here.
Thanks,
Yury
On Thu, Mar 12, 2026 at 12:36:36PM +0200, Claudiu Zissulescu wrote:
> >
> > 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.
>
> A test is provided in the second patch. I can add it to this one.
>
The provided test is for a different use case (setjmp / longjmp). Also,
the way the test is added requires extra work.
> >
> > 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.
>
> I am open for suggestions. A tunable may be a solution, let's see others
> input on this topic too.
My point above was to ask you about what exactly do you expect to happen
here. Is your use case something along the lines of running a sanitizer
in a development environment? Glibc should work on various targets and
in various contexts, and we should not enable a development or a debugging
feature unconditionally and by default.
>
> > > +#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.
>
> Noted.
>
> > > +
> > > +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)?
>
> AFAIK, the checking for the MTE capability is done before calling this
> function. I'll double check this.
>
> >
> > > + 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.
>
> The user application can set it's own MTE behavior, sync or asynchronous. I
> can understand this may impact other setting. Shall we remove this feature
> from user control, or shall we have it as tunable? Any other suggestions?
Again, what is your use case here? What are the requirements that you
want to implement?
Thanks,
Yury
On 16/03/26 06:06, Yury Khrustalev wrote:
> * Adhemerval
>
> On Fri, Mar 13, 2026 at 03:51:10PM -0300, Adhemerval Zanella Netto wrote:
>>
>> On 11/03/26 07:36, Yury Khrustalev wrote:
>>> 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.
>>>
>>
>> It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
>> and, given that this is an opt-in feature, I am also not sure whether
>> adding a configure check would be really worth it here.
>>
>> A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
>> use MTE instruction, so running them on hardware without HWCAP2_MTE
>> is expected to trigger SIGILL (with exceptions for possible
>> misconfigured environments like qemu with -cpu max and -m virt,mte=off,
>> and I am not sure how proper hardware is supported to work when MTE
>> is not enabled by the kernel).
>>
>> So, the most sensible behavior from the loader standpoint is to abort
>> startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
>> the kernel does not support HWCAP2_MTE. A tunable will only mask this
>> off and not prevent the SIGILL.
>>
>> The --enable-memory-tagging option differs because glibc can control
>> whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
>> be used on hardware without MTE support. I would expect that
>> DT_AARCH64_MEMTAG_HEAP would enforce its usage.
>>
>> And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
>> play along with dlopen. The current approach will:
>>
>> 1. On hardware without MTE, triggers a SIGILL when a binary without
>> MEMTAG_STACK dlopen a library with MEMTAG_STACK
>>
>> 2. On hardware with MTE, dlopen a MTE will succeed without enabling
>> MTE on the stack.
>>
>> For 1. dlopen requires failing similarly to how we do for GCS. The 2.
>> is technically possible, but implementing it properly requires either
>> stop-the-work mode (as sanitizers use with ptrace) or some synchronization
>> between pthread_create and dlopen to change all thread stacks during
>> process execution without any thread or dlopen altering the global
>> thread state.
>>
>> Android does something like that [1] (with
>> __pthread_internal_remap_stack_with_mte), with a global lock for
>> pthread/dlopen. I am not sure if we should follow the same semantics.
>>
>> [1] https://android.googlesource.com/platform/bionic/+/main/docs/mte.md
>
> Hi Adhemerval, thanks for this input, you raise important points here
> but I think you've misunderstood my point entirely here.
>
> Ideally, there should be no --enable-memory-tagging configure option
> (and right now we're looking into the best way to remove it) and as for
> the glibc.mem.tagging tunable, it should either be gone or do something
> else.
>
> The 2nd patch in this series misuses the --enable-memory-tagging configure
> option without offering a clear path to separately controlling stack and
> heap tagging. I think this is not going to work well.
I understood that you suggested adding another tunable for Memtag ABI
extension [1], but it seems that I misunderstood.
And I agree that it is time to remove --enable-memory-tagging, and I think
that it has not been done yet because not widely available MTE hardware
support (1), and there is still a minor performance impact when USE_MTAG is
defined (a global variable load plus comparison) (2).
We are starting to see some hardware with MTE support, and qemu now has full
support, so 1. should not be a problem for allowing more testing. I also do
not consider (2) to be an impending issue, although it would be good to have
some performance numbers to know the impact, because memtag changes how malloc
works (it will make __glibc_morecore fallback to mmap more often to allow more
memory to be tagged).
And to enable --enable-memory-tagging we definitely need more testing, since
this is not enabled by default, nor do we have tests that explicitly check the
tunable.
And running a simple test shows that we need to fix some issues before actually
enabling it by default:
$ cat t.c
#include <stdlib.h>
#include <string.h>
int main ()
{
const size_t sz = 128;
void *h = malloc (sz);
memset (h, 0xaa, sz);
free (h);
}
$ gdb -ex "set env GLIBC_TUNABLES=glibc.mem.tagging=1" --args elf/ld.so --library-path . ./t
[...]
(gdb) r
Starting program: /home/azanella/Projects/glibc/build/aarch64-linux-gnu/elf/ld.so --library-path . ./t
warning: Expected absolute pathname for libpthread in the inferior, but got ./libc.so.6.
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
Program received signal SIGSEGV, Segmentation fault
Memory tag violation
Fault address unavailable.
__unregister_atfork (dso_handle=dso_handle@entry=0xfffff7fa0040) at register-atfork.c:83
83 lll_lock (atfork_lock, LLL_PRIVATE);
(gdb) bt
#0 __unregister_atfork (dso_handle=dso_handle@entry=0xfffff7fa0040) at register-atfork.c:83
#1 0x0000fffff7dfddac in __cxa_finalize (d=0xfffff7fa0040) at cxa_finalize.c:120
#2 0x0000fffff7f80800 [PAC] in ?? ()
#3 0x002dfffff7e5cd08 in ?? ()
We made multiple changes to the generic malloc code, and I think memory
tagging support might have been regressed due to insufficient testing.
>
> The question that you are raising above is important one but it is out
> of scope here.
>
> Thanks,
> Yury
>
[1] https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst
On Mon, Mar 16, 2026 at 10:31:56AM -0300, Adhemerval Zanella Netto wrote:
>
> On 16/03/26 06:06, Yury Khrustalev wrote:
> > * Adhemerval
> >
> > On Fri, Mar 13, 2026 at 03:51:10PM -0300, Adhemerval Zanella Netto wrote:
> >>
> >> On 11/03/26 07:36, Yury Khrustalev wrote:
> >>> 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.
> >>>
> >>
> >> ...
> >>
> >> It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
> >> and, given that this is an opt-in feature, I am also not sure whether
> >> adding a configure check would be really worth it here.
> >>
> >> A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
> >> use MTE instruction, so running them on hardware without HWCAP2_MTE
> >> is expected to trigger SIGILL (with exceptions for possible
> >> misconfigured environments like qemu with -cpu max and -m virt,mte=off,
> >> and I am not sure how proper hardware is supported to work when MTE
> >> is not enabled by the kernel).
> >>
> >> So, the most sensible behavior from the loader standpoint is to abort
> >> startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
> >> the kernel does not support HWCAP2_MTE. A tunable will only mask this
> >> off and not prevent the SIGILL.
> >>
> >> The --enable-memory-tagging option differs because glibc can control
> >> whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
> >> be used on hardware without MTE support. I would expect that
> >> DT_AARCH64_MEMTAG_HEAP would enforce its usage.
> >>
> >> And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
> >> play along with dlopen. The current approach will:
> >>
> >> 1. On hardware without MTE, triggers a SIGILL when a binary without
> >> MEMTAG_STACK dlopen a library with MEMTAG_STACK
> >>
> >> 2. On hardware with MTE, dlopen a MTE will succeed without enabling
> >> MTE on the stack.
> >>
> >> For 1. dlopen requires failing similarly to how we do for GCS. The 2.
> >> is technically possible, but implementing it properly requires either
> >> stop-the-work mode (as sanitizers use with ptrace) or some synchronization
> >> between pthread_create and dlopen to change all thread stacks during
> >> process execution without any thread or dlopen altering the global
> >> thread state.
> >>
> >> Android does something like that [1] (with
> >> __pthread_internal_remap_stack_with_mte), with a global lock for
> >> pthread/dlopen. I am not sure if we should follow the same semantics.
> >>
> >> [1] https://android.googlesource.com/platform/bionic/+/main/docs/mte.md
> >
> > Hi Adhemerval, thanks for this input, you raise important points here
> > but I think you've misunderstood my point entirely here.
> >
> > Ideally, there should be no --enable-memory-tagging configure option
> > (and right now we're looking into the best way to remove it) and as for
> > the glibc.mem.tagging tunable, it should either be gone or do something
> > else.
> >
> > The 2nd patch in this series misuses the --enable-memory-tagging configure
> > option without offering a clear path to separately controlling stack and
> > heap tagging. I think this is not going to work well.
>
> I understood that you suggested adding another tunable for Memtag ABI
> extension [1], but it seems that I misunderstood.
I was just saying we need some form for control over when the proposed
stack tagging is enabled. There is no *defined* ABI for stack tagging, so
it either have to be done in a way that doesn't require any Glibc changes
or we have to make it disabled by default and only enabled on demand and
explicitly.
Whether to use configure flag or tunable or something else, we can
consider various options.
> And I agree that it is time to remove --enable-memory-tagging, and I think
> that it has not been done yet because not widely available MTE hardware
> support (1), and there is still a minor performance impact when USE_MTAG is
> defined (a global variable load plus comparison) (2).
I am working on this right now, but it's not an easy thing to do. We
certainly don't want to just delete #ifdef USE_MTAG, it has to be more
tricky than that.
> We are starting to see some hardware with MTE support, and qemu now has full
> support, so 1. should not be a problem for allowing more testing. I also do
> not consider (2) to be an impending issue, although it would be good to have
> some performance numbers to know the impact, because memtag changes how malloc
> works (it will make __glibc_morecore fallback to mmap more often to allow more
> memory to be tagged).
>
> And to enable --enable-memory-tagging we definitely need more testing, since
> this is not enabled by default, nor do we have tests that explicitly check the
> tunable.
>
> And running a simple test shows that we need to fix some issues before actually
> enabling it by default:
>
>
> ...
>
> We made multiple changes to the generic malloc code, and I think memory
> tagging support might have been regressed due to insufficient testing.
Exactly, and sorting this out will require some work. Adding support for
stack tagging should not be just bolted on the existing code. It should
either be entirely independent of the malloc part (including things like
USE_MTAG) or it would have to wait till existing code has been
refactored and under regular testing.
On 16/03/26 11:08, Yury Khrustalev wrote:
> On Mon, Mar 16, 2026 at 10:31:56AM -0300, Adhemerval Zanella Netto wrote:
>>
>> On 16/03/26 06:06, Yury Khrustalev wrote:
>>> * Adhemerval
>>>
>>> On Fri, Mar 13, 2026 at 03:51:10PM -0300, Adhemerval Zanella Netto wrote:
>>>>
>>>> On 11/03/26 07:36, Yury Khrustalev wrote:
>>>>> 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.
>>>>>
>>>>
>>>> ...
>>>>
>>>> It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
>>>> and, given that this is an opt-in feature, I am also not sure whether
>>>> adding a configure check would be really worth it here.
>>>>
>>>> A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
>>>> use MTE instruction, so running them on hardware without HWCAP2_MTE
>>>> is expected to trigger SIGILL (with exceptions for possible
>>>> misconfigured environments like qemu with -cpu max and -m virt,mte=off,
>>>> and I am not sure how proper hardware is supported to work when MTE
>>>> is not enabled by the kernel).
>>>>
>>>> So, the most sensible behavior from the loader standpoint is to abort
>>>> startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
>>>> the kernel does not support HWCAP2_MTE. A tunable will only mask this
>>>> off and not prevent the SIGILL.
>>>>
>>>> The --enable-memory-tagging option differs because glibc can control
>>>> whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
>>>> be used on hardware without MTE support. I would expect that
>>>> DT_AARCH64_MEMTAG_HEAP would enforce its usage.
>>>>
>>>> And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
>>>> play along with dlopen. The current approach will:
>>>>
>>>> 1. On hardware without MTE, triggers a SIGILL when a binary without
>>>> MEMTAG_STACK dlopen a library with MEMTAG_STACK
>>>>
>>>> 2. On hardware with MTE, dlopen a MTE will succeed without enabling
>>>> MTE on the stack.
>>>>
>>>> For 1. dlopen requires failing similarly to how we do for GCS. The 2.
>>>> is technically possible, but implementing it properly requires either
>>>> stop-the-work mode (as sanitizers use with ptrace) or some synchronization
>>>> between pthread_create and dlopen to change all thread stacks during
>>>> process execution without any thread or dlopen altering the global
>>>> thread state.
>>>>
>>>> Android does something like that [1] (with
>>>> __pthread_internal_remap_stack_with_mte), with a global lock for
>>>> pthread/dlopen. I am not sure if we should follow the same semantics.
>>>>
>>>> [1] https://android.googlesource.com/platform/bionic/+/main/docs/mte.md
>>>
>>> Hi Adhemerval, thanks for this input, you raise important points here
>>> but I think you've misunderstood my point entirely here.
>>>
>>> Ideally, there should be no --enable-memory-tagging configure option
>>> (and right now we're looking into the best way to remove it) and as for
>>> the glibc.mem.tagging tunable, it should either be gone or do something
>>> else.
>>>
>>> The 2nd patch in this series misuses the --enable-memory-tagging configure
>>> option without offering a clear path to separately controlling stack and
>>> heap tagging. I think this is not going to work well.
>>
>> I understood that you suggested adding another tunable for Memtag ABI
>> extension [1], but it seems that I misunderstood.
>
> I was just saying we need some form for control over when the proposed
> stack tagging is enabled. There is no *defined* ABI for stack tagging, so
> it either have to be done in a way that doesn't require any Glibc changes
> or we have to make it disabled by default and only enabled on demand and
> explicitly.
>
> Whether to use configure flag or tunable or something else, we can
> consider various options.
As I said the tunable does not make sense in this context. If we really
do not want to commit to the current AArch64 Memtag ABI, best course of
action is to add a configure check (--enable-experimental-memtag or
something), that enables the handling of DT_AARCH64_MEMTAG_*.
It seems that Android already is implement is as non-experimental, and
it moves from the system specific .note.android.memtag to the Memtag
in recent versions.
>
>> And I agree that it is time to remove --enable-memory-tagging, and I think
>> that it has not been done yet because not widely available MTE hardware
>> support (1), and there is still a minor performance impact when USE_MTAG is
>> defined (a global variable load plus comparison) (2).
>
> I am working on this right now, but it's not an easy thing to do. We
> certainly don't want to just delete #ifdef USE_MTAG, it has to be more
> tricky than that.
>
>> We are starting to see some hardware with MTE support, and qemu now has full
>> support, so 1. should not be a problem for allowing more testing. I also do
>> not consider (2) to be an impending issue, although it would be good to have
>> some performance numbers to know the impact, because memtag changes how malloc
>> works (it will make __glibc_morecore fallback to mmap more often to allow more
>> memory to be tagged).
>>
>> And to enable --enable-memory-tagging we definitely need more testing, since
>> this is not enabled by default, nor do we have tests that explicitly check the
>> tunable.
>>
>> And running a simple test shows that we need to fix some issues before actually
>> enabling it by default:
>>
>>
>> ...
>>
>> We made multiple changes to the generic malloc code, and I think memory
>> tagging support might have been regressed due to insufficient testing.
>
> Exactly, and sorting this out will require some work. Adding support for
> stack tagging should not be just bolted on the existing code. It should
> either be entirely independent of the malloc part (including things like
> USE_MTAG) or it would have to wait till existing code has been
> refactored and under regular testing.
I agree and my previous comments are not really for this part.
On Mon, Mar 16, 2026 at 11:19:20AM -0300, Adhemerval Zanella Netto wrote:
> >>>
> >>> ...
> >>>
> >>> Hi Adhemerval, thanks for this input, you raise important points here
> >>> but I think you've misunderstood my point entirely here.
> >>>
> >>> Ideally, there should be no --enable-memory-tagging configure option
> >>> (and right now we're looking into the best way to remove it) and as for
> >>> the glibc.mem.tagging tunable, it should either be gone or do something
> >>> else.
> >>>
> >>> The 2nd patch in this series misuses the --enable-memory-tagging configure
> >>> option without offering a clear path to separately controlling stack and
> >>> heap tagging. I think this is not going to work well.
> >>
> >> I understood that you suggested adding another tunable for Memtag ABI
> >> extension [1], but it seems that I misunderstood.
> >
> > I was just saying we need some form for control over when the proposed
> > stack tagging is enabled. There is no *defined* ABI for stack tagging, so
> > it either have to be done in a way that doesn't require any Glibc changes
> > or we have to make it disabled by default and only enabled on demand and
> > explicitly.
> >
> > Whether to use configure flag or tunable or something else, we can
> > consider various options.
>
> As I said the tunable does not make sense in this context.
I hear you, but I disagree, however this is not in this scope, let's
discuss it elsewhere.
> If we really
> do not want to commit to the current AArch64 Memtag ABI,
We really cannot: that ABI has been ALPHA which means it's unstable and
is subject to change.
> best course of
> action is to add a configure check (--enable-experimental-memtag or
> something), that enables the handling of DT_AARCH64_MEMTAG_*.
I'm happy to consider that, but DT_AARCH64_MEMTAG_* includes not only
stack but also heap, globals, and so on. If we make a point of
implementing this ABI (even if under an "experimental" flag), we should
implement it consistently.
Furthermore, if we look at the dynamic array tags, question is, what do
we do with static binaries? We already have GNU properties for other
features, so it might be reasonable to do the same for memory tagging.
Which means we should not really support DT_AARCH64_MEMTAG_* in Glibc at
all (not even experimentally).
We should discuss all these questions, come to some consensus and then
come back to this patch (or rather its updated version).
On 16/03/26 11:32, Yury Khrustalev wrote:
> On Mon, Mar 16, 2026 at 11:19:20AM -0300, Adhemerval Zanella Netto wrote:
>>>>>
>>>>> ...
>>>>>
>>>>> Hi Adhemerval, thanks for this input, you raise important points here
>>>>> but I think you've misunderstood my point entirely here.
>>>>>
>>>>> Ideally, there should be no --enable-memory-tagging configure option
>>>>> (and right now we're looking into the best way to remove it) and as for
>>>>> the glibc.mem.tagging tunable, it should either be gone or do something
>>>>> else.
>>>>>
>>>>> The 2nd patch in this series misuses the --enable-memory-tagging configure
>>>>> option without offering a clear path to separately controlling stack and
>>>>> heap tagging. I think this is not going to work well.
>>>>
>>>> I understood that you suggested adding another tunable for Memtag ABI
>>>> extension [1], but it seems that I misunderstood.
>>>
>>> I was just saying we need some form for control over when the proposed
>>> stack tagging is enabled. There is no *defined* ABI for stack tagging, so
>>> it either have to be done in a way that doesn't require any Glibc changes
>>> or we have to make it disabled by default and only enabled on demand and
>>> explicitly.
>>>
>>> Whether to use configure flag or tunable or something else, we can
>>> consider various options.
>>
>> As I said the tunable does not make sense in this context.
>
> I hear you, but I disagree, however this is not in this scope, let's
> discuss it elsewhere.
>
>> If we really
>> do not want to commit to the current AArch64 Memtag ABI,
>
> We really cannot: that ABI has been ALPHA which means it's unstable and
> is subject to change.
It is not clear to me exactly what you think we not commit wrt current
AArch64 Memtag ABI. Both gcc and clang support DT_AARCH64_MEMTAG_* for a
while, and even Memtag ABI Extension is not fully clear about all runtime
behavior compile support is ready and current definitions are reasonable.
For DT_AARCH64_MEMTAG_STACK it defines that:
"If DT_AARCH64_MEMTAG_STACK is present, the dynamic loader should enable
tagging for the main stack and thread stacks. Re-mapping currently alive
stack frames as taggable is dangerous."
I tend to agree with this and I think we should *not* follow Android that
allows stack remapping during process execution.
There is an extra care for audit modules and ldproload modules, since they
are loaded *before* executable dynamic tags parsing that we will require
extra care.
>
>> best course of
>> action is to add a configure check (--enable-experimental-memtag or
>> something), that enables the handling of DT_AARCH64_MEMTAG_*.
>
> I'm happy to consider that, but DT_AARCH64_MEMTAG_* includes not only
> stack but also heap, globals, and so on. If we make a point of
> implementing this ABI (even if under an "experimental" flag), we should
> implement it consistently.
>
> Furthermore, if we look at the dynamic array tags, question is, what do
> we do with static binaries? We already have GNU properties for other
> features, so it might be reasonable to do the same for memory tagging.
> Which means we should not really support DT_AARCH64_MEMTAG_* in Glibc at
> all (not even experimentally).
>
> We should discuss all these questions, come to some consensus and then
> come back to this patch (or rather its updated version).
>
>
On Mon, Mar 16, 2026 at 11:43:03AM -0300, Adhemerval Zanella Netto wrote:
>
> ...
>
> > We really cannot: that ABI has been ALPHA which means it's unstable and
> > is subject to change.
>
> It is not clear to me exactly what you think we not commit wrt current
> AArch64 Memtag ABI.
Adhemerval, if you read the document [1], you will surely see (section
3. Scope):
As an alpha document all details in this document are subject to change.
I really don't know what else to add here. My understanding was that
Glibc does not add implementation for unstable ABI as a rule...
> Both gcc and clang support DT_AARCH64_MEMTAG_* for a
> while, and even Memtag ABI Extension is not fully clear about all runtime
> behavior compile support is ready and current definitions are reasonable.
What exactly is implemented in gcc and clang with respect to stack
tagging? There is an implementation in GCC that doesn't seem to be
documented anywhere (at least I couldn't find any relevant spec).
For example, could you please point me to a place in [1] that explains
what is expected to happen in longjmp / setjmp?
We could use [1] as a vehicle to explore various options, but we should
not really use this document as the only reason to merge related changes
upstream.
[1]: https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst
On 16/03/26 12:12, Yury Khrustalev wrote:
> On Mon, Mar 16, 2026 at 11:43:03AM -0300, Adhemerval Zanella Netto wrote:
>>
>> ...
>>
>>> We really cannot: that ABI has been ALPHA which means it's unstable and
>>> is subject to change.
>>
>> It is not clear to me exactly what you think we not commit wrt current
>> AArch64 Memtag ABI.
>
> Adhemerval, if you read the document [1], you will surely see (section
> 3. Scope):
>
> As an alpha document all details in this document are subject to change.
>
> I really don't know what else to add here. My understanding was that
> Glibc does not add implementation for unstable ABI as a rule...
>
>> Both gcc and clang support DT_AARCH64_MEMTAG_* for a
>> while, and even Memtag ABI Extension is not fully clear about all runtime
>> behavior compile support is ready and current definitions are reasonable.
>
> What exactly is implemented in gcc and clang with respect to stack
> tagging? There is an implementation in GCC that doesn't seem to be
> documented anywhere (at least I couldn't find any relevant spec).
The gcc has a wiki describing the planned support [1]. And gcc-16 has
support -fsanitize=memtag-stack, which pass z memtag-stack to enable
DT_AARCH64_MEMTAG_STACK creation.
>
> For example, could you please point me to a place in [1] that explains
> what is expected to happen in longjmp / setjmp?
My understanding is Memtag ABI Extension to *ELF* do not, and I expect
not to, get into detail about the semantic of a *C* function. The documentation
is runtime neutral, so it should up to the implementers.
>
> We could use [1] as a vehicle to explore various options, but we should
> not really use this document as the only reason to merge related changes
> upstream.
>
> [1]: https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst
>
[1] https://gcc.gnu.org/wiki/MTE
On 13/03/26 15:51, Adhemerval Zanella Netto wrote:
>
>
> On 11/03/26 07:36, Yury Khrustalev wrote:
>> 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.
>>
>
> It does not make sense to add a tunable for DT_AARCH64_MEMTAG_STACK,
> and, given that this is an opt-in feature, I am also not sure whether
> adding a configure check would be really worth it here.
>
> A binary with DT_AARCH64_MEMTAG_STACK has text segments that always
> use MTE instruction, so running them on hardware without HWCAP2_MTE
> is expected to trigger SIGILL (with exceptions for possible
> misconfigured environments like qemu with -cpu max and -m virt,mte=off,
> and I am not sure how proper hardware is supported to work when MTE
> is not enabled by the kernel).
>
> So, the most sensible behavior from the loader standpoint is to abort
> startup with a proper error if DT_AARCH64_MEMTAG_STACK is present and
> the kernel does not support HWCAP2_MTE. A tunable will only mask this
> off and not prevent the SIGILL.
>
> The --enable-memory-tagging option differs because glibc can control
> whether to tag memory (sysdeps/aarch64/libc-mtag.h), so it malloc can
> be used on hardware without MTE support. I would expect that
> DT_AARCH64_MEMTAG_HEAP would enforce its usage.
>
> And I think we also need to define how DT_AARCH64_MEMTAG_STACK will
> play along with dlopen. The current approach will:
>
> 1. On hardware without MTE, triggers a SIGILL when a binary without
> MEMTAG_STACK dlopen a library with MEMTAG_STACK
>
> 2. On hardware with MTE, dlopen a MTE will succeed without enabling
> MTE on the stack.
Beside these points, I think we need to sort other missing semantics:
3. How should glibc handle other DT_AARCH64_MEMTAG_* with only
DT_AARCH64_MEMTAG_STACK support? Should we just ignore (and allowing
possible SIGILL during process execution) or should abort at process
startup (fail early)? Same for dlopen case for 1. and 2.
4. How should audit/DT_AUDIT module should act wrt DT_AARCH64_MEMTAG_*?
They are loaded before the main program and it might require to either
always enable MTE or fail if process does not have the Memtag ABI.
5. Same as 4. but for preload/LD_PRELOAD.
6. How should have running binaries with DT_AARCH64_MEMTAG_* on old
glibc releases? For DT_RELR we ended up adding a glibc specific symbol
version (GLIBC_ABI_DT_RELR), and I think we should also consider doing
the same here.
On 3/16/26 11:10 AM, Yury Khrustalev wrote:
> On Thu, Mar 12, 2026 at 12:36:36PM +0200, Claudiu Zissulescu wrote:
>>>
>>> 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.
>>
>> A test is provided in the second patch. I can add it to this one.
>>
>
> The provided test is for a different use case (setjmp / longjmp). Also,
> the way the test is added requires extra work.
The patch has two tests, one for setjmp/longjmp, and the second one for
the mte stack in general.
The tst-mte-jmp.c is testing setjmp/longjmp.
The tst-mte-stack.c is checking if the stack is correctly set with MTE
flag. The test is placing a mte guarded array on the stack, it uses it,
and finally reads the array beyond the array range. If the stack is not
MTE enabled, the test will continue and exit with an error. If the stack
is MTE enabled, an exception is risen, and the test is successfully.
>> The user application can set it's own MTE behavior, sync or asynchronous. I
>> can understand this may impact other setting. Shall we remove this feature
>> from user control, or shall we have it as tunable? Any other suggestions?
>
> Again, what is your use case here? What are the requirements that you
> want to implement?
Enabling stack protection using MTE, in the same way the stack is
enabled to be executable.
Cheers,
Claudiu
> What exactly is implemented in gcc and clang with respect to stack
> tagging? There is an implementation in GCC that doesn't seem to be
> documented anywhere (at least I couldn't find any relevant spec).
>
The MTE in compilers is an old topic (at least 6 yo) see[1]. Regarding
exceptions (longjmp/setjmp) is also a long discussion see[2]. The
present patch in glibc is almost 1 yo. Also, the gnu support has been
presented in the last Cauldron.
Ref
[1] https://llvm.org/docs/MemTagSanitizer.html
[2]
https://discourse.llvm.org/t/mte-discussion-on-exception-unwinding-abi/55226
@@ -3039,7 +3039,12 @@ enum
#define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
#define DT_AARCH64_PAC_PLT (DT_LOPROC + 3)
#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
-#define DT_AARCH64_NUM 6
+#define DT_AARCH64_MEMTAG_MODE (DT_LOPROC + 9)
+#define DT_AARCH64_MEMTAG_HEAP (DT_LOPROC + 11)
+#define DT_AARCH64_MEMTAG_STACK (DT_LOPROC + 12)
+#define DT_AARCH64_MEMTAG_GLOBALS (DT_LOPROC + 13)
+#define DT_AARCH64_MEMTAG_GLOBALSSZ (DT_LOPROC + 15)
+#define DT_AARCH64_NUM 16
/* AArch64 specific values for the st_other field. */
#define STO_AARCH64_VARIANT_PCS 0x80
@@ -4,6 +4,7 @@ ifeq ($(subdir),elf)
sysdep-dl-routines += \
dl-bti \
dl-gcs \
+ dl-mte \
# sysdep-dl-routines
tests += \
@@ -74,4 +74,16 @@ struct cpu_features
bool mops;
};
+#define ARCH_MTE_MODE_SYNC (1 << 1)
+#define ARCH_MTE_MODE_ASYNC (1 << 2)
+#define AARCH64_CPU_FEATURE_MTE_STATE_STACK (1 << 3)
+
+#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_MASK (0x3)
+#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_ASYNC (1)
+#define AARCH64_CPU_FEATURE_MTE_STATE_MODE_SYNC (1 << 1)
+
+#ifndef ARCH_INIT_MEMORY_STACK_TAGGING
+# define ARCH_INIT_MEMORY_STACK_TAGGING _dl_mte_stack_protect
+#endif
+
#endif /* _CPU_FEATURES_AARCH64_H */
new file mode 100644
@@ -0,0 +1,85 @@
+/* AArch64 MTE Stack functions.
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ 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 <errno.h>
+#include <ldsodefs.h>
+#include <libintl.h>
+#include <stackinfo.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+extern int _dl_mte_mode (void);
+
+void
+_dl_mte_stack_check (struct link_map *l,
+ const char *program __attribute__((unused)))
+{
+ 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;
+ 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;
+ 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;
+ }
+ }
+
+ if (mte_enabled && mte_mode_selected)
+ {
+ int errval = 0;
+ _dl_mte_mode ();
+ GL (dl_stack_prot_flags) |= PROT_MTE;
+
+ uintptr_t page = ((uintptr_t) __libc_stack_end
+ & -(uintptr_t) GLRO (dl_pagesize));
+
+ if (__mprotect ((void *) page, GLRO (dl_pagesize),
+ GL (dl_stack_prot_flags)
+#if _STACK_GROWS_DOWN
+ | PROT_GROWSDOWN
+#elif _STACK_GROWS_UP
+ | PROT_GROWSUP
+#endif
+ ) != 0)
+ errval = errno;
+
+ if (errval != 0)
+ {
+ const char *name = "MTE Stack";
+ struct dl_exception exception;
+ _dl_exception_create (&exception, name,
+ N_("cannot set stack with PROT_MTE"));
+ _dl_signal_exception (errval, &exception, NULL);
+ }
+ }
+}
@@ -27,11 +27,15 @@ extern void _dl_bti_check (struct link_map *, const char *)
extern void _dl_gcs_check (struct link_map *, const char *, int)
attribute_hidden;
+extern void _dl_mte_stack_check (struct link_map *, const char *)
+ attribute_hidden;
+
static inline void __attribute__ ((always_inline))
_rtld_main_check (struct link_map *m, const char *program)
{
_dl_bti_check (m, program);
_dl_gcs_check (m, program, 0);
+ _dl_mte_stack_check (m, program);
}
static inline void __attribute__ ((always_inline))
@@ -9,6 +9,10 @@ modules-names += \
LDFLAGS-tst-tlsdesc-pac = -rdynamic
$(objpfx)tst-tlsdesc-pac.out: $(objpfx)tst-tlsdesc-pac-mod.so
+
+sysdep-dl-routines += \
+ dl-mte-stack \
+ # sysdep-dl-routines
endif
ifeq ($(subdir),misc)
new file mode 100644
@@ -0,0 +1,45 @@
+/* Memory tagging handling for GNU dynamic linker. AArch64 version.
+ 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 <cpu-features.h>
+#include <ldsodefs.h>
+#include <sys/prctl.h>
+
+#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);
+}