[PATCH v4 3/3] aarch64: Add tests for glibc.cpu.aarch64_bti behaviour
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Dec 3 15:58:01 GMT 2025
On 01/12/25 13:14, Yury Khrustalev wrote:
> Check that the new tunable changes behaviour correctly:
>
> * When BTI is enforced, any unmarked binary that is loaded
> results in an error: either an abort or dlopen error when
> this binary is loaded via dlopen.
> * When BTI is not enforced, it is OK to load an unmarked
> binary.
Just a small nit below, there is no need to change a new version. I think
there is no need to check for static dlopen.
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> sysdeps/aarch64/Makefile | 57 ++++++++++++++++-
> sysdeps/aarch64/tst-bti-abort-imm.c | 3 +
> sysdeps/aarch64/tst-bti-abort-transitive.c | 3 +
> sysdeps/aarch64/tst-bti-abort-unprot.c | 3 +
> sysdeps/aarch64/tst-bti-abort.sh | 39 ++++++++++++
> sysdeps/aarch64/tst-bti-dep-prot.c | 3 +
> sysdeps/aarch64/tst-bti-dlopen-imm.c | 6 ++
> sysdeps/aarch64/tst-bti-dlopen-prot.c | 6 ++
> sysdeps/aarch64/tst-bti-dlopen-transitive.c | 6 ++
> sysdeps/aarch64/tst-bti-mod-prot.c | 30 +++++++++
> sysdeps/aarch64/tst-bti-mod-unprot.c | 30 +++++++++
> sysdeps/aarch64/tst-bti-mod.c | 27 ++++++++
> sysdeps/aarch64/tst-bti-permissive-dlopen.c | 6 ++
> sysdeps/aarch64/tst-bti-permissive-imm.c | 3 +
> .../aarch64/tst-bti-permissive-transitive.c | 3 +
> sysdeps/aarch64/tst-bti-skeleton-dlopen.c | 62 +++++++++++++++++++
> sysdeps/aarch64/tst-bti-skeleton.c | 45 ++++++++++++++
> 17 files changed, 331 insertions(+), 1 deletion(-)
> create mode 100644 sysdeps/aarch64/tst-bti-abort-imm.c
> create mode 100644 sysdeps/aarch64/tst-bti-abort-transitive.c
> create mode 100644 sysdeps/aarch64/tst-bti-abort-unprot.c
> create mode 100644 sysdeps/aarch64/tst-bti-abort.sh
> create mode 100644 sysdeps/aarch64/tst-bti-dep-prot.c
> create mode 100644 sysdeps/aarch64/tst-bti-dlopen-imm.c
> create mode 100644 sysdeps/aarch64/tst-bti-dlopen-prot.c
> create mode 100644 sysdeps/aarch64/tst-bti-dlopen-transitive.c
> create mode 100644 sysdeps/aarch64/tst-bti-mod-prot.c
> create mode 100644 sysdeps/aarch64/tst-bti-mod-unprot.c
> create mode 100644 sysdeps/aarch64/tst-bti-mod.c
> create mode 100644 sysdeps/aarch64/tst-bti-permissive-dlopen.c
> create mode 100644 sysdeps/aarch64/tst-bti-permissive-imm.c
> create mode 100644 sysdeps/aarch64/tst-bti-permissive-transitive.c
> create mode 100644 sysdeps/aarch64/tst-bti-skeleton-dlopen.c
> create mode 100644 sysdeps/aarch64/tst-bti-skeleton.c
>
> diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
> index 29348912e3..d8defadafa 100644
> --- a/sysdeps/aarch64/Makefile
> +++ b/sysdeps/aarch64/Makefile
> @@ -83,8 +83,63 @@ tests-internal += \
>
> $(objpfx)tst-sme-clone3: $(objpfx)clone3.o $(objpfx)__arm_za_disable.o
>
> +ifeq (yes,$(have-test-bti))
> +
> +tests += \
> + tst-bti-abort-imm \
> + tst-bti-abort-transitive \
> + tst-bti-abort-unprot \
> + tst-bti-dep-prot \
> + tst-bti-dlopen-imm \
> + tst-bti-dlopen-prot \
> + tst-bti-dlopen-transitive \
> + tst-bti-permissive-dlopen \
> + tst-bti-permissive-imm \
> + tst-bti-permissive-transitive \
> + # tests
> +
> +modules-names += \
> + tst-bti-mod \
> + tst-bti-mod-prot \
> + tst-bti-mod-unprot
Add a '\' and a # modules-names as the end of the list, like the tests.
> +
> +$(objpfx)tst-bti-abort-imm: $(objpfx)tst-bti-mod-unprot.so
> +$(objpfx)tst-bti-abort-transitive: $(objpfx)tst-bti-mod.so
> +$(objpfx)tst-bti-abort-unprot: $(objpfx)tst-bti-mod-prot.so
> +$(objpfx)tst-bti-dep-prot: $(objpfx)tst-bti-mod-prot.so
> +$(objpfx)tst-bti-mod.so: $(objpfx)tst-bti-mod-unprot.so
> +$(objpfx)tst-bti-permissive-imm: $(objpfx)tst-bti-mod-unprot.so
> +$(objpfx)tst-bti-permissive-transitive: $(objpfx)tst-bti-mod.so
> +
> +CFLAGS-tst-bti-abort-unprot.o += -mbranch-protection=none
> +CFLAGS-tst-bti-mod-unprot.os += -mbranch-protection=none
> +
> +tst-bti-abort-imm-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-abort-transitive-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-abort-unprot-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-dep-prot-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-dlopen-imm-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-dlopen-prot-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +tst-bti-dlopen-transitive-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1
> +
> +tst-bti-permissive-imm-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=0
> +tst-bti-permissive-transitive-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=0
> +tst-bti-permissive-dlopen-ENV = GLIBC_TUNABLES=glibc.cpu.aarch64_bti=0
> +
> +define run-bti-abort-test
> + $(test-wrapper-env) $(run-program-env) \
> + $(tst-bti-abort-$*-ENV) $(host-test-program-cmd)
> +endef
> +
> +$(objpfx)tst-bti-abort-%.out: $(..)sysdeps/aarch64/tst-bti-abort.sh \
> + $(objpfx)tst-bti-abort-%
> + $(SHELL) $< $(common-objpfx) $(test-name) '$(run-bti-abort-test)'; \
> + $(evaluate-test)
> +
> +endif # ifeq (yes,$(have-test-bti))
> +
> endif
>
> ifeq ($(subdir),malloc)
> sysdep_malloc_debug_routines = __mtag_tag_zero_region __mtag_tag_region
> -endif
> +endif # malloc directory
Ok.
> diff --git a/sysdeps/aarch64/tst-bti-abort-imm.c b/sysdeps/aarch64/tst-bti-abort-imm.c
> new file mode 100644
> index 0000000000..60d29f6773
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-abort-imm.c
> @@ -0,0 +1,3 @@
> +/* This test checks that process is aborted when an immediate
> + dependency is not marked with BTI and BTI is enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-abort-transitive.c b/sysdeps/aarch64/tst-bti-abort-transitive.c
> new file mode 100644
> index 0000000000..1264ae0362
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-abort-transitive.c
> @@ -0,0 +1,3 @@
> +/* This test checks that process is aborted when a transitive
> + dependency is not marked with BTI and BTI is enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-abort-unprot.c b/sysdeps/aarch64/tst-bti-abort-unprot.c
> new file mode 100644
> index 0000000000..6c3b31b421
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-abort-unprot.c
> @@ -0,0 +1,3 @@
> +/* This test checks that process is aborted the executable
> + is not marked with BTI and BTI is enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-abort.sh b/sysdeps/aarch64/tst-bti-abort.sh
> new file mode 100644
> index 0000000000..d2ef007be4
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-abort.sh
> @@ -0,0 +1,39 @@
> +#!/bin/sh
> +# Test wrapper for AArch64 tests for BTI that are expected to abort.
> +# Copyright (C) 2025 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
> +tstrun=$1; shift
> +
> +logfile=$objpfx/$tstname.out
> +
> +rm -vf $logfile
> +touch $logfile
> +
> +${tstrun} 2>> $logfile >> $logfile; status=$?
> +
> +if test $status -eq 127 \
> + && grep -q -w "failed to turn on BTI protection" "$logfile" ; then
> + exit 0
> +elif test $status -eq 77; then
> + exit 77
> +else
> + echo "expected 'failed to turn on BTI protection' not $status return status"
> + exit 1
> +fi
> diff --git a/sysdeps/aarch64/tst-bti-dep-prot.c b/sysdeps/aarch64/tst-bti-dep-prot.c
> new file mode 100644
> index 0000000000..9da00a68bd
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-dep-prot.c
> @@ -0,0 +1,3 @@
> +/* This test checks that program works correctly when an immediate
> + dependency is marked with BTI and BTI is enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-dlopen-imm.c b/sysdeps/aarch64/tst-bti-dlopen-imm.c
> new file mode 100644
> index 0000000000..262bb70abe
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-dlopen-imm.c
> @@ -0,0 +1,6 @@
> +/* This test checks that dlopen returns an error when a dependency
> + is loaded via dlopen and the corresponding binary is not marked
> + with BTI while BTI is enforced. */
> +#define TEST_BTI_DLOPEN_MODULE "tst-bti-mod-unprot.so"
> +#define TEST_BTI_EXPECT_DLOPEN 0
> +#include "tst-bti-skeleton-dlopen.c"
> diff --git a/sysdeps/aarch64/tst-bti-dlopen-prot.c b/sysdeps/aarch64/tst-bti-dlopen-prot.c
> new file mode 100644
> index 0000000000..10e4fb79ce
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-dlopen-prot.c
> @@ -0,0 +1,6 @@
> +/* This test checks that dlopen succeeds when a dependency is loaded
> + via dlopen and the corresponding binary is marked with BTI
> + while BTI is enforced. */
> +#define TEST_BTI_DLOPEN_MODULE "tst-bti-mod-prot.so"
> +#define TEST_BTI_EXPECT_DLOPEN 1
> +#include "tst-bti-skeleton-dlopen.c"
> diff --git a/sysdeps/aarch64/tst-bti-dlopen-transitive.c b/sysdeps/aarch64/tst-bti-dlopen-transitive.c
> new file mode 100644
> index 0000000000..4f4f8456cc
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-dlopen-transitive.c
> @@ -0,0 +1,6 @@
> +/* This test checks that dlopen returns an error when a dependency
> + is loaded via dlopen that has an unmarked dependency while BTI
> + is enforced. */
> +#define TEST_BTI_DLOPEN_MODULE "tst-bti-mod.so"
> +#define TEST_BTI_EXPECT_DLOPEN 0
> +#include "tst-bti-skeleton-dlopen.c"
> diff --git a/sysdeps/aarch64/tst-bti-mod-prot.c b/sysdeps/aarch64/tst-bti-mod-prot.c
> new file mode 100644
> index 0000000000..1187e0f8c9
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-mod-prot.c
> @@ -0,0 +1,30 @@
> +/* This SO will be linked with BTI marking.
> + Copyright (C) 2025 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 <stdio.h>
> +
> +int foo (void)
> +{
> + puts ("called function fun unprot");
> + return 0;
> +}
> +
> +int fun (void)
> +{
> + return 0;
> +}
> diff --git a/sysdeps/aarch64/tst-bti-mod-unprot.c b/sysdeps/aarch64/tst-bti-mod-unprot.c
> new file mode 100644
> index 0000000000..03b656d2dd
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-mod-unprot.c
> @@ -0,0 +1,30 @@
> +/* This SO will be linked without BTI marking.
> + Copyright (C) 2025 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 <stdio.h>
> +
> +int foo (void)
> +{
> + puts ("called function fun unprot");
> + return 0;
> +}
> +
> +int fun (void)
> +{
> + return 0;
> +}
> diff --git a/sysdeps/aarch64/tst-bti-mod.c b/sysdeps/aarch64/tst-bti-mod.c
> new file mode 100644
> index 0000000000..79b48d2561
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-mod.c
> @@ -0,0 +1,27 @@
> +/* DSO for testing BTI.
> + Copyright (C) 2025 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 <stdio.h>
> +
> +extern int foo (void);
> +
> +int fun (void)
> +{
> + puts ("called function fun");
> + return foo ();
> +}
> diff --git a/sysdeps/aarch64/tst-bti-permissive-dlopen.c b/sysdeps/aarch64/tst-bti-permissive-dlopen.c
> new file mode 100644
> index 0000000000..bcfa1601ed
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-permissive-dlopen.c
> @@ -0,0 +1,6 @@
> +/* This test checks that dlopen succeeds when a dependency is loaded
> + via dlopen and the corresponding binary is not marked with BTI
> + while BTI is not enforced. */
> +#define TEST_BTI_DLOPEN_MODULE "tst-bti-mod-unprot.so"
> +#define TEST_BTI_EXPECT_DLOPEN 1
> +#include "tst-bti-skeleton-dlopen.c"
> diff --git a/sysdeps/aarch64/tst-bti-permissive-imm.c b/sysdeps/aarch64/tst-bti-permissive-imm.c
> new file mode 100644
> index 0000000000..61a993d3b0
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-permissive-imm.c
> @@ -0,0 +1,3 @@
> +/* This test checks that process runs when an immediate
> + dependency is not marked with BTI but BTI is not enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-permissive-transitive.c b/sysdeps/aarch64/tst-bti-permissive-transitive.c
> new file mode 100644
> index 0000000000..0808fe17f6
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-permissive-transitive.c
> @@ -0,0 +1,3 @@
> +/* This test checks that process runs when a transitive
> + dependency is not marked with BTI but BTI is not enforced. */
> +#include "tst-bti-skeleton.c"
> diff --git a/sysdeps/aarch64/tst-bti-skeleton-dlopen.c b/sysdeps/aarch64/tst-bti-skeleton-dlopen.c
> new file mode 100644
> index 0000000000..b855b9a7d4
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-skeleton-dlopen.c
> @@ -0,0 +1,62 @@
> +/* Simple test for BTI support with dlopen: this base source file is
> + included in several tests.
> + Copyright (C) 2025 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 <stdio.h>
> +#include <dlfcn.h>
> +#include <string.h>
> +#include <sys/auxv.h>
> +#include <sys/signal.h>
> +
> +#include <support/check.h>
> +#include <support/test-driver.h>
> +
> +typedef int (*fun_t) (void);
> +
> +static int
> +do_test (void)
> +{
> + unsigned long hwcap2 = getauxval (AT_HWCAP2);
> + if ((hwcap2 & HWCAP2_BTI) == 0)
> + {
> + FAIL_UNSUPPORTED ("BTI is not supported by this system");
> + }
> +
> + void *h = dlopen (TEST_BTI_DLOPEN_MODULE, RTLD_NOW);
> + const char *err = dlerror ();
> +
> +#if TEST_BTI_EXPECT_DLOPEN
> + TEST_VERIFY (h != NULL);
> +#else
> + TEST_VERIFY (h == NULL);
> + /* Only accept expected BTI-related errors. */
> + TEST_VERIFY (strstr (err, "failed to turn on BTI protection") != NULL);
> +#endif
> +
> + if (h == NULL)
> + printf ("dlopen error: %s\n", err);
> + else
> + {
> + puts ("library " TEST_BTI_DLOPEN_MODULE " loaded normally");
> + dlclose (h);
> + }
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/aarch64/tst-bti-skeleton.c b/sysdeps/aarch64/tst-bti-skeleton.c
> new file mode 100644
> index 0000000000..460b4302c9
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-bti-skeleton.c
> @@ -0,0 +1,45 @@
> +/* Simple test for BTI support: this base source file is included in
> + several tests.
> + Copyright (C) 2025 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 <stdio.h>
> +#include <sys/auxv.h>
> +#include <sys/signal.h>
> +
> +#include <support/check.h>
> +#include <support/test-driver.h>
> +
> +/* Defined in tst-bti-mod.c file. */
> +extern int fun (void);
> +
> +typedef int (*fun_t) (void);
> +
> +static int
> +do_test (void)
> +{
> + unsigned long hwcap2 = getauxval (AT_HWCAP2);
> + if ((hwcap2 & HWCAP2_BTI) == 0)
> + {
> + FAIL_UNSUPPORTED ("BTI is not supported by this system");
> + }
> +
> + fun_t fn = &fun;
> + return fn ();
> +}
> +
> +#include <support/test-driver.c>
More information about the Libc-alpha
mailing list