mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
aarch64: Add initial Memtag ABI Extension to ELF (stack only)
This patch introduces initial support for the AArch64 Memory Tagging Extension (MTE) in the dynamic linker, implementing stack tagging (DT_AARCH64_MEMTAG_STACK) and MTE mode configuration (DT_AARCH64_MEMTAG_MODE) as defined in the Memtag ABI Extension for ELF64 [1]. The feature is guarded by a new configure option, --enable-aarch64-memtag-abi, and it is disabled by default. Semantics: * The MTE stack protection is enabled if and only if the main executable (PDE/PIE) is marked with DT_AARCH64_MEMTAG_STACK. * If the main executable is not marked and any dependency requires MTE stack protection, the dynamic loader aborts at startup. * Any unsupported marking (DT_AARCH64_MEMTAG_HEAP or DT_AARCH64_MEMTAG_GLOBALS), and any invalid or inconsistent (orphan) set of DT_AARCH64_MEMTAG_xxx dynamic tags, on either the main executable or any dependency, aborts the startup. * The MTE execution mode is defined by DT_AARCH64_MEMTAG_MODE of the main executable; if absent, asynchronous mode is used. * If the main executable did not enable the MTE stack protection at startup, any subsequent dlopen of a shared object that requires it is rejected to prevent unsafe memory access. Static PDEs are not supported since they carry no dynamic tags. [1] https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst
This commit is contained in:
@@ -279,6 +279,15 @@ passed to 'configure'. For example:
|
||||
|
||||
Default is to disable SFrame support.
|
||||
|
||||
'--enable-aarch64-memtag-abi'
|
||||
Enable initial support for the AArch64 Memory Tagging Extension
|
||||
(MTE) ABI. The option implements stack tagging
|
||||
(DT_AARCH64_MEMTAG_STACK) and MTE execution mode configuration
|
||||
(DT_AARCH64_MEMTAG_MODE) as defined in the Memtag ABI Extension for
|
||||
ELF64.
|
||||
|
||||
This option is disabled by default and only supported on aarch64.
|
||||
|
||||
To build the library and related programs, type 'make'. This will
|
||||
produce a lot of output, some of which may look like errors from 'make'
|
||||
but aren't. Look for error messages from 'make' containing '***'.
|
||||
|
||||
@@ -90,6 +90,11 @@ Major new features:
|
||||
|
||||
* A new locale has been added: hrx_BR (Hunsrik language spoken in Brazil).
|
||||
|
||||
* AArch64 now has initial support for the Memtag ABI Extension for ELF64,
|
||||
specifically handling stack tagging (DT_AARCH64_MEMTAG_STACK) and execution
|
||||
mode configuration (DT_AARCH64_MEMTAG_MODE). It can be enabled with the
|
||||
new --enable-aarch64-memtag-abi configure option.
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* Although malloc and related functions currently return pointers
|
||||
|
||||
@@ -182,6 +182,9 @@
|
||||
/* Define if inlined system calls are available. */
|
||||
#undef HAVE_INLINED_SYSCALLS
|
||||
|
||||
/* Define if AArch64 Memtag ABI extension should be enabled. */
|
||||
#undef USE_AARCH64_MEMTAG_ABI
|
||||
|
||||
/* Package description. */
|
||||
#undef PKGVERSION
|
||||
|
||||
|
||||
@@ -78,6 +78,8 @@ multi-arch = @multi_arch@
|
||||
|
||||
mach-interface-list = @mach_interface_list@
|
||||
|
||||
aarch64-memtag-abi = @aarch64_memtag_abi@
|
||||
|
||||
# Configuration options.
|
||||
build-shared = @shared@
|
||||
build-profile = @profile@
|
||||
|
||||
@@ -702,6 +702,7 @@ INSTALL_PROGRAM
|
||||
base_machine
|
||||
build_pt_chown
|
||||
build_nscd
|
||||
aarch64_memtag_abi
|
||||
enable_werror
|
||||
force_install
|
||||
bindnow
|
||||
@@ -808,6 +809,7 @@ enable_maintainer_mode
|
||||
enable_kernel
|
||||
enable_werror
|
||||
enable_multi_arch
|
||||
enable_aarch64_memtag_abi
|
||||
enable_systemtap
|
||||
enable_build_nscd
|
||||
enable_nscd
|
||||
@@ -1485,6 +1487,9 @@ Optional Features:
|
||||
--disable-werror do not build with -Werror
|
||||
--enable-multi-arch enable single DSO with optimizations for multiple
|
||||
architectures
|
||||
--enable-aarch64-memtag-abi
|
||||
enable AArch64 Memtag ABI Extension for ELF
|
||||
[default=no]
|
||||
--enable-systemtap enable systemtap static probe points [default=no]
|
||||
--disable-build-nscd disable building and installing the nscd daemon
|
||||
--disable-nscd library functions will not contact the nscd daemon
|
||||
@@ -4668,6 +4673,25 @@ esac
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-aarch64-memtag-abi was given.
|
||||
if test ${enable_aarch64_memtag_abi+y}
|
||||
then :
|
||||
enableval=$enable_aarch64_memtag_abi; aarch64_memtag_abi=$enableval
|
||||
else case e in #(
|
||||
e) aarch64_memtag_abi=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$aarch64_memtag_abi" = yes; then
|
||||
case $host_cpu in
|
||||
aarch64)
|
||||
printf "%s\n" "#define USE_AARCH64_MEMTAG_ABI 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-systemtap was given.
|
||||
if test ${enable_systemtap+y}
|
||||
then :
|
||||
|
||||
@@ -315,6 +315,20 @@ AC_ARG_ENABLE([multi-arch],
|
||||
[multi_arch=$enableval],
|
||||
[multi_arch=default])
|
||||
|
||||
AC_ARG_ENABLE([aarch64-memtag-abi],
|
||||
AS_HELP_STRING([--enable-aarch64-memtag-abi],
|
||||
[enable AArch64 Memtag ABI Extension for ELF @<:@default=no@:>@]),
|
||||
[aarch64_memtag_abi=$enableval],
|
||||
[aarch64_memtag_abi=no])
|
||||
if test "$aarch64_memtag_abi" = yes; then
|
||||
case $host_cpu in
|
||||
aarch64)
|
||||
AC_DEFINE(USE_AARCH64_MEMTAG_ABI)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
AC_SUBST(aarch64_memtag_abi)
|
||||
|
||||
AC_ARG_ENABLE([systemtap],
|
||||
[AS_HELP_STRING([--enable-systemtap],
|
||||
[enable systemtap static probe points @<:@default=no@:>@])],
|
||||
|
||||
@@ -28,6 +28,13 @@ libc {
|
||||
# by scripts/versions.awk.
|
||||
__placeholder_only_for_empty_version_map;
|
||||
}
|
||||
%ifdef USE_AARCH64_MEMTAG_ABI
|
||||
GLIBC_ABI_MEMTAG {
|
||||
# This symbol is used only for empty version map and will be removed
|
||||
# by scripts/versions.awk.
|
||||
__placeholder_only_for_empty_version_map;
|
||||
}
|
||||
%endif
|
||||
GLIBC_PRIVATE {
|
||||
# functions used in other libraries
|
||||
__libc_early_init;
|
||||
|
||||
@@ -3041,7 +3041,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
|
||||
|
||||
@@ -309,6 +309,29 @@ Currently this is only supported on x86_64 and aarch64. The option
|
||||
enables SFrame support on @code{backtrace}.
|
||||
|
||||
Default is to disable SFrame support.
|
||||
|
||||
@item --enable-aarch64-memtag-abi
|
||||
Enable initial support for the AArch64 Memory Tagging Extension (MTE) ABI.
|
||||
The option implements stack tagging (@code{DT_AARCH64_MEMTAG_STACK}) and MTE
|
||||
execution mode configuration (@code{DT_AARCH64_MEMTAG_MODE}) as defined in
|
||||
the Memtag ABI Extension for ELF64.
|
||||
|
||||
The MTE stack protection is enabled if and only if the main executable is
|
||||
marked with @code{DT_AARCH64_MEMTAG_STACK}. If the main executable is not
|
||||
marked and any dependency requires MTE stack protection, the program fails
|
||||
at startup. The program also fails at startup if any object carries an
|
||||
unsupported marking (@code{DT_AARCH64_MEMTAG_HEAP} or
|
||||
@code{DT_AARCH64_MEMTAG_GLOBALS}), or an invalid or inconsistent set of
|
||||
@code{DT_AARCH64_MEMTAG_xxx} dynamic tags.
|
||||
|
||||
If the execution mode is not specified with @code{DT_AARCH64_MEMTAG_MODE},
|
||||
the asynchronous mode is used.
|
||||
|
||||
If the main executable does not enable the MTE stack protection at startup,
|
||||
any subsequent attempt to @code{dlopen} a shared object that requires it
|
||||
will be rejected.
|
||||
|
||||
This option is disabled by default and only supported on aarch64.
|
||||
@end table
|
||||
|
||||
To build the library and related programs, type @code{make}. This will
|
||||
|
||||
@@ -4,6 +4,7 @@ ifeq ($(subdir),elf)
|
||||
sysdep-dl-routines += \
|
||||
dl-bti \
|
||||
dl-gcs \
|
||||
dl-mte \
|
||||
# sysdep-dl-routines
|
||||
|
||||
tests += \
|
||||
|
||||
Vendored
+191
@@ -484,3 +484,194 @@ else
|
||||
have-test-gcs = no"
|
||||
fi
|
||||
|
||||
# Check if compiler supports MEMTAG stack support. Also check if linker
|
||||
# support the required options.
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports -fsanitize=memtag-stack" >&5
|
||||
printf %s "checking if compiler supports -fsanitize=memtag-stack... " >&6; }
|
||||
if test ${libc_cv_cc_memtag_stack+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e) if { ac_try='${CC-cc} -Werror -march=armv8.5-a+memtag -fsanitize=memtag-stack -xc /dev/null -S -o /dev/null'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then :
|
||||
libc_cv_cc_memtag_stack=yes
|
||||
else case e in #(
|
||||
e) libc_cv_cc_memtag_stack=no ;;
|
||||
esac
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_memtag_stack" >&5
|
||||
printf "%s\n" "$libc_cv_cc_memtag_stack" >&6; }
|
||||
if test "$TEST_CC" = "$CC"; then
|
||||
libc_cv_test_cc_memtag_stack=$libc_cv_cc_memtag_stack
|
||||
else
|
||||
|
||||
saved_CC="$CC"
|
||||
CC="$TEST_CC"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports -fsanitize=memtag-stack in testing" >&5
|
||||
printf %s "checking if compiler supports -fsanitize=memtag-stack in testing... " >&6; }
|
||||
if test ${libc_cv_test_cc_memtag_stack+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e) if { ac_try='${CC-cc} -Werror -march=armv8.5-a+memtag -fsanitize=memtag-stack -xc /dev/null -S -o /dev/null'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then :
|
||||
libc_cv_test_cc_memtag_stack=yes
|
||||
else case e in #(
|
||||
e) libc_cv_test_cc_memtag_stack=no
|
||||
;;
|
||||
esac
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_cc_memtag_stack" >&5
|
||||
printf "%s\n" "$libc_cv_test_cc_memtag_stack" >&6; }
|
||||
|
||||
CC="$saved_CC"
|
||||
|
||||
fi
|
||||
|
||||
# lld requires the memtag-mode to be used along memtag-stack
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z memtag-stack" >&5
|
||||
printf %s "checking for linker that supports -z memtag-stack... " >&6; }
|
||||
libc_linker_feature=no
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--fatal-warnings -Wl,-z,memtag-stack -z memtag-mode=sync -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,--fatal-warnings -Wl,-z,memtag-stack -z memtag-mode=sync -nostdlib \
|
||||
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||
| grep "warning: -z memtag-stack ignored" > /dev/null 2>&1; then
|
||||
true
|
||||
else
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest*
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_ld_memtag_stack=yes
|
||||
else
|
||||
libc_cv_ld_memtag_stack=no
|
||||
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
if test $libc_cv_test_cc_memtag_stack = yes && \
|
||||
test $libc_cv_ld_memtag_stack = yes
|
||||
then
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-stack = yes"
|
||||
else
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-stack = no"
|
||||
fi
|
||||
|
||||
# Check if linker supports Memtag Heap support. lld requires the memtag-mode.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z memtag-heap" >&5
|
||||
printf %s "checking for linker that supports -z memtag-heap... " >&6; }
|
||||
libc_linker_feature=no
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--fatal-warnings -Wl,-z,memtag-heap -z memtag-mode=sync -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,--fatal-warnings -Wl,-z,memtag-heap -z memtag-mode=sync -nostdlib \
|
||||
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||
| grep "warning: -z memtag-heap ignored" > /dev/null 2>&1; then
|
||||
true
|
||||
else
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest*
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_ld_memtag_heap=yes
|
||||
else
|
||||
libc_cv_ld_memtag_heap=no
|
||||
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
if test $libc_cv_ld_memtag_heap = yes
|
||||
then
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-heap = yes"
|
||||
else
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-heap = no"
|
||||
fi
|
||||
|
||||
# Check if the linker accepts -z memtag-mode without any MTE feature option.
|
||||
# BFD ld emits an orphan DT_AARCH64_MEMTAG_MODE dynamic tag in this case,
|
||||
# which is used to check the inconsistent marking handling.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z memtag-mode" >&5
|
||||
printf %s "checking for linker that supports -z memtag-mode... " >&6; }
|
||||
libc_linker_feature=no
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--fatal-warnings -Wl,-z,memtag-mode=sync -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,--fatal-warnings -Wl,-z,memtag-mode=sync -nostdlib \
|
||||
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||
| grep "warning: -z memtag-mode ignored" > /dev/null 2>&1; then
|
||||
true
|
||||
else
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest*
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_ld_memtag_mode_only=yes
|
||||
else
|
||||
libc_cv_ld_memtag_mode_only=no
|
||||
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
if test $libc_cv_ld_memtag_mode_only = yes
|
||||
then
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-mode-only = yes"
|
||||
else
|
||||
config_vars="$config_vars
|
||||
have-test-memtag-mode-only = no"
|
||||
fi
|
||||
|
||||
|
||||
@@ -105,3 +105,54 @@ then
|
||||
else
|
||||
LIBC_CONFIG_VAR([have-test-gcs], [no])
|
||||
fi
|
||||
|
||||
# Check if compiler supports MEMTAG stack support. Also check if linker
|
||||
# support the required options.
|
||||
LIBC_TRY_CC_AND_TEST_CC_OPTION(
|
||||
[if compiler supports -fsanitize=memtag-stack],
|
||||
[-Werror -march=armv8.5-a+memtag -fsanitize=memtag-stack],
|
||||
libc_cv_cc_memtag_stack,
|
||||
[libc_cv_cc_memtag_stack=yes],
|
||||
[libc_cv_cc_memtag_stack=no],
|
||||
libc_cv_test_cc_memtag_stack,
|
||||
[libc_cv_test_cc_memtag_stack=yes],
|
||||
[libc_cv_test_cc_memtag_stack=no]
|
||||
)
|
||||
# lld requires the memtag-mode to be used along memtag-stack
|
||||
LIBC_LINKER_FEATURE(
|
||||
[-z memtag-stack], [-Wl,--fatal-warnings -Wl,-z,memtag-stack -z memtag-mode=sync],
|
||||
[libc_cv_ld_memtag_stack=yes], [libc_cv_ld_memtag_stack=no]
|
||||
)
|
||||
if test $libc_cv_test_cc_memtag_stack = yes && \
|
||||
test $libc_cv_ld_memtag_stack = yes
|
||||
then
|
||||
LIBC_CONFIG_VAR([have-test-memtag-stack], [yes])
|
||||
else
|
||||
LIBC_CONFIG_VAR([have-test-memtag-stack], [no])
|
||||
fi
|
||||
|
||||
# Check if linker supports Memtag Heap support. lld requires the memtag-mode.
|
||||
LIBC_LINKER_FEATURE(
|
||||
[-z memtag-heap], [-Wl,--fatal-warnings -Wl,-z,memtag-heap -z memtag-mode=sync],
|
||||
[libc_cv_ld_memtag_heap=yes], [libc_cv_ld_memtag_heap=no]
|
||||
)
|
||||
if test $libc_cv_ld_memtag_heap = yes
|
||||
then
|
||||
LIBC_CONFIG_VAR([have-test-memtag-heap], [yes])
|
||||
else
|
||||
LIBC_CONFIG_VAR([have-test-memtag-heap], [no])
|
||||
fi
|
||||
|
||||
# Check if the linker accepts -z memtag-mode without any MTE feature option.
|
||||
# BFD ld emits an orphan DT_AARCH64_MEMTAG_MODE dynamic tag in this case,
|
||||
# which is used to check the inconsistent marking handling.
|
||||
LIBC_LINKER_FEATURE(
|
||||
[-z memtag-mode], [-Wl,--fatal-warnings -Wl,-z,memtag-mode=sync],
|
||||
[libc_cv_ld_memtag_mode_only=yes], [libc_cv_ld_memtag_mode_only=no]
|
||||
)
|
||||
if test $libc_cv_ld_memtag_mode_only = yes
|
||||
then
|
||||
LIBC_CONFIG_VAR([have-test-memtag-mode-only], [yes])
|
||||
else
|
||||
LIBC_CONFIG_VAR([have-test-memtag-mode-only], [no])
|
||||
fi
|
||||
|
||||
@@ -59,6 +59,13 @@ enum {
|
||||
BTI_CHECK_ENFORCED = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTE_MODE_SYNC = 0x1,
|
||||
MTE_MODE_ASYNC = 0x2,
|
||||
MTE_MODE_MASK = MTE_MODE_SYNC | MTE_MODE_ASYNC,
|
||||
MTE_STACK = 0x4,
|
||||
};
|
||||
|
||||
struct cpu_features
|
||||
{
|
||||
uint64_t midr_el1;
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/* AArch64 Memtag ABI Extension for ELF support.
|
||||
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 <ldsodefs.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <dl-mte.h>
|
||||
#include <dl-prop.h>
|
||||
|
||||
#ifdef USE_AARCH64_MEMTAG_ABI
|
||||
|
||||
/* The maximal set of permitted tags that the MTE random tag generation
|
||||
instruction may use. */
|
||||
# define MTE_ALLOWED_TAGS (0xfffe << PR_MTE_TAG_SHIFT)
|
||||
|
||||
# define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
|
||||
|
||||
/* Parsed view of the DT_AARCH64_MEMTAG_xxx dynamic tags of an object. */
|
||||
struct memtag_marking
|
||||
{
|
||||
/* DT_AARCH64_MEMTAG_MODE, valid iff MODE_PRESENT. */
|
||||
uint64_t mode;
|
||||
bool mode_present;
|
||||
/* The object requires the respective MTE protection. */
|
||||
bool stack;
|
||||
bool heap;
|
||||
bool globals;
|
||||
/* A tag has a value outside the ones defined by the ABI. */
|
||||
bool invalid;
|
||||
/* MEMTAG_MODE without any protection being requested, or only one of
|
||||
MEMTAG_GLOBALS and MEMTAG_GLOBALSSZ. */
|
||||
bool orphan;
|
||||
};
|
||||
|
||||
static struct memtag_marking
|
||||
read_marking (const struct link_map *l)
|
||||
{
|
||||
struct memtag_marking m = { 0 };
|
||||
const ElfW(Dyn) *d;
|
||||
|
||||
bool stack_present = false;
|
||||
bool heap_present = false;
|
||||
|
||||
if ((d = l->l_info[DT_AARCH64 (MEMTAG_MODE)]) != NULL)
|
||||
{
|
||||
m.mode_present = true;
|
||||
m.mode = d->d_un.d_val;
|
||||
if (m.mode > 1)
|
||||
m.invalid = true;
|
||||
}
|
||||
|
||||
if ((d = l->l_info[DT_AARCH64 (MEMTAG_STACK)]) != NULL)
|
||||
{
|
||||
stack_present = true;
|
||||
if (d->d_un.d_val > 1)
|
||||
m.invalid = true;
|
||||
m.stack = d->d_un.d_val != 0;
|
||||
}
|
||||
|
||||
if ((d = l->l_info[DT_AARCH64 (MEMTAG_HEAP)]) != NULL)
|
||||
{
|
||||
heap_present = true;
|
||||
if (d->d_un.d_val > 1)
|
||||
m.invalid = true;
|
||||
m.heap = d->d_un.d_val != 0;
|
||||
}
|
||||
|
||||
bool globals_present = l->l_info[DT_AARCH64 (MEMTAG_GLOBALS)] != NULL;
|
||||
bool globalssz_present = l->l_info[DT_AARCH64 (MEMTAG_GLOBALSSZ)] != NULL;
|
||||
m.globals = globals_present;
|
||||
|
||||
if (globals_present != globalssz_present)
|
||||
m.orphan = true;
|
||||
if (m.mode_present && !stack_present && !heap_present && !globals_present)
|
||||
m.orphan = true;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/* PROGRAM is non-NULL during program startup, where any failure is fatal;
|
||||
otherwise the object comes from dlopen and the error can be handled by
|
||||
the caller. */
|
||||
static void _Noreturn
|
||||
fail (const struct link_map *l, const char *program, const char *reason)
|
||||
{
|
||||
if (program == NULL)
|
||||
_dl_signal_error (0, l->l_name, "dlopen", reason);
|
||||
|
||||
if (l->l_name[0] != '\0')
|
||||
_dl_fatal_printf ("%s: error: %s: %s\n", program, l->l_name, reason);
|
||||
_dl_fatal_printf ("%s: error: %s\n", program, reason);
|
||||
}
|
||||
|
||||
static void
|
||||
check_marking (const struct link_map *l, const char *program,
|
||||
const struct memtag_marking *m)
|
||||
{
|
||||
if (m->invalid)
|
||||
fail (l, program, "invalid DT_AARCH64_MEMTAG_xxx dynamic tag value");
|
||||
if (m->orphan)
|
||||
fail (l, program, "inconsistent DT_AARCH64_MEMTAG_xxx dynamic tags");
|
||||
if (m->heap)
|
||||
fail (l, program, "MTE protection heap is not supported");
|
||||
if (m->globals)
|
||||
fail (l, program, "MTE protection globals is not supported");
|
||||
}
|
||||
#endif /* USE_AARCH64_MEMTAG_ABI */
|
||||
|
||||
void
|
||||
_dl_mte_check (struct link_map *l, const char *program)
|
||||
{
|
||||
#ifdef USE_AARCH64_MEMTAG_ABI
|
||||
/* During startup L is the main executable map, otherwise it is the
|
||||
dlopen'ed object. */
|
||||
bool startup = program != NULL;
|
||||
|
||||
/* Whether the MTE stack protection was enabled at startup. */
|
||||
bool mte_stack = (GL(dl_aarch64_mte) & MTE_STACK) != 0;
|
||||
|
||||
struct memtag_marking m = read_marking (l);
|
||||
check_marking (l, program, &m);
|
||||
|
||||
/* Only the main executable marking enables the MTE stack protection. If
|
||||
the main executable is not marked, any dependency that requires it makes
|
||||
the process to fail (either at startup or on dlopen). */
|
||||
if (startup)
|
||||
mte_stack = m.stack;
|
||||
else if (m.stack && !mte_stack)
|
||||
fail (l, program,
|
||||
"shared object requires MTE stack protection, but it was not "
|
||||
"enabled at program startup");
|
||||
|
||||
for (unsigned int i = 0; i < l->l_searchlist.r_nlist; i++)
|
||||
{
|
||||
const struct link_map *dep = l->l_searchlist.r_list[i];
|
||||
if (dep == l)
|
||||
continue;
|
||||
struct memtag_marking dm = read_marking (dep);
|
||||
check_marking (dep, program, &dm);
|
||||
if (dm.stack && !mte_stack)
|
||||
fail (dep, program,
|
||||
startup
|
||||
? "shared object requires MTE stack protection, but it is not "
|
||||
"enabled by the main executable"
|
||||
: "shared object requires MTE stack protection, but it was not "
|
||||
"enabled at program startup");
|
||||
}
|
||||
|
||||
if (startup && mte_stack)
|
||||
{
|
||||
GL(dl_aarch64_mte) |= MTE_STACK;
|
||||
/* Use asynchronous mode if DT_AARCH64_MEMTAG_MODE is not present. */
|
||||
GL(dl_aarch64_mte) |= (m.mode_present && m.mode == 0)
|
||||
? MTE_MODE_SYNC : MTE_MODE_ASYNC;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable the MTE state required by the DT_AARCH64_MEMTAG_xxx dynamic tags of
|
||||
the main executable, parsed by _dl_mte_check. It is done after initial
|
||||
relocation processing, but prior any user code execution (including ELF
|
||||
constructors). */
|
||||
void
|
||||
_dl_mte_init (void)
|
||||
{
|
||||
#ifdef USE_AARCH64_MEMTAG_ABI
|
||||
if ((GL(dl_aarch64_mte) & MTE_STACK) == 0)
|
||||
return;
|
||||
|
||||
if ((GLRO (dl_hwcap2) & HWCAP2_MTE) == 0)
|
||||
_dl_fatal_printf ("Fatal glibc error: MTE stack protection required, "
|
||||
"but not supported by the kernel or CPU\n");
|
||||
|
||||
uint64_t flags = PR_TAGGED_ADDR_ENABLE | MTE_ALLOWED_TAGS;
|
||||
flags |= (GL(dl_aarch64_mte) & MTE_MODE_SYNC) != 0
|
||||
? PR_MTE_TCF_SYNC : PR_MTE_TCF_ASYNC;
|
||||
|
||||
int r = INLINE_SYSCALL_CALL (prctl, PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0);
|
||||
if (r < 0)
|
||||
_dl_fatal_printf ("Fatal glibc error: failed to enable MTE: %d\n", -r);
|
||||
|
||||
if (!_dl_mte_setup_stack ())
|
||||
_dl_fatal_printf ("Fatal glibc error: MTE stack protection setup "
|
||||
"failed\n");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* AArch64 MTE support.
|
||||
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/>. */
|
||||
|
||||
#ifndef _DL_MTE_H
|
||||
#define _DL_MTE_H
|
||||
|
||||
#ifndef PR_SET_TAGGED_ADDR_CTRL
|
||||
# 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)
|
||||
#endif
|
||||
|
||||
#ifndef USE_AARCH64_MEMTAG_ABI
|
||||
static __always_inline bool _dl_mte_setup_stack (void) { return false; };
|
||||
#else
|
||||
extern bool _dl_mte_setup_stack (void) attribute_hidden;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -27,11 +27,17 @@ 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_check (struct link_map *, const char *)
|
||||
attribute_hidden;
|
||||
|
||||
extern void _dl_mte_init (void) 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_check (m, program);
|
||||
}
|
||||
|
||||
static inline void __attribute__ ((always_inline))
|
||||
@@ -39,6 +45,7 @@ _dl_open_check (struct link_map *m, int dlopen_mode)
|
||||
{
|
||||
_dl_bti_check (m, NULL);
|
||||
_dl_gcs_check (m, NULL, dlopen_mode);
|
||||
_dl_mte_check (m, NULL);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
||||
@@ -65,6 +65,11 @@ ENTRY (_start)
|
||||
svc 0x0
|
||||
cbnz w0, L(failed_gcs_lock)
|
||||
L(skip_gcs_enable):
|
||||
/* Enable MTE if required by the Memtag ABI ELF marking. */
|
||||
bl _dl_mte_init
|
||||
/* Reload GL, x16 might be clobbered by the call above. */
|
||||
adrp x16, _rtld_local
|
||||
add x16, x16, :lo12:_rtld_local
|
||||
|
||||
.globl _dl_start_user
|
||||
.type _dl_start_user, %function
|
||||
|
||||
@@ -19,6 +19,10 @@ tests-static += \
|
||||
# tests-static
|
||||
tst-cpu-tunable-static-pie-TUNABLES = glibc.cpu.hwcaps=-midr,-sve,-mops
|
||||
endif
|
||||
|
||||
sysdep-dl-routines += \
|
||||
dl-mte-stack \
|
||||
# sysdep-dl-routines
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),misc)
|
||||
@@ -375,6 +379,108 @@ tst-gcs-audit-override-ARGS = -- $(host-test-program-cmd)
|
||||
|
||||
endif # ifeq ($(have-test-gcs),yes)
|
||||
|
||||
ifeq ($(aarch64-memtag-abi)$(have-test-memtag-stack),yesyes)
|
||||
tests += \
|
||||
tst-memtag-abort-dep \
|
||||
tst-memtag-stack-async \
|
||||
tst-memtag-stack-dep1 \
|
||||
tst-memtag-stack-dep2 \
|
||||
tst-memtag-stack-dlopen \
|
||||
tst-memtag-stack-dlopen-dep \
|
||||
tst-memtag-stack-dlopen-enabled \
|
||||
tst-memtag-stack-sync \
|
||||
# tests
|
||||
|
||||
modules-names += \
|
||||
tst-memtag-mod1 \
|
||||
tst-memtag-mod2 \
|
||||
tst-memtag-mod3 \
|
||||
# modules-names
|
||||
|
||||
# Disable the stack protector for the stack tagging tests. Some GCC versions
|
||||
# have a bug where the stack frame untagging at the function epilogue is done
|
||||
# before the stack canary check.
|
||||
memtag-stack-cflags = -march=armv8.5-a+memtag -fsanitize=memtag-stack \
|
||||
$(no-stack-protector)
|
||||
|
||||
CFLAGS-tst-memtag-stack-sync.c += $(memtag-stack-cflags)
|
||||
LDFLAGS-tst-memtag-stack-sync += -Wl,-z,memtag-stack -Wl,-z,memtag-mode=sync
|
||||
tst-memtag-stack-sync-ARGS = sync
|
||||
|
||||
CFLAGS-tst-memtag-stack-async.c += $(memtag-stack-cflags)
|
||||
LDFLAGS-tst-memtag-stack-async += -Wl,-z,memtag-stack -Wl,-z,memtag-mode=async
|
||||
tst-memtag-stack-async-ARGS = async
|
||||
|
||||
CFLAGS-tst-memtag-mod2.c += -march=armv8.5-a+memtag -fsanitize=memtag-stack
|
||||
LDFLAGS-tst-memtag-mod2.so += -Wl,-z,memtag-stack -Wl,-z,memtag-mode=sync
|
||||
$(objpfx)tst-memtag-mod2.so: $(libsupport)
|
||||
|
||||
CFLAGS-tst-memtag-stack-dep1.c += $(memtag-stack-cflags)
|
||||
LDFLAGS-tst-memtag-stack-dep1 += -Wl,-z,memtag-stack -Wl,-z,memtag-mode=sync
|
||||
$(objpfx)tst-memtag-stack-dep1: $(objpfx)tst-memtag-mod1.so
|
||||
tst-memtag-stack-dep1-ARGS = sync
|
||||
|
||||
CFLAGS-tst-memtag-stack-dep2.c += $(memtag-stack-cflags)
|
||||
LDFLAGS-tst-memtag-stack-dep2 += -Wl,-z,memtag-stack -Wl,-z,memtag-mode=sync \
|
||||
-Wl,--no-as-needed
|
||||
$(objpfx)tst-memtag-stack-dep2: $(objpfx)tst-memtag-mod2.so
|
||||
tst-memtag-stack-dep2-ARGS = sync
|
||||
|
||||
$(objpfx)tst-memtag-stack-dlopen.out: $(objpfx)tst-memtag-mod2.so
|
||||
|
||||
LDFLAGS-tst-memtag-mod3.so += -Wl,--no-as-needed
|
||||
$(objpfx)tst-memtag-mod3.so: $(objpfx)tst-memtag-mod2.so
|
||||
$(objpfx)tst-memtag-stack-dlopen-dep.out: $(objpfx)tst-memtag-mod3.so \
|
||||
$(objpfx)tst-memtag-mod1.so
|
||||
|
||||
CFLAGS-tst-memtag-stack-dlopen-enabled.c += $(memtag-stack-cflags)
|
||||
LDFLAGS-tst-memtag-stack-dlopen-enabled += -Wl,-z,memtag-stack \
|
||||
-Wl,-z,memtag-mode=sync
|
||||
$(objpfx)tst-memtag-stack-dlopen-enabled.out: $(objpfx)tst-memtag-mod2.so
|
||||
|
||||
LDFLAGS-tst-memtag-abort-dep += -Wl,--no-as-needed
|
||||
$(objpfx)tst-memtag-abort-dep: $(objpfx)tst-memtag-mod2.so
|
||||
tst-memtag-abort-dep-ERROR = requires MTE stack protection
|
||||
|
||||
ifeq ($(have-test-memtag-heap),yes)
|
||||
tests += \
|
||||
tst-memtag-abort-heap \
|
||||
# tests
|
||||
|
||||
LDFLAGS-tst-memtag-abort-heap += -Wl,-z,memtag-heap -Wl,-z,memtag-mode=sync
|
||||
tst-memtag-abort-heap-ERROR = MTE protection heap is not supported
|
||||
endif # ifeq ($(have-test-memtag-heap),yes)
|
||||
|
||||
ifeq ($(have-test-memtag-mode-only),yes)
|
||||
tests += \
|
||||
tst-memtag-abort-orphan \
|
||||
tst-memtag-dlopen-orphan \
|
||||
# tests
|
||||
|
||||
modules-names += \
|
||||
tst-memtag-mod4 \
|
||||
# modules-names
|
||||
|
||||
LDFLAGS-tst-memtag-abort-orphan += -Wl,-z,memtag-mode=sync
|
||||
tst-memtag-abort-orphan-ERROR = inconsistent DT_AARCH64_MEMTAG_xxx dynamic tags
|
||||
|
||||
LDFLAGS-tst-memtag-mod4.so += -Wl,-z,memtag-mode=sync
|
||||
$(objpfx)tst-memtag-dlopen-orphan.out: $(objpfx)tst-memtag-mod4.so \
|
||||
$(objpfx)tst-memtag-mod1.so
|
||||
endif # ifeq ($(have-test-memtag-mode-only),yes)
|
||||
|
||||
define run-memtag-abort-test
|
||||
$(test-wrapper-env) $(run-program-env) $(host-test-program-cmd)
|
||||
endef
|
||||
|
||||
$(objpfx)tst-memtag-abort-%.out: \
|
||||
$(..)sysdeps/unix/sysv/linux/aarch64/tst-memtag-abort.sh \
|
||||
$(objpfx)tst-memtag-abort-%
|
||||
$(SHELL) $< $(common-objpfx) $(test-name) \
|
||||
'$(tst-memtag-abort-$*-ERROR)' '$(run-memtag-abort-test)'; \
|
||||
$(evaluate-test)
|
||||
endif # ifeq ($(aarch64-memtag-abi)$(have-test-memtag-stack),yesyes)
|
||||
|
||||
endif # ifeq ($(subdir),misc)
|
||||
|
||||
ifeq ($(subdir),stdlib)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* 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/>. */
|
||||
|
||||
#ifdef USE_AARCH64_MEMTAG_ABI
|
||||
#include <ldsodefs.h>
|
||||
#include <dl-prop.h>
|
||||
|
||||
bool
|
||||
_dl_mte_setup_stack (void)
|
||||
{
|
||||
GL(dl_stack_prot_flags) |= PROT_MTE;
|
||||
void *page = PTR_ALIGN_DOWN (__libc_stack_end, GLRO (dl_pagesize));
|
||||
return __mprotect (page, GLRO (dl_pagesize),
|
||||
GL(dl_stack_prot_flags) | PROT_GROWSDOWN) == 0;
|
||||
}
|
||||
#endif
|
||||
@@ -34,4 +34,18 @@ PROCINFO_CLASS unsigned long _dl_aarch64_gcs
|
||||
# else
|
||||
,
|
||||
# endif
|
||||
|
||||
# if !defined PROCINFO_DECL && defined SHARED
|
||||
._dl_aarch64_mte
|
||||
# else
|
||||
PROCINFO_CLASS unsigned long _dl_aarch64_mte
|
||||
# endif
|
||||
# ifndef PROCINFO_DECL
|
||||
= 0
|
||||
# endif
|
||||
# if !defined SHARED || defined PROCINFO_DECL
|
||||
;
|
||||
# else
|
||||
,
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Check that an unmarked main executable with a dependency that requires
|
||||
MTE stack protection aborts at startup.
|
||||
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 <support/check.h>
|
||||
|
||||
void run_mte_test (void *);
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
void (*fp) (void *) = run_mte_test;
|
||||
FAIL_EXIT1 ("dynamic loader did not abort with a MTE marked dependency "
|
||||
"(%p)", fp);
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Check that a main executable marked with DT_AARCH64_MEMTAG_HEAP aborts
|
||||
at startup, since only the MTE stack protection is supported.
|
||||
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 <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
FAIL_EXIT1 ("dynamic loader did not abort with a MTE heap marking");
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Check that a main executable with an orphan DT_AARCH64_MEMTAG_MODE
|
||||
dynamic tag (without any MTE protection being requested) aborts at
|
||||
startup.
|
||||
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 <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
FAIL_EXIT1 ("dynamic loader did not abort with an orphan MTE marking");
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
# Test wrapper for AArch64 Memtag ABI tests that are expected to abort
|
||||
# at startup.
|
||||
# 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/>.
|
||||
|
||||
objpfx=$1; shift
|
||||
tstname=$1; shift
|
||||
expected=$1; shift
|
||||
tstrun=$1; shift
|
||||
|
||||
logfile=$objpfx/$tstname.out
|
||||
|
||||
rm -f $logfile
|
||||
touch $logfile
|
||||
|
||||
${tstrun} 2>> $logfile >> $logfile; status=$?
|
||||
|
||||
if test $status -eq 127 && grep -q "$expected" "$logfile" ; then
|
||||
exit 0
|
||||
elif test $status -eq 77; then
|
||||
exit 77
|
||||
else
|
||||
echo "expected '$expected' with 127, not $status return status"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Check that dlopen of a module with an orphan DT_AARCH64_MEMTAG_MODE
|
||||
dynamic tag fails instead of aborting the process.
|
||||
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 <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
#include "tst-mte-helper.h"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_VERIFY_EXIT (!mte_enable ());
|
||||
|
||||
/* The module marking is inconsistent (DT_AARCH64_MEMTAG_MODE without any
|
||||
MTE protection request). The dlopen should fail without aborting the
|
||||
process. */
|
||||
void *h = dlopen ("tst-memtag-mod4.so", RTLD_NOW);
|
||||
TEST_VERIFY (h == NULL);
|
||||
const char *message = dlerror ();
|
||||
if (strstr (message, "inconsistent DT_AARCH64_MEMTAG_xxx") == NULL)
|
||||
FAIL_EXIT1 ("invalid dlopen error message: %s", message);
|
||||
|
||||
/* The process should still work, including loading unmarked modules. */
|
||||
xdlclose (xdlopen ("tst-memtag-mod1.so", RTLD_NOW));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1 @@
|
||||
int foo (void) { return 0; }
|
||||
@@ -0,0 +1 @@
|
||||
#include "tst-memtag-test-skeleton.c"
|
||||
@@ -0,0 +1,10 @@
|
||||
/* Unmarked module with a dependency (tst-memtag-mod2.so) that requires
|
||||
MTE stack protection. */
|
||||
|
||||
extern void run_mte_test (void *);
|
||||
|
||||
void
|
||||
mod3_func (void *closure)
|
||||
{
|
||||
run_mte_test (closure);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* Module linked with an orphan DT_AARCH64_MEMTAG_MODE dynamic tag (without
|
||||
any MTE protection request). */
|
||||
|
||||
int
|
||||
mod4_func (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Check DT_AARCH64_MEMTAG_STACK with DT_AARCH64_MEMTAG_MODE equal 0. */
|
||||
#include "tst-memtag-stack-skeleton.c"
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Check if dependencies without DT_AARCH64_MEMTAG_STACK still enables MTE
|
||||
support. */
|
||||
#include "tst-memtag-stack-skeleton.c"
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Check that a marked main executable with a dependency that also requires
|
||||
MTE stack protection enables the MTE stack protection. */
|
||||
#include "tst-memtag-stack-skeleton.c"
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Check that without MTE stack protection enabled at startup.
|
||||
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 <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
#include "tst-mte-helper.h"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_VERIFY_EXIT (!mte_enable ());
|
||||
|
||||
/* The module itself is unmarked, but its dependency requires MTE stack
|
||||
protection. The dlopen should fail without aborting the process. */
|
||||
void *h = dlopen ("tst-memtag-mod3.so", RTLD_NOW);
|
||||
TEST_VERIFY (h == NULL);
|
||||
const char *message = dlerror ();
|
||||
if (strstr (message, "requires MTE stack protection") == NULL)
|
||||
FAIL_EXIT1 ("invalid dlopen error message: %s", message);
|
||||
|
||||
/* The process should still work, including loading unmarked modules. */
|
||||
xdlclose (xdlopen ("tst-memtag-mod1.so", RTLD_NOW));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Check that a marked main executable can dlopen a module that requires
|
||||
MTE stack protection.
|
||||
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/auxv.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
#include "tst-mte-helper.h"
|
||||
|
||||
static void (*mod_run_mte_test) (void *);
|
||||
|
||||
static void
|
||||
run_dlopened_test (void *closure)
|
||||
{
|
||||
mod_run_mte_test (closure);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
|
||||
FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
|
||||
|
||||
TEST_VERIFY_EXIT (mte_enable ());
|
||||
|
||||
void *h = xdlopen ("tst-memtag-mod2.so", RTLD_NOW);
|
||||
mod_run_mte_test = xdlsym (h, "run_mte_test");
|
||||
|
||||
struct support_capture_subprocess result =
|
||||
support_capture_subprocess (run_dlopened_test, (void *) TEST_MAIN);
|
||||
support_capture_subprocess_check (&result, "MTE stack fault in dlopened "
|
||||
"module", EXIT_MTESERR, sc_allow_none);
|
||||
support_capture_subprocess_free (&result);
|
||||
|
||||
xdlclose (h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Tests for MEMTAG support.
|
||||
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 <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#include "tst-mte-helper.h"
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
|
||||
FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
|
||||
|
||||
TEST_VERIFY_EXIT (!mte_enable ());
|
||||
|
||||
/* Verify that if the MTE stack protection is not enabled at startup,
|
||||
trying to load a DSO that requires it should fail. */
|
||||
void *h = dlopen ("tst-memtag-mod2.so", RTLD_NOW);
|
||||
TEST_VERIFY (h == NULL);
|
||||
const char *message = dlerror ();
|
||||
if (strstr (message, "requires MTE stack protection") == NULL)
|
||||
FAIL_EXIT1 ("invalid dlopen error message: %s", message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Tests for MEMTAG support.
|
||||
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 <string.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#include "tst-memtag-test-skeleton.c"
|
||||
|
||||
static int
|
||||
do_test (int argc, char *argv[])
|
||||
{
|
||||
if (!(getauxval (AT_HWCAP2) & HWCAP2_MTE))
|
||||
FAIL_UNSUPPORTED ("kernel or CPU does not support or enable MTE");
|
||||
|
||||
TEST_VERIFY_EXIT (mte_enable ());
|
||||
/* We must have
|
||||
- one or four parameters left if called initially
|
||||
+ path for ld.so optional
|
||||
+ "--library-path" optional
|
||||
+ the library path optional
|
||||
+ the application name
|
||||
+ the expected MTE mode
|
||||
*/
|
||||
TEST_VERIFY_EXIT (argc == 2);
|
||||
int mode = mte_mode ();
|
||||
if (strcmp (argv[1], "sync") == 0)
|
||||
TEST_VERIFY_EXIT (mode == PR_MTE_TCF_SYNC);
|
||||
else if (strcmp (argv[1], "async") == 0)
|
||||
TEST_VERIFY_EXIT (mode == PR_MTE_TCF_ASYNC);
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result =
|
||||
support_capture_subprocess (run_mte_test, (void*)TEST_MAIN);
|
||||
|
||||
support_capture_subprocess_check (&result, "MTE main stack",
|
||||
EXIT_MTESERR, sc_allow_none);
|
||||
|
||||
support_capture_subprocess_free (&result);
|
||||
}
|
||||
|
||||
{
|
||||
struct support_capture_subprocess result =
|
||||
support_capture_subprocess (run_mte_test, (void*)TEST_THREAD);
|
||||
|
||||
support_capture_subprocess_check (&result, "MTE thread stack",
|
||||
EXIT_MTESERR, sc_allow_none);
|
||||
|
||||
support_capture_subprocess_free (&result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Check DT_AARCH64_MEMTAG_STACK with DT_AARCH64_MEMTAG_MODE equal 0. */
|
||||
#include "tst-memtag-stack-skeleton.c"
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Tests skeleton for MEMTAG tests.
|
||||
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 <stdlib.h>
|
||||
#include <libc-diag.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xsignal.h>
|
||||
#include <support/xthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tst-mte-helper.h"
|
||||
|
||||
static void
|
||||
sigsegv_handler (int signum, siginfo_t *si, void *context)
|
||||
{
|
||||
if (si->si_signo == SIGSEGV
|
||||
&& (si->si_code == SEGV_MTESERR || si->si_code == SEGV_MTEAERR))
|
||||
_exit (EXIT_MTESERR);
|
||||
else
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Prevent inlining so the stack frame is definitively constructed to
|
||||
trigger a stack frame, and optimization to avoid compiler optimize
|
||||
away the invalid stack operation. */
|
||||
static void *
|
||||
__attribute_noinline__
|
||||
__attribute_optimization_barrier__
|
||||
trigger_mte_fault (void *closure)
|
||||
{
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
DIAG_IGNORE_NEEDS_COMMENT_GCC (16, "-Warray-bounds");
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset (&mask);
|
||||
sigaddset (&mask, SIGSEGV);
|
||||
|
||||
/* Aling to a MTE tag granule. */
|
||||
_Alignas (16) char stack_buffer[16];
|
||||
volatile char *ptr = &stack_buffer[16];
|
||||
|
||||
*(volatile char *)ptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
run_mte_test (void *closure)
|
||||
{
|
||||
test_mode mode = (test_mode)(uintptr_t)closure;
|
||||
|
||||
{
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = sigsegv_handler,
|
||||
.sa_flags = SA_NODEFER | SA_SIGINFO,
|
||||
};
|
||||
sigemptyset (&sa.sa_mask);
|
||||
xsigaction (SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
if (mode == TEST_MAIN)
|
||||
trigger_mte_fault (NULL);
|
||||
else
|
||||
{
|
||||
pthread_t t = xpthread_create (NULL, trigger_mte_fault, NULL);
|
||||
xpthread_join (t);
|
||||
}
|
||||
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Helper routines to check MEMTAG support.
|
||||
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/>. */
|
||||
|
||||
#ifndef TST_MTE_HELPER_H
|
||||
#define TST_MTE_HELPER_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TEST_MAIN = 0,
|
||||
TEST_THREAD = 1,
|
||||
} test_mode;
|
||||
|
||||
#define EXIT_MTESERR 79
|
||||
|
||||
void run_mte_test (void *);
|
||||
|
||||
static inline bool
|
||||
mte_enable (void)
|
||||
{
|
||||
int ctrl = prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
|
||||
return ctrl > 0 && (ctrl & PR_MTE_TCF_MASK) != PR_MTE_TCF_NONE;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mte_mode (void)
|
||||
{
|
||||
int ctrl = prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
|
||||
TEST_VERIFY_EXIT (ctrl >= 0);
|
||||
return ctrl & PR_MTE_TCF_MASK;
|
||||
}
|
||||
|
||||
#define __attribute_disable_mte_stack__ \
|
||||
__attribute__((no_sanitize("memtag-stack")))
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user