[PATCH v4 3/3] aarch64: Add tests for glibc.cpu.aarch64_bti behaviour
Yury Khrustalev
yury.khrustalev@arm.com
Mon Dec 1 16:14:58 GMT 2025
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.
---
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
+
+$(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
+# <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>
--
2.47.3
More information about the Libc-alpha
mailing list