From: Yury Khrustalev Date: Wed, 29 Oct 2025 16:14:06 +0000 (+0000) Subject: aarch64: Add tests for glibc.cpu.aarch64_bti behaviour X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6f869f54fb3e066964fc7138e36433de793244af;p=thirdparty%2Fglibc.git aarch64: Add tests for glibc.cpu.aarch64_bti behaviour 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. Reviewed-by: Adhemerval Zanella --- diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile index 879c8022c0..d0e4be8829 100644 --- a/sysdeps/aarch64/Makefile +++ b/sysdeps/aarch64/Makefile @@ -87,8 +87,64 @@ 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 \ + # modules-names + +$(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 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 +# . + +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 + . */ + +#include + +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 + . */ + +#include + +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 + . */ + +#include + +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 + . */ + +#include +#include +#include +#include +#include + +#include +#include + +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 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 + . */ + +#include +#include +#include + +#include +#include + +/* 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