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  <adhemerval.zanella@linaro.org>
This commit is contained in:
Yury Khrustalev 2025-10-29 16:14:06 +00:00
parent dba95d2887
commit 6f869f54fb
17 changed files with 332 additions and 1 deletions

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 ();
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>