* [PATCH v2 00/10] Add arm64/signal initial kselftest support
@ 2019-07-03 16:35 Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 01/10] kselftest: arm64: introduce new boilerplate code Cristian Marussi
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Hi
this patchset aims to add the initial arch-specific arm64 support to
kselftest starting with signals-related test-cases.
A common internal test-case layout is proposed which then it is
anyway wired-up to the toplevel kselftest Makefile, so that it
should be possible at the end to run it on an arm64 target in the
usual way with KSFT.
~/linux# make TARGETS=arm64 kselftest
New KSFT arm64 testcases live inside tools/testing/selftests/arm64 grouped by
family inside subdirectories: arm64/signal is the first family proposed with
this series. arm64/signal tests can be run via KSFT or standalone.
Thanks
Cristian
Notes:
-----
- further details in the included READMEs
- more tests still to be written (current strategy is going through the related
Kernel signal-handling code and write a test for each possible and sensible code-path)
- a bit of overlap around KSFT arm64/ Makefiles is expected with this recently
proposed patch-series:
http://lists.infradead.org/pipermail/linux-arm-kernel/2019-June/659432.html
Changes:
--------
v1-->v2:
- rebased on 5.2-rc7
- various makefile's cleanups
- mixed READMEs fixes
- fixed test_arm64_signals.sh runner script
- cleaned up assembly code in signal.S
- improved get_current_context() logic
- fixed SAFE_WRITE()
- common support code splitted into more chunks, each one introduced when
needed by some new testcases
- fixed some headers validation routines in testcases.c
- removed some still broken/immature tests:
+ fake_sigreturn_misaligned
+ fake_sigreturn_overflow_reserved
+ mangle_pc_invalid
+ mangle_sp_misaligned
- fixed some other testcases:
+ mangle_pstate_ssbs_regs: better checks of SSBS bit when feature unsupported
+ mangle_pstate_invalid_compat_toggle: name fix
+ mangle_pstate_invalid_mode_el[1-3]: precautionary zeroing PSTATE.MODE
+ fake_sigreturn_bad_magic, fake_sigreturn_bad_size,
fake_sigreturn_bad_size_for_magic0:
- accounting for available space...dropping extra when needed
- keeping alignent
- new testcases on FPSMID context:
+ fake_sigreturn_missing_fpsimd
+ fake_sigreturn_duplicated_fpsimd
Cristian Marussi (10):
kselftest: arm64: introduce new boilerplate code
kselftest: arm64: adds first test and common utils
kselftest: arm64: mangle_pstate_invalid_daif_bits
kselftest: arm64: mangle_pstate_invalid_mode_el
kselftest: arm64: mangle_pstate_ssbs_regs
kselftest: arm64: fake_sigreturn_bad_magic
kselftest: arm64: fake_sigreturn_bad_size_for_magic0
kselftest: arm64: fake_sigreturn_missing_fpsimd
kselftest: arm64: fake_sigreturn_duplicated_fpsimd
kselftest: arm64: fake_sigreturn_bad_size
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/arm64/Makefile | 51 +++
tools/testing/selftests/arm64/README | 43 +++
.../testing/selftests/arm64/signal/.gitignore | 5 +
tools/testing/selftests/arm64/signal/Makefile | 86 +++++
tools/testing/selftests/arm64/signal/README | 59 ++++
.../testing/selftests/arm64/signal/signals.S | 64 ++++
.../arm64/signal/test_arm64_signals.sh | 55 +++
.../selftests/arm64/signal/test_signals.c | 26 ++
.../selftests/arm64/signal/test_signals.h | 141 ++++++++
.../arm64/signal/test_signals_utils.c | 331 ++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 31 ++
.../arm64/signal/testcases/.gitignore | 11 +
.../testcases/fake_sigreturn_bad_magic.c | 63 ++++
.../testcases/fake_sigreturn_bad_size.c | 85 +++++
.../fake_sigreturn_bad_size_for_magic0.c | 57 +++
.../fake_sigreturn_duplicated_fpsimd.c | 62 ++++
.../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++
.../mangle_pstate_invalid_compat_toggle.c | 25 ++
.../mangle_pstate_invalid_daif_bits.c | 28 ++
.../mangle_pstate_invalid_mode_el1.c | 29 ++
.../mangle_pstate_invalid_mode_el2.c | 29 ++
.../mangle_pstate_invalid_mode_el3.c | 29 ++
.../testcases/mangle_pstate_ssbs_regs.c | 56 +++
.../arm64/signal/testcases/testcases.c | 150 ++++++++
.../arm64/signal/testcases/testcases.h | 83 +++++
26 files changed, 1644 insertions(+)
create mode 100644 tools/testing/selftests/arm64/Makefile
create mode 100644 tools/testing/selftests/arm64/README
create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/Makefile
create mode 100644 tools/testing/selftests/arm64/signal/README
create mode 100644 tools/testing/selftests/arm64/signal/signals.S
create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.sh
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
--
2.17.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 01/10] kselftest: arm64: introduce new boilerplate code
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 02/10] kselftest: arm64: adds first test and common utils Cristian Marussi
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a new arm64-specific empty subsystem amongst TARGETS of KSFT build
framework; once populated with testcases, it will be possible to build
and invoke the new KSFT TARGETS=arm64 related tests from the toplevel
Makefile in the usual ways.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/arm64/Makefile | 51 ++++++++++++++++++++++++++
tools/testing/selftests/arm64/README | 43 ++++++++++++++++++++++
3 files changed, 95 insertions(+)
create mode 100644 tools/testing/selftests/arm64/Makefile
create mode 100644 tools/testing/selftests/arm64/README
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 9781ca79794a..4ff0b41ead8a 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
TARGETS = android
+TARGETS += arm64
TARGETS += bpf
TARGETS += breakpoints
TARGETS += capabilities
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
new file mode 100644
index 000000000000..03a0d4f71218
--- /dev/null
+++ b/tools/testing/selftests/arm64/Makefile
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# When ARCH not overridden for crosscompiling, lookup machine
+ARCH ?= $(shell uname -m)
+ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
+
+ifeq ("x$(ARCH)", "xarm64")
+SUBDIRS :=
+else
+SUBDIRS :=
+endif
+
+CFLAGS := -Wall -O2 -g
+
+export CC
+export CFLAGS
+
+all:
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ mkdir -p $$BUILD_TARGET; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+install: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+run_tests: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+# Avoid any output on non arm64 on emit_tests
+emit_tests: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+clean:
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+.PHONY: all clean install run_tests emit_tests
diff --git a/tools/testing/selftests/arm64/README b/tools/testing/selftests/arm64/README
new file mode 100644
index 000000000000..dee3306071cc
--- /dev/null
+++ b/tools/testing/selftests/arm64/README
@@ -0,0 +1,43 @@
+KSelfTest ARM64
+===============
+
+- These tests are arm64 specific and so not built or run but just skipped
+ completely when env-variable ARCH is found to be different than 'arm64'
+ and `uname -m` reports other than 'aarch64'.
+
+- Holding true the above, ARM64 KSFT tests can be run:
+
+ + as standalone (example for signal tests)
+
+ $ make -C tools/testing/selftest/arm64/signal \
+ INSTALL_PATH=<your-installation-path> install
+
+ and then launching on the target device inside the installed path:
+
+ $ <your-installed-path>/test_arm64_signals.sh [-k | -v]
+
+ + within the KSelfTest framework using standard Linux top-level-makefile
+ targets:
+
+ $ make TARGETS=arm64 kselftest-clean
+ $ make TARGETS=arm64 kselftest
+
+ Further details on building and running KFST can be found in:
+ Documentation/dev-tools/kselftest.rst
+
+- Tests can depend on some arch-specific definitions which can be found in a
+ standard Kernel Headers installation in $(top_srcdir)/usr/include.
+ Such Kernel Headers are automatically installed (via make headers_install)
+ by KSFT framework itself in a dedicated directory when tests are launched
+ via KSFT itself; when running standalone, instead, a Warning is issued
+ if such headers cannot be found somewhere (we try to guess a few standard
+ locations anyway)
+
+- Some of these tests may be related to possibly not implemented ARMv8
+ features: depending on their implementation status on the effective HW
+ we'll expect different results. The tests' harness will take care to check
+ at run-time if the required features are supported and will act accordingly.
+ Moreover, in order to avoid any kind of compile-time dependency on the
+ toolchain (possibly due to the above mentioned not-implemented features),
+ we make strictly use of direct 'S3_ sysreg' raw-encoding while checking for
+ those features and/or lookin up sysregs.
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 02/10] kselftest: arm64: adds first test and common utils
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 01/10] kselftest: arm64: introduce new boilerplate code Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 03/10] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added some arm64/signal specific boilerplate and utility code to help
further testcase development. A simple testcase is introduced:
mangle_pstate_invalid_compat_toggle which is a simple mangle testcase
which messes with the ucontext_t from within the sig_handler, trying
to toggle PSTATE state bits to switch the system between 32bit/64bit
execution state. Expects SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
tools/testing/selftests/arm64/Makefile | 2 +-
.../testing/selftests/arm64/signal/.gitignore | 5 +
tools/testing/selftests/arm64/signal/Makefile | 86 +++++++
tools/testing/selftests/arm64/signal/README | 59 +++++
.../arm64/signal/test_arm64_signals.sh | 55 ++++
.../selftests/arm64/signal/test_signals.c | 26 ++
.../selftests/arm64/signal/test_signals.h | 137 ++++++++++
.../arm64/signal/test_signals_utils.c | 240 ++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 28 ++
.../arm64/signal/testcases/.gitignore | 1 +
.../mangle_pstate_invalid_compat_toggle.c | 25 ++
.../arm64/signal/testcases/testcases.c | 150 +++++++++++
.../arm64/signal/testcases/testcases.h | 83 ++++++
13 files changed, 896 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/Makefile
create mode 100644 tools/testing/selftests/arm64/signal/README
create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.sh
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index 03a0d4f71218..af59dc74e0dc 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
ifeq ("x$(ARCH)", "xarm64")
-SUBDIRS :=
+SUBDIRS := signal
else
SUBDIRS :=
endif
diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
new file mode 100644
index 000000000000..7234ebd99363
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/.gitignore
@@ -0,0 +1,5 @@
+# Helper script's internal testcases list (TPROGS) is regenerated
+# each time by Makefile on standalone (non KSFT driven) runs.
+# Committing such list creates a dependency between testcases
+# patches such that they are no more easily revertable. Just ignore.
+test_arm64_signals.sh
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
new file mode 100644
index 000000000000..5ec92a4dba48
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# Supports also standalone invokation out of KSFT-tree
+# Compile standalone and run on your device with:
+#
+# $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
+#
+# Run standalone on device with:
+#
+# $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
+#
+# If INSTALL_PATH= is NOT provided it will default to ./install
+
+# A proper top_srcdir is needed both by KSFT(lib.mk)
+# and standalone builds
+top_srcdir = ../../../../..
+
+CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
+SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
+PROGS := $(patsubst %.c,%,$(SRCS))
+
+# Guessing as best as we can where the Kernel headers
+# could have been installed depending on ENV config and
+# type of invocation.
+ifeq ($(KBUILD_OUTPUT),)
+khdr_dir = $(top_srcdir)/usr/include
+else
+ifeq (0,$(MAKELEVEL))
+khdr_dir = $(KBUILD_OUTPUT)/usr/include
+else
+# the KSFT preferred location when KBUILD_OUTPUT is set
+khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
+endif
+endif
+
+CFLAGS += -I$(khdr_dir)
+
+# Standalone run
+ifeq (0,$(MAKELEVEL))
+CC := $(CROSS_COMPILE)gcc
+RUNNER = test_arm64_signals.sh
+INSTALL_PATH ?= install/
+
+all: $(RUNNER)
+
+$(RUNNER): $(PROGS)
+ sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
+
+install: all
+ mkdir -p $(INSTALL_PATH)/testcases
+ cp $(PROGS) $(INSTALL_PATH)/testcases
+ cp $(RUNNER) $(INSTALL_PATH)/
+
+.PHONY clean:
+ rm -f $(PROGS)
+# KSFT run
+else
+# Generated binaries to be installed by top KSFT script
+TEST_GEN_PROGS := $(notdir $(PROGS))
+
+# Get Kernel headers installed and use them.
+KSFT_KHDR_INSTALL := 1
+
+# This include mk will also mangle the TEST_GEN_PROGS list
+# to account for any OUTPUT target-dirs optionally provided
+# by the toplevel makefile
+include ../../lib.mk
+
+$(TEST_GEN_PROGS): $(PROGS)
+ cp $(PROGS) $(OUTPUT)/
+
+clean:
+ $(CLEAN)
+ rm -f $(PROGS)
+endif
+
+# Common test-unit targets to build common-layout test-cases executables
+# Needs secondary expansion to properly include the testcase c-file in pre-reqs
+.SECONDEXPANSION:
+$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
+ @if [ ! -d $(khdr_dir) ]; then \
+ echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
+ echo "===> Are you sure Kernel Headers have been installed properly ?\n"; \
+ fi
+ $(CC) $(CFLAGS) $^ -o $@
diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
new file mode 100644
index 000000000000..53f005f7910a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/README
@@ -0,0 +1,59 @@
+KSelfTest arm64/signal/
+=======================
+
+Signals Tests
++++++++++++++
+
+- Tests are built around a common main compilation unit: such shared main
+ enforces a standard sequence of operations needed to perform a single
+ signal-test (setup/trigger/run/result/cleanup)
+
+- The above mentioned ops are configurable on a test-by-test basis: each test
+ is described (and configured) using the descriptor signals.h::struct tdescr
+
+- Each signal testcase is compiled into its own executable: a separate
+ executable is used for each test since many tests complete successfully
+ by receiving some kind of fatal signal from the Kernel, so it's safer
+ to run each test unit in its own standalone process, so as to start each
+ test from a clean slate.
+
+- New tests can be simply defined in testcases/ dir providing a proper struct
+ tdescr overriding all the defaults we wish to change (as of now providing a
+ custom run method is mandatory though)
+
+- Signals' test-cases hereafter defined belong currently to two
+ principal families:
+
+ - 'mangle_' tests: a real signal (SIGUSR1) is raised and used as a trigger
+ and then the test case code messes-up with the sigframe ucontext_t from
+ inside the sighandler itself.
+
+ - 'fake_sigreturn_' tests: a brand new custom artificial sigframe structure
+ is placed on the stack and a sigreturn syscall is called to simulate a
+ real signal return. This kind of tests does not use a trigger usually and
+ they are just fired using some simple included assembly trampoline code.
+
+ - Most of these tests are successfully passing if the process gets killed by
+ some fatal signal: usually SIGSEGV or SIGBUS. Since while writing this
+ kind of tests it is extremely easy in fact to end-up injecting other
+ unrelated SEGV bugs in the testcases, it becomes extremely tricky to
+ be really sure that the tests are really addressing what they are meant
+ to address and they are not instead falling apart due to unplanned bugs
+ in the test code.
+ In order to alleviate the misery of the life of such test-developer, a few
+ helpers are provided:
+
+ - a couple of ASSERT_BAD/GOOD_CONTEXT() macros to easily parse a ucontext_t
+ and verify if it is indeed GOOD or BAD (depending on what we were
+ expecting), using the same logic/perspective as in the arm64 Kernel signals
+ routines.
+
+ - a sanity mechanism to be used in 'fake_sigreturn_'-alike tests: enabled by
+ default it takes care to verify that the test-execution had at least
+ successfully progressed up to the stage of triggering the fake sigreturn
+ call.
+
+ In both cases test results are expected in terms of:
+ - some fatal signal sent by the Kernel to the test process
+ or
+ - analyzing some final regs state
diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.sh b/tools/testing/selftests/arm64/signal/test_arm64_signals.sh
new file mode 100755
index 000000000000..163e941e2997
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+ret=0
+keep_on_fail=0
+err_out="2> /dev/null"
+
+usage() {
+ echo "Usage: `basename $0` [-v] [-k]"
+ exit 1
+}
+
+# avoiding getopt to avoid compatibility issues on targets
+# with limited resources
+while [ $# -gt 0 ]
+do
+ case $1 in
+ "-k")
+ keep_on_fail=1
+ ;;
+ "-v")
+ err_out=
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+TPROGS=
+
+tot=$(echo $TPROGS | wc -w)
+
+# Tests are expected in testcases/ subdir inside the installation path
+workdir="`dirname $0 2>/dev/null`"
+[ -n $workdir ] && cd $workdir
+
+passed=0
+run=0
+for test in $TPROGS
+do
+ run=$((run + 1))
+ eval ./$test $err_out
+ if [ $? != 0 ]; then
+ [ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
+ else
+ passed=$((passed + 1))
+ fi
+done
+
+echo "==>> PASSED: $passed/$run on $tot available tests."
+
+exit $ret
diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
new file mode 100644
index 000000000000..a14fa2810a28
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <kselftest.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+
+struct tdescr *current;
+extern struct tdescr tde;
+
+int main(int argc, char *argv[])
+{
+ current = &tde;
+
+ ksft_print_msg("%s :: %s - SIG_TRIG:%d SIG_OK:%d -- current:%p\n",
+ current->name, current->descr, current->sig_trig,
+ current->sig_ok, current);
+ if (test_setup(current)) {
+ if (test_run(current))
+ test_result(current);
+ test_cleanup(current);
+ }
+
+ return !current->pass;
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
new file mode 100644
index 000000000000..85db3ac44b32
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_H__
+#define __TEST_SIGNALS_H__
+
+#include <assert.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <stdint.h>
+
+/*
+ * Using ARCH specific and sanitized Kernel headers installed by KSFT
+ * framework since we asked for it by setting flag KSFT_KHDR_INSTALL
+ * in our Makefile.
+ */
+#include <asm/ptrace.h>
+#include <asm/hwcap.h>
+
+/* pasted from include/linux/stringify.h */
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+/*
+ * Reads a sysreg using the, possibly provided, S3_ encoding in order to
+ * avoid inject any dependency on the used toolchain regarding possibly
+ * still unsupported ARMv8 extensions.
+ *
+ * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
+ * would introduce a compile-time dependency on possibly unsupported ARMv8
+ * Extensions: you could end-up failing to build the test depending on the
+ * available toolchain.
+ * This is undesirable since some tests, even if specifically targeted at some
+ * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
+ * optional ARM features. (SSBS bit preservation is an example: Kernel handles
+ * it transparently not caring at all about the effective set of supported
+ * features).
+ * On the other side we will expect to observe different behaviours if the
+ * feature is supported or not: usually getting a SIGILL when trying to use
+ * unsupported features. For this reason we have anyway in place some
+ * preliminary run-time checks about the cpu effectively supported features.
+ *
+ * This helper macro is meant to be used for regs readable at EL0, BUT some
+ * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
+ * if the required reg is included in the supported encoding space:
+ *
+ * Documentation/arm64/cpu-feature-regsiters.txt
+ *
+ * "The infrastructure emulates only the following system register space:
+ * Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
+ */
+#define get_regval(regname, out) \
+ asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
+
+/* Regs encoding and masks naming copied in from sysreg.h */
+#define SYS_ID_AA64MMFR1_EL1 S3_0_C0_C7_1 /* MRS Emulated */
+#define SYS_ID_AA64MMFR2_EL1 S3_0_C0_C7_2 /* MRS Emulated */
+#define ID_AA64MMFR1_PAN_SHIFT 20
+#define ID_AA64MMFR2_UAO_SHIFT 4
+
+/* Local Helpers */
+#define IS_PAN_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
+#define IS_UAO_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
+
+#define S3_MRS_SSBS_SYSREG S3_3_C4_C2_6 /* EL0 supported */
+
+/*
+ * Feature flags used in tdescr.feats_required to specify
+ * any feature by the test
+ */
+enum {
+ FSSBS_BIT,
+ FPAN_BIT,
+ FUAO_BIT,
+ FMAX_END
+};
+
+#define FEAT_SSBS (1UL << FSSBS_BIT)
+#define FEAT_PAN (1UL << FPAN_BIT)
+#define FEAT_UAO (1UL << FUAO_BIT)
+
+/*
+ * A descriptor used to describe and configure a test case.
+ * Fields with a non-trivial meaning are described inline in the following.
+ */
+struct tdescr {
+ /* KEEP THIS FIELD FIRST for easier lookup from assembly */
+ void *token;
+ /* when disabled token based sanity checking is skipped in handler */
+ bool sanity_disabled;
+ /* just a name for the test-case; manadatory field */
+ char *name;
+ char *descr;
+ unsigned long feats_required;
+ /* bitmask of effectively supported feats: populated at run-time */
+ unsigned long feats_supported;
+ bool feats_ok;
+ bool initialized;
+ unsigned int minsigstksz;
+ /* signum used as a test trigger. Zero if no trigger-signal is used */
+ int sig_trig;
+ /*
+ * signum considered as a successful test completion.
+ * Zero when no signal is expected on success
+ */
+ int sig_ok;
+ /* signum expected on unsupported CPU features. */
+ int sig_unsupp;
+ /* a timeout in second for test completion */
+ unsigned int timeout;
+ bool triggered;
+ bool pass;
+ /* optional sa_flags for the installed handler */
+ int sa_flags;
+ ucontext_t saved_uc;
+
+ /* a setup function to be called before test starts */
+ int (*setup)(struct tdescr *td);
+ void (*cleanup)(struct tdescr *td);
+
+ /* an optional function to be used as a trigger for test starting */
+ int (*trigger)(struct tdescr *td);
+ /*
+ * the actual test-core: invoked differently depending on the
+ * presence of the trigger function above; this is mandatory
+ */
+ int (*run)(struct tdescr *td, siginfo_t *si, ucontext_t *uc);
+
+ /* an optional function for custom results' processing */
+ void (*check_result)(struct tdescr *td);
+
+ void *priv;
+};
+#endif
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
new file mode 100644
index 000000000000..203deac4aa8a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/auxv.h>
+#include <linux/auxvec.h>
+#include <ucontext.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+#include "testcases/testcases.h"
+
+extern struct tdescr *current;
+
+static char *feats_store[FMAX_END] = {
+ "SSBS",
+ "PAN",
+ "UAO"
+};
+
+#define MAX_FEATS_SZ 128
+static inline char *feats_to_string(unsigned long feats)
+{
+ static char feats_string[MAX_FEATS_SZ];
+
+ for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
+ if (feats & 1UL << i)
+ snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
+ feats_string, feats_store[i]);
+ }
+
+ return feats_string;
+}
+
+static void unblock_signal(int signum)
+{
+ sigset_t sset;
+
+ sigemptyset(&sset);
+ sigaddset(&sset, signum);
+ sigprocmask(SIG_UNBLOCK, &sset, NULL);
+}
+
+static void default_result(struct tdescr *td, bool force_exit)
+{
+ if (td->pass)
+ SAFE_WRITE(2, "==>> completed. PASS(1)\n");
+ else
+ SAFE_WRITE(1, "==>> completed. FAIL(0)\n");
+ if (force_exit)
+ exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static inline bool are_feats_ok(struct tdescr *td)
+{
+ return td ? td->feats_required == td->feats_supported : 0;
+}
+
+static void default_handler(int signum, siginfo_t *si, void *uc)
+{
+ if (current->sig_trig && signum == current->sig_trig) {
+ SAFE_WRITE(2, "Handling SIG_TRIG\n");
+ current->triggered = 1;
+ /* ->run was asserted NON-NULL in test_setup() already */
+ current->run(current, si, uc);
+ } else if (signum == SIGILL && !current->initialized) {
+ /*
+ * A SIGILL here while still not initialized means we failed
+ * even to asses the existence of features during init
+ */
+ SAFE_WRITE(1, "Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
+ current->feats_supported = 0;
+ } else if (current->sig_ok && signum == current->sig_ok) {
+ /* it's a bug in the test code when this assert fail */
+ assert(!current->sig_trig || current->triggered);
+ if (!current->sanity_disabled) {
+ fprintf(stderr,
+ "SIG_OK -- si_addr@:0x%p token@:0x%p\n",
+ si->si_addr, current->token);
+ assert(current->token);
+ }
+ SAFE_WRITE(2, "Handling SIG_OK\n");
+ current->pass = 1;
+ /*
+ * Some tests can lead to SEGV loops: in such a case we want
+ * to terminate immediately exiting straight away
+ */
+ default_result(current, 1);
+ } else {
+ if (signum == current->sig_unsupp && !are_feats_ok(current)) {
+ SAFE_WRITE(2, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
+ current->pass = 1;
+ } else if (signum == SIGALRM && current->timeout) {
+ SAFE_WRITE(2, "-- Timeout !\n");
+ } else {
+ fprintf(stderr,
+ "-- RX UNEXPECTED SIGNAL: %d\n", signum);
+ }
+ default_result(current, 1);
+ }
+}
+
+static int default_setup(struct tdescr *td)
+{
+ struct sigaction sa;
+
+ sa.sa_sigaction = default_handler;
+ sa.sa_flags = SA_SIGINFO;
+ if (td->sa_flags)
+ sa.sa_flags |= td->sa_flags;
+ sigemptyset(&sa.sa_mask);
+ /* uncatchable signals naturally skipped ... */
+ for (int sig = 1; sig < 32; sig++)
+ sigaction(sig, &sa, NULL);
+ /*
+ * RT Signals default disposition is Term but they cannot be
+ * generated by the Kernel in response to our tests; so just catch
+ * them all and report them as UNEXPECTED signals.
+ */
+ for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
+ sigaction(sig, &sa, NULL);
+
+ /* just in case...unblock explicitly all we need */
+ if (td->sig_trig)
+ unblock_signal(td->sig_trig);
+ if (td->sig_ok)
+ unblock_signal(td->sig_ok);
+ if (td->sig_unsupp)
+ unblock_signal(td->sig_unsupp);
+
+ if (td->timeout) {
+ unblock_signal(SIGALRM);
+ alarm(td->timeout);
+ }
+ fprintf(stderr, "Registered handlers for all signals.\n");
+
+ return 1;
+}
+
+static inline int default_trigger(struct tdescr *td)
+{
+ return !raise(td->sig_trig);
+}
+
+static int test_init(struct tdescr *td)
+{
+ td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
+ if (!td->minsigstksz)
+ td->minsigstksz = MINSIGSTKSZ;
+ fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
+
+ if (td->feats_required) {
+ bool feats_ok = false;
+ td->feats_supported = 0;
+ /*
+ * Checking for CPU required features using both the
+ * auxval and the arm64 MRS Emulation to read sysregs.
+ */
+ if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
+ uint64_t val = 0;
+
+ if (td->feats_required & FEAT_SSBS) {
+ /* Uses HWCAP to check capability */
+ if (getauxval(AT_HWCAP) & HWCAP_SSBS)
+ td->feats_supported |= FEAT_SSBS;
+ }
+ if (td->feats_required & FEAT_PAN) {
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR1_EL1, val);
+ if (IS_PAN_SUPPORTED(val))
+ td->feats_supported |= FEAT_PAN;
+ }
+ if (td->feats_required & FEAT_UAO) {
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR2_EL1 , val);
+ if (IS_UAO_SUPPORTED(val))
+ td->feats_supported |= FEAT_UAO;
+ }
+ } else {
+ fprintf(stderr,
+ "HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
+ }
+ feats_ok = are_feats_ok(td);
+ fprintf(stderr,
+ "Required Features: [%s] %ssupported\n",
+ feats_ok ? feats_to_string(td->feats_supported) :
+ feats_to_string(td->feats_required ^ td->feats_supported),
+ !feats_ok ? "NOT " : "");
+ }
+
+ td->initialized = 1;
+ return 1;
+}
+
+int test_setup(struct tdescr *td)
+{
+ /* assert core invariants symptom of a rotten testcase */
+ assert(current);
+ assert(td);
+ assert(td->name);
+ assert(td->run);
+
+ if (!test_init(td))
+ return 0;
+
+ if (td->setup)
+ return td->setup(td);
+ else
+ return default_setup(td);
+}
+
+int test_run(struct tdescr *td)
+{
+ if (td->sig_trig) {
+ if (td->trigger)
+ return td->trigger(td);
+ else
+ return default_trigger(td);
+ } else {
+ return td->run(td, NULL, NULL);
+ }
+}
+
+void test_result(struct tdescr *td)
+{
+ if (td->check_result)
+ td->check_result(td);
+ default_result(td, 0);
+}
+
+void test_cleanup(struct tdescr *td)
+{
+ if (td->cleanup)
+ td->cleanup(td);
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
new file mode 100644
index 000000000000..7d80a478bad9
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_UTILS_H__
+#define __TEST_SIGNALS_UTILS_H__
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <string.h>
+
+#include <asm/unistd.h>
+
+#include "test_signals.h"
+
+/* Using a signal-safe function to write something out */
+#define SAFE_WRITE(fd, str) do { \
+ int bytes = 0; \
+ bytes += write((fd), (str) + bytes, sizeof(str) - bytes); \
+ if (bytes < 0 || bytes == sizeof(str)) \
+ break; \
+} while(1)
+
+int test_setup(struct tdescr *td);
+void test_cleanup(struct tdescr *td);
+int test_run(struct tdescr *td);
+void test_result(struct tdescr *td);
+#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
new file mode 100644
index 000000000000..8651272e3cfc
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -0,0 +1 @@
+mangle_pstate_invalid_compat_toggle
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
new file mode 100644
index 000000000000..971193e7501b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /* This config should trigger a SIGSEGV by Kernel */
+ uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
+ .descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
new file mode 100644
index 000000000000..a59785092e1f
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -0,0 +1,150 @@
+#include "testcases.h"
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+ size_t resv_sz, size_t *offset)
+{
+ size_t offs = 0;
+ struct _aarch64_ctx *found = NULL;
+
+ if (!head || resv_sz < HDR_SZ)
+ return found;
+
+ do {
+ if (head->magic == magic) {
+ found = head;
+ break;
+ }
+ offs += head->size;
+ head = GET_RESV_NEXT_HEAD(head);
+ } while (offs < resv_sz - HDR_SZ);
+
+ if (offset)
+ *offset = offs;
+
+ return found;
+}
+
+bool validate_extra_context(struct extra_context *extra, char **err)
+{
+ struct _aarch64_ctx *term;
+
+ if (!extra || !err)
+ return false;
+
+ fprintf(stderr, "Validating EXTRA...\n");
+ term = GET_RESV_NEXT_HEAD(extra);
+ if (!term || term->magic || term->size) {
+ *err = "UN-Terminated EXTRA context";
+ return false;
+ }
+ if (extra->datap & 0x0fUL)
+ *err = "Extra DATAP misaligned";
+ else if (extra->size & 0x0fUL)
+ *err = "Extra SIZE misaligned";
+ else if (extra->datap != (uint64_t)term + sizeof(*term))
+ *err = "Extra DATAP misplaced (not contiguos)";
+ if (*err)
+ return false;
+
+ return true;
+}
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
+{
+ bool terminated = false;
+ size_t offs = 0;
+ int flags = 0;
+ struct extra_context *extra = NULL;
+ struct _aarch64_ctx *head =
+ (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
+
+ if (!err)
+ return false;
+ /* Walk till the end terminator verifying __reserved contents */
+ while (head && !terminated && offs < resv_sz) {
+ if ((uint64_t)head & 0x0fUL) {
+ *err = "Misaligned HEAD";
+ return false;
+ }
+
+ switch (head->magic) {
+ case 0:
+ if (head->size)
+ *err = "Bad size for MAGIC0";
+ else
+ terminated = true;
+ break;
+ case FPSIMD_MAGIC:
+ if (flags & FPSIMD_CTX)
+ *err = "Multiple FPSIMD_MAGIC";
+ else if (head->size !=
+ sizeof(struct fpsimd_context))
+ *err = "Bad size for fpsimd_context";
+ flags |= FPSIMD_CTX;
+ break;
+ case ESR_MAGIC:
+ if (head->size != sizeof(struct esr_context))
+ fprintf(stderr,
+ "Bad size for esr_context is not an error...just ignore.\n");
+ break;
+ case SVE_MAGIC:
+ if (flags & SVE_CTX)
+ *err = "Multiple SVE_MAGIC";
+ else if (head->size !=
+ sizeof(struct sve_context))
+ *err = "Bad size for sve_context";
+ flags |= SVE_CTX;
+ break;
+ case EXTRA_MAGIC:
+ if (flags & EXTRA_CTX)
+ *err = "Multiple EXTRA_MAGIC";
+ else if (head->size !=
+ sizeof(struct extra_context))
+ *err = "Bad size for extra_context";
+ flags |= EXTRA_CTX;
+ extra = (struct extra_context *)head;
+ break;
+ case KSFT_BAD_MAGIC:
+ /*
+ * This is a BAD magic header defined
+ * artificially by a testcase and surely
+ * unknown to the Kernel parse_user_sigframe().
+ * It MUST cause a Kernel induced SEGV
+ */
+ *err = "BAD MAGIC !";
+ break;
+ default:
+ /*
+ * A still unknown Magic: potentially freshly added
+ * to the Kernel code and still unknown to the
+ * tests.
+ */
+ fprintf(stdout,
+ "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
+ head->magic);
+ break;
+ }
+
+ if (*err)
+ return false;
+
+ offs += head->size;
+ if (resv_sz - offs < sizeof(*head)) {
+ *err = "HEAD Overrun";
+ return false;
+ }
+
+ if (flags & EXTRA_CTX)
+ if (!validate_extra_context(extra, err))
+ return false;
+
+ head = GET_RESV_NEXT_HEAD(head);
+ }
+
+ if (terminated && !(flags & FPSIMD_CTX)) {
+ *err = "Missing FPSIMD";
+ return false;
+ }
+
+ return true;
+}
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
new file mode 100644
index 000000000000..624717c71b1d
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -0,0 +1,83 @@
+#ifndef __TESTCASES_H__
+#define __TESTCASES_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <assert.h>
+
+/* Architecture specific sigframe definitions */
+#include <asm/sigcontext.h>
+
+#define FPSIMD_CTX (1 << 0)
+#define SVE_CTX (1 << 1)
+#define EXTRA_CTX (1 << 2)
+
+#define KSFT_BAD_MAGIC 0xdeadbeef
+
+#define HDR_SZ \
+ sizeof(struct _aarch64_ctx)
+
+#define GET_SF_RESV_HEAD(sf) \
+ (struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
+
+#define GET_SF_RESV_SIZE(sf) \
+ sizeof((sf).uc.uc_mcontext.__reserved)
+
+#define GET_UCP_RESV_SIZE(ucp) \
+ sizeof((ucp)->uc_mcontext.__reserved)
+
+#define ASSERT_BAD_CONTEXT(uc) do { \
+ char *err = NULL; \
+ assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
+ if (err) \
+ fprintf(stderr, \
+ "Using badly built context - ERR: %s\n", err); \
+} while(0)
+
+#define ASSERT_GOOD_CONTEXT(uc) do { \
+ char *err = NULL; \
+ if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) { \
+ if (err) \
+ fprintf(stderr, \
+ "Detected BAD context - ERR: %s\n", err);\
+ assert(0); \
+ } else { \
+ fprintf(stderr, "uc context validated.\n"); \
+ } \
+} while(0)
+
+/* head->size accounts both for payload and header _aarch64_ctx size ! */
+#define GET_RESV_NEXT_HEAD(h) \
+ (struct _aarch64_ctx *)((char *)(h) + (h)->size)
+
+struct fake_sigframe {
+ siginfo_t info;
+ ucontext_t uc;
+};
+
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
+
+bool validate_extra_context(struct extra_context *extra, char **err);
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+ size_t resv_sz, size_t *offset);
+
+static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
+ size_t resv_sz,
+ size_t *offset)
+{
+ return get_header(head, 0, resv_sz, offset);
+}
+
+static inline void write_terminator_record(struct _aarch64_ctx *tail)
+{
+ if (tail) {
+ tail->magic = 0;
+ tail->size = 0;
+ }
+}
+#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 03/10] kselftest: arm64: mangle_pstate_invalid_daif_bits
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 01/10] kselftest: arm64: introduce new boilerplate code Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 02/10] kselftest: arm64: adds first test and common utils Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 04/10] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to set PSTATE DAIF bits to an
invalid value (masking everything).
Expects SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../mangle_pstate_invalid_daif_bits.c | 28 +++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8651272e3cfc..8a0a29f0cc2a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1 +1,2 @@
mangle_pstate_invalid_compat_toggle
+mangle_pstate_invalid_daif_bits
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
new file mode 100644
index 000000000000..af899d4bb655
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel when it checks
+ * the sigframe consistency in valid_user_regs() routine.
+ */
+ uc->uc_mcontext.pstate |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_DAIF_BITS",
+ .descr = "Mangling uc_mcontext with INVALID DAIF_BITS",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 04/10] kselftest: arm64: mangle_pstate_invalid_mode_el
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (2 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 03/10] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 05/10] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added 3 simple mangle testcases that mess with the ucontext_t
from within the sig_handler, trying to toggle PSTATE mode bits to
trick the system into switching to EL1/EL2/EL3.
Expects SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 3 ++
.../mangle_pstate_invalid_mode_el1.c | 29 +++++++++++++++++++
.../mangle_pstate_invalid_mode_el2.c | 29 +++++++++++++++++++
.../mangle_pstate_invalid_mode_el3.c | 29 +++++++++++++++++++
4 files changed, 90 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8a0a29f0cc2a..226bb179b673 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1,2 +1,5 @@
mangle_pstate_invalid_compat_toggle
mangle_pstate_invalid_daif_bits
+mangle_pstate_invalid_mode_el1
+mangle_pstate_invalid_mode_el2
+mangle_pstate_invalid_mode_el3
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
new file mode 100644
index 000000000000..07aed7624383
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL1t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL1t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL1t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
new file mode 100644
index 000000000000..0fe7f69efb33
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL2t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL2t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL2t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
new file mode 100644
index 000000000000..61131dd6ca0c
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL3t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL3t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL3t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 05/10] kselftest: arm64: mangle_pstate_ssbs_regs
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (3 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 04/10] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 06/10] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to toggle PSTATE SSBS bit.
Expect SIGILL if SSBS feature unsupported or that the value set in
PSTATE.SSBS is preserved on test PASS.
This commit also introduces a new common utility function:
get_current_context() which can be used to grab a ucontext without
the help of libc, and detect if such ucontext has been actively used
to jump back into it.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../selftests/arm64/signal/test_signals.h | 4 +
.../arm64/signal/test_signals_utils.c | 91 +++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 2 +
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/mangle_pstate_ssbs_regs.c | 56 ++++++++++++
5 files changed, 154 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 85db3ac44b32..37bed0590226 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -116,6 +116,10 @@ struct tdescr {
/* optional sa_flags for the installed handler */
int sa_flags;
ucontext_t saved_uc;
+ /* used by get_current_ctx() */
+ size_t live_sz;
+ ucontext_t *live_uc;
+ volatile bool live_uc_valid;
/* a setup function to be called before test starts */
int (*setup)(struct tdescr *td);
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index 203deac4aa8a..ac438fd123f1 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -17,6 +17,8 @@
extern struct tdescr *current;
+static int sig_copyctx = SIGUSR2;
+
static char *feats_store[FMAX_END] = {
"SSBS",
"PAN",
@@ -37,6 +39,85 @@ static inline char *feats_to_string(unsigned long feats)
return feats_string;
}
+/*
+ * Obtaining a valid and full-blown ucontext_t from userspace is tricky:
+ * libc getcontext does() not save all the regs and messes with some of
+ * them (pstate value in particular is not reliable).
+ * Here we use a service signal to grab the ucontext_t from inside a
+ * dedicated signal handler, since there, it is populated by Kernel
+ * itself in setup_sigframe(). The grabbed context is then stored and
+ * made available in td->live_uc.
+ *
+ * Anyway this function really serves a dual purpose:
+ *
+ * 1. grab a valid sigcontext into td->live_uc for result analysis: in
+ * such case it returns 1.
+ *
+ * 2. detect if somehow a previously grabbed live_uc context has been
+ * used actively with a sigreturn: in such a case the execution would have
+ * magically resumed in the middle of the function itself (seen_already==1):
+ * in such a case return 0, since in fact we have not just simply grabbed
+ * the context.
+ *
+ * This latter case is useful to detect when a fake_sigreturn test-case has
+ * unexpectedly survived without hittig a SEGV.
+ */
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc)
+{
+ static volatile sig_atomic_t seen_already;
+
+ if (!td || !dest_uc) {
+ fprintf(stdout, "Signal-based Context dumping NOT available\n");
+ return 0;
+ }
+
+ /* it's a genuine invokation..reinit */
+ seen_already = 0;
+ td->live_uc_valid = 0;
+ td->live_sz = sizeof(*dest_uc);
+ memset(dest_uc, 0x00, td->live_sz);
+ td->live_uc = dest_uc;
+ /*
+ * Grab ucontext_t triggering a signal...
+ * ASM equivalent of raise(sig_copyctx);
+ *
+ * Note that:
+ * - live_uc_valid is declared volatile in struct tdescr
+ * since it will be changed inside the sig_copyctx handler.
+ * - the kill() syscall invocation returns only after any possible
+ * registered sig_handler for the invoked signal has returned,
+ * so that live_uc_valid flag is surely up to date when this
+ * function return it.
+ * - the additional 'memory' clobber is there to avoid possible
+ * compiler's assumption on the content pointed by dest_uc, which
+ * is changed inside the handler, but not referenced here anyway.
+ */
+ asm volatile ("mov x8, %0\n\t"
+ "svc #0\n\t"
+ "mov x1, %1\n\t"
+ "mov x8, %2\n\t"
+ "svc #0"
+ :
+ : "i" (__NR_getpid),
+ "r" (sig_copyctx),
+ "i" (__NR_kill)
+ : "x1","x8","x0","memory");
+ /*
+ * If we get here with seen_already==1 it implies the td->live_uc
+ * context has been used to get back here....this probably means
+ * a test has failed to cause a SEGV...anyway the live_uc has not
+ * just been acquired...so return 0
+ */
+ if (seen_already) {
+ fprintf(stdout,
+ "Successful sigreturn detected: live_uc is stale !\n");
+ return 0;
+ }
+ seen_already = 1;
+
+ return td->live_uc_valid;
+}
+
static void unblock_signal(int signum)
{
sigset_t sset;
@@ -91,6 +172,12 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
* to terminate immediately exiting straight away
*/
default_result(current, 1);
+ } else if (signum == sig_copyctx && current->live_uc) {
+ memcpy(current->live_uc, uc, current->live_sz);
+ ASSERT_GOOD_CONTEXT(current->live_uc);
+ current->live_uc_valid = 1;
+ SAFE_WRITE(2,
+ "GOOD CONTEXT grabbed from sig_copyctx handler\n");
} else {
if (signum == current->sig_unsupp && !are_feats_ok(current)) {
SAFE_WRITE(2, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
@@ -193,6 +280,10 @@ static int test_init(struct tdescr *td)
!feats_ok ? "NOT " : "");
}
+ if (td->sig_trig == sig_copyctx)
+ sig_copyctx = SIGUSR1;
+ unblock_signal(sig_copyctx);
+
td->initialized = 1;
return 1;
}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 7d80a478bad9..b37167c98ccd 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -25,4 +25,6 @@ int test_setup(struct tdescr *td);
void test_cleanup(struct tdescr *td);
int test_run(struct tdescr *td);
void test_result(struct tdescr *td);
+
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 226bb179b673..a48a118b1a1a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -3,3 +3,4 @@ mangle_pstate_invalid_daif_bits
mangle_pstate_invalid_mode_el1
mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
+mangle_pstate_ssbs_regs
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
new file mode 100644
index 000000000000..a399d9aa40d5
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_ssbs_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /* set bit value */
+ uc->uc_mcontext.pstate |= PSR_SSBS_BIT;
+ fprintf(stderr, "SSBS set to 1 -- PSTATE: 0x%016lX\n",
+ uc->uc_mcontext.pstate);
+ /* Save after mangling...it should be preserved */
+ td->saved_uc = *uc;
+
+ return 1;
+}
+
+static void pstate_ssbs_bit_checks(struct tdescr *td)
+{
+ uint64_t val = 0;
+ ucontext_t uc;
+
+ /* This check reports some result even if MRS SSBS unsupported */
+ if (get_current_context(td, &uc))
+ fprintf(stderr,
+ "INFO: live_uc - got PSTATE: 0x%016lX -> SSBS %s\n",
+ uc.uc_mcontext.pstate,
+ (td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT) ==
+ (uc.uc_mcontext.pstate & PSR_SSBS_BIT) ?
+ "PRESERVED" : "CLEARED");
+
+ fprintf(stderr, "Checking with MRS SSBS...\n");
+ get_regval(S3_MRS_SSBS_SYSREG, val);
+ fprintf(stderr, "INFO: MRS SSBS - got: 0x%016lX\n", val);
+ /* pass when preserved */
+ td->pass = (val & PSR_SSBS_BIT) ==
+ (td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT);
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_SSBS_REGS",
+ .descr = "Mangling uc_mcontext changing SSBS.(PRESERVE)",
+ .feats_required = FEAT_SSBS,
+ .sig_trig = SIGUSR1,
+ .sig_unsupp = SIGILL,
+ .run = mangle_invalid_pstate_ssbs_run,
+ .check_result = pstate_ssbs_bit_checks,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 06/10] kselftest: arm64: fake_sigreturn_bad_magic
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (4 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 05/10] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 07/10] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a bad magic header and place it onto the stack.
Expects a SIGSEGV on test PASS.
This commit also introduces a common utility assembly function to
invoke a sigreturn using a fake provided sigframe.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
tools/testing/selftests/arm64/signal/Makefile | 2 +-
.../testing/selftests/arm64/signal/signals.S | 64 +++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 1 +
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_bad_magic.c | 63 ++++++++++++++++++
5 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/arm64/signal/signals.S
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
index 5ec92a4dba48..fbef7986f8c8 100644
--- a/tools/testing/selftests/arm64/signal/Makefile
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -78,7 +78,7 @@ endif
# Common test-unit targets to build common-layout test-cases executables
# Needs secondary expansion to properly include the testcase c-file in pre-reqs
.SECONDEXPANSION:
-$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
+$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
@if [ ! -d $(khdr_dir) ]; then \
echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
echo "===> Are you sure Kernel Headers have been installed properly ?\n"; \
diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
new file mode 100644
index 000000000000..6262b877400b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/signals.S
@@ -0,0 +1,64 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2019 ARM Limited
+ */
+
+#include <asm/unistd.h>
+
+.section ".rodata", "a"
+call_fmt:
+ .asciz "Calling sigreturn with fake sigframe sized:%zd at calculated SP @%08lX\n"
+
+.text
+
+.globl fake_sigreturn
+
+/* fake_sigreturn x0:&sigframe, x1:sigframe_size, x2:alignment_SP */
+fake_sigreturn:
+ mov x20, x0
+ mov x21, x1
+ mov x22, x2
+ mov x23, sp
+
+ /* create space on the stack for fake sigframe..."x22"-aligned */
+ mov x0, #0
+ add x0, x21, x22
+ sub x22, x22, #1
+ bic x0, x0, x22
+ sub x23, x23, x0
+
+ ldr x0, =call_fmt
+ mov x1, x21
+ mov x2, x23
+ bl printf
+
+ mov sp, x23
+
+ /* now fill it with the provided content... */
+ mov x0, sp
+ mov x1, x20
+ mov x2, x21
+ bl memcpy
+
+ /*
+ * Here saving a last minute SP to current->token acts as a marker:
+ * if we got here, we are successfully faking a sigreturn; in other
+ * words we are sure no bad fatal signal has been raised till now
+ * for unrelated reasons, so we should consider the possibl observed
+ * fatal signal like SEGV coming from Kernel restore_sigframe() and
+ * triggered as expected from our test-case.
+ * For simplicity this assumes that current field 'token' is laid out
+ * as first in struct tdescr
+ */
+ ldr x0, current
+ str x23, [x0]
+ /* SP is already pointing back to the just built fake sigframe here */
+ mov x8, #__NR_rt_sigreturn
+ svc #0
+
+ /*
+ * Above sigreturn should not return...looping here leads to a timeout
+ * and ensure proper and clean test failure, instead of jumping around
+ * on a potentially corrupted stack.
+ */
+ b .
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index b37167c98ccd..cdf3018aa1aa 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -27,4 +27,5 @@ int test_run(struct tdescr *td);
void test_result(struct tdescr *td);
bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
+int fake_sigreturn(void *sigframe, size_t sz, int alignment);
#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index a48a118b1a1a..0ea6fdc3765c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -4,3 +4,4 @@ mangle_pstate_invalid_mode_el1
mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
+fake_sigreturn_bad_magic
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
new file mode 100644
index 000000000000..b4c063e02a7a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_bad_magic_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
+ * and the other for the usual terminator.
+ */
+ if (head && resv_sz - offset < HDR_SZ * 2) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /*
+ * use a well known NON existent bad magic...something
+ * we should pretty sure won't be ever defined in Kernel
+ */
+ head->magic = KSFT_BAD_MAGIC;
+ head->size = HDR_SZ;
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_MAGIC",
+ .descr = "Triggers a fake sigreturn with a sigframe including a bad non-existent magic",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_magic_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 07/10] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (5 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 06/10] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 08/10] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized magic0 header and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../fake_sigreturn_bad_size_for_magic0.c | 57 +++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 0ea6fdc3765c..cf2a73599818 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -5,3 +5,4 @@ mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
+fake_sigreturn_bad_size_for_magic0
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
new file mode 100644
index 000000000000..2f53c4740c85
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN 16
+
+static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least HDR_SZ + 16 space for the bad sized terminator.
+ */
+ if (head && resv_sz - offset < HDR_SZ + MIN_SZ_ALIGN) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ + MIN_SZ_ALIGN) {
+ head->magic = 0;
+ head->size = MIN_SZ_ALIGN;
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE_FOR_MAGIC0",
+ .descr = "Triggers a fake sigreturn with a sigframe including a bad non-zero size magic0",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_for_magic0_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 08/10] kselftest: arm64: fake_sigreturn_missing_fpsimd
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (6 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 07/10] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 09/10] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 10/10] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple fake_sigreturn testcase which builds a ucontext_t
without the required fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index cf2a73599818..17d1c5e73319 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -6,3 +6,4 @@ mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
+fake_sigreturn_missing_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
new file mode 100644
index 000000000000..b8dd57ce6844
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ head = get_header(head, FPSIMD_MAGIC, resv_sz, &offset);
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /* Just overwrite fpsmid_context */
+ write_terminator_record(head);
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_MISSING_FPSIMD",
+ .descr = "Triggers a fake sigreturn with a sigframe missing the mandatory fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_missing_fpsimd_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 09/10] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (7 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 08/10] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 10/10] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple fake_sigreturn testcase which builds a ucontext_t
with an anomalous additional fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../fake_sigreturn_duplicated_fpsimd.c | 62 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 17d1c5e73319..94f9baaf638c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -7,3 +7,4 @@ mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
fake_sigreturn_missing_fpsimd
+fake_sigreturn_duplicated_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
new file mode 100644
index 000000000000..09af7a0f8776
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least space for one additional fpsimd_context
+ */
+ if (head && resv_sz - offset < sizeof(struct fpsimd_context)) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+
+ /* just give up and timeout if still not enough space */
+ if (head &&
+ resv_sz - offset >= sizeof(struct fpsimd_context) + HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /* Add a spurios fpsimd_context */
+ head->magic = FPSIMD_MAGIC;
+ head->size = sizeof(struct fpsimd_context);
+ /* and terminate */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_DUPLICATED_FPSIMD",
+ .descr = "Triggers a fake sigreturn with a sigframe including two fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_duplicated_fpsimd_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 10/10] kselftest: arm64: fake_sigreturn_bad_size
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
` (8 preceding siblings ...)
2019-07-03 16:35 ` [PATCH v2 09/10] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
@ 2019-07-03 16:35 ` Cristian Marussi
9 siblings, 0 replies; 11+ messages in thread
From: Cristian Marussi @ 2019-07-03 16:35 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: dave.martin, andreyknvl
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized header that causes a overrun in the __reserved
area and place it onto the stack. Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_bad_size.c | 85 +++++++++++++++++++
2 files changed, 86 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 94f9baaf638c..3408e0f5ba98 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -8,3 +8,4 @@ fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
fake_sigreturn_missing_fpsimd
fake_sigreturn_duplicated_fpsimd
+fake_sigreturn_bad_size
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
new file mode 100644
index 000000000000..1467fb534d8b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN 16
+
+static int fake_sigreturn_bad_size_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, need_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least for the bad sized esr_context.
+ */
+ need_sz = HDR_SZ + sizeof(struct esr_context);
+ if (head && resv_sz - offset < need_sz) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= need_sz) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /*
+ * Use an esr_context to build a fake header with a
+ * size greater then the free __reserved area minus HDR_SZ;
+ * using ESR_MAGIC here since it is not checked for size nor
+ * is limited to one instance.
+ *
+ * At first inject an additional normal esr_context
+ */
+ head->magic = ESR_MAGIC;
+ head->size = sizeof(struct esr_context);
+ /* and terminate properly */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+ ASSERT_GOOD_CONTEXT(&sf.uc);
+
+ /*
+ * now mess with fake esr_context size: leaving less space than
+ * neededwhile keeping size value 16-aligned
+ *
+ * It must trigger a SEGV from Kernel on:
+ *
+ * resv_sz - offset < sizeof(*head)
+ */
+ /* at first set the maximum good 16-aligned size */
+ head->size = (resv_sz - offset - need_sz + MIN_SZ_ALIGN) & ~0xfUL;
+ /* plus a bit more of 16-aligned sized stuff */
+ head->size += MIN_SZ_ALIGN;
+ /* and terminate properly */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE",
+ .descr = "Triggers a fake sigreturn with a sigframe including a badly sized header which overruns the __reserved area",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2019-07-03 16:36 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-03 16:35 [PATCH v2 00/10] Add arm64/signal initial kselftest support Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 01/10] kselftest: arm64: introduce new boilerplate code Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 02/10] kselftest: arm64: adds first test and common utils Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 03/10] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 04/10] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 05/10] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 06/10] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 07/10] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 08/10] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 09/10] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
2019-07-03 16:35 ` [PATCH v2 10/10] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).