* [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 11:15 ` Dave Martin
2019-10-09 8:26 ` [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils Cristian Marussi
` (10 subsequent siblings)
11 siblings, 1 reply; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Modify KSFT arm64 toplevel Makefile to maintain arm64 kselftests organized
by subsystem, keeping them into distinct subdirectories under arm64 custom
KSFT directory: tools/testing/selftests/arm64/
Add to such toplevel Makefile a mechanism to guess the effective location
of Kernel headers as installed by KSFT framework.
Fit existing arm64 tags kselftest into this new schema moving them into
their own subdirectory (arm64/tags).
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
Based on:
commit 9ce1263033cd ("selftests, arm64: add a selftest for passing
tagged pointers to kernel")
---
v6 --> v7
- renamed SUBTARGETS to ARM64_SUBTARGETS to avoid name clashes
- rebased on v5.4-rc2 accounting for further new patches on top of commit 9ce1263033cd
v5 --> v6
- using realpath to avoid passing down relative paths
- fix commit msg & Copyright
- removed unneded Makefile export
- added SUBTARGETS specification, to allow building specific only some
arm64 test subsystems
v4 --> v5
- rebased on arm64/for-next/core
- merged this patch with KSFT arm64 tags patch, while moving the latter
into its own subdir
- moved kernel header includes search mechanism from KSFT arm64
SIGNAL Makefile
- export proper top_srcdir ENV for lib.mk
v3 --> v4
- comment reword
- simplified documentation in README
- dropped README about standalone
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/arm64/Makefile | 64 +++++++++++++++++--
tools/testing/selftests/arm64/README | 25 ++++++++
tools/testing/selftests/arm64/tags/Makefile | 7 ++
.../arm64/{ => tags}/run_tags_test.sh | 0
.../selftests/arm64/{ => tags}/tags_test.c | 0
6 files changed, 92 insertions(+), 5 deletions(-)
create mode 100644 tools/testing/selftests/arm64/README
create mode 100644 tools/testing/selftests/arm64/tags/Makefile
rename tools/testing/selftests/arm64/{ => tags}/run_tags_test.sh (100%)
rename tools/testing/selftests/arm64/{ => tags}/tags_test.c (100%)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index c3feccb99ff5..b7c8ad3d0b34 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
index f9f79fb272f0..cd27ca689224 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -1,12 +1,66 @@
# SPDX-License-Identifier: GPL-2.0
-# ARCH can be overridden by the user for cross compiling
+# When ARCH not overridden for crosscompiling, lookup machine
ARCH ?= $(shell uname -m 2>/dev/null || echo not)
ifneq (,$(filter $(ARCH),aarch64 arm64))
-CFLAGS += -I../../../../usr/include/
-TEST_GEN_PROGS := tags_test
-TEST_PROGS := run_tags_test.sh
+ARM64_SUBTARGETS ?= tags
+else
+ARM64_SUBTARGETS :=
endif
-include ../lib.mk
+CFLAGS := -Wall -O2 -g
+
+# A proper top_srcdir is needed by KSFT(lib.mk)
+top_srcdir = $(realpath ../../../../)
+
+# Additional include paths needed by kselftest.h and local headers
+CFLAGS += -I$(top_srcdir)/tools/testing/selftests/
+
+# Guessing where the Kernel headers could have been installed
+# depending on ENV config
+ifeq ($(KBUILD_OUTPUT),)
+khdr_dir = $(top_srcdir)/usr/include
+else
+# the KSFT preferred location when KBUILD_OUTPUT is set
+khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
+endif
+
+CFLAGS += -I$(khdr_dir)
+
+export CFLAGS
+export top_srcdir
+
+all:
+ @for DIR in $(ARM64_SUBTARGETS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ mkdir -p $$BUILD_TARGET; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+install: all
+ @for DIR in $(ARM64_SUBTARGETS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+run_tests: all
+ @for DIR in $(ARM64_SUBTARGETS); 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 $(ARM64_SUBTARGETS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+clean:
+ @for DIR in $(ARM64_SUBTARGETS); 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..a1badd882102
--- /dev/null
+++ b/tools/testing/selftests/arm64/README
@@ -0,0 +1,25 @@
+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 within the KSelfTest
+ framework using standard Linux top-level-makefile targets:
+
+ $ make TARGETS=arm64 kselftest-clean
+ $ make TARGETS=arm64 kselftest
+
+ or
+
+ $ make -C tools/testing/selftests TARGETS=arm64 \
+ INSTALL_PATH=<your-installation-path> install
+
+ or, alternatively, only specific arm64/ subtargets can be picked:
+
+ $ make -C tools/testing/selftests TARGETS=arm64 ARM64_SUBTARGETS="tags signal" \
+ INSTALL_PATH=<your-installation-path> install
+
+ Further details on building and running KFST can be found in:
+ Documentation/dev-tools/kselftest.rst
diff --git a/tools/testing/selftests/arm64/tags/Makefile b/tools/testing/selftests/arm64/tags/Makefile
new file mode 100644
index 000000000000..41cb75070511
--- /dev/null
+++ b/tools/testing/selftests/arm64/tags/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CFLAGS += -I../../../../../usr/include/
+TEST_GEN_PROGS := tags_test
+TEST_PROGS := run_tags_test.sh
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/arm64/run_tags_test.sh b/tools/testing/selftests/arm64/tags/run_tags_test.sh
similarity index 100%
rename from tools/testing/selftests/arm64/run_tags_test.sh
rename to tools/testing/selftests/arm64/tags/run_tags_test.sh
diff --git a/tools/testing/selftests/arm64/tags_test.c b/tools/testing/selftests/arm64/tags/tags_test.c
similarity index 100%
rename from tools/testing/selftests/arm64/tags_test.c
rename to tools/testing/selftests/arm64/tags/tags_test.c
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile
2019-10-09 8:26 ` [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile Cristian Marussi
@ 2019-10-09 11:15 ` Dave Martin
2019-10-09 11:52 ` Cristian Marussi
0 siblings, 1 reply; 21+ messages in thread
From: Dave Martin @ 2019-10-09 11:15 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On Wed, Oct 09, 2019 at 09:26:00AM +0100, Cristian Marussi wrote:
> Modify KSFT arm64 toplevel Makefile to maintain arm64 kselftests organized
> by subsystem, keeping them into distinct subdirectories under arm64 custom
> KSFT directory: tools/testing/selftests/arm64/
>
> Add to such toplevel Makefile a mechanism to guess the effective location
> of Kernel headers as installed by KSFT framework.
>
> Fit existing arm64 tags kselftest into this new schema moving them into
> their own subdirectory (arm64/tags).
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> Based on:
> commit 9ce1263033cd ("selftests, arm64: add a selftest for passing
> tagged pointers to kernel")
> ---
> v6 --> v7
> - renamed SUBTARGETS to ARM64_SUBTARGETS to avoid name clashes
> - rebased on v5.4-rc2 accounting for further new patches on top of commit 9ce1263033cd
> v5 --> v6
> - using realpath to avoid passing down relative paths
> - fix commit msg & Copyright
> - removed unneded Makefile export
> - added SUBTARGETS specification, to allow building specific only some
> arm64 test subsystems
> v4 --> v5
> - rebased on arm64/for-next/core
> - merged this patch with KSFT arm64 tags patch, while moving the latter
> into its own subdir
> - moved kernel header includes search mechanism from KSFT arm64
> SIGNAL Makefile
> - export proper top_srcdir ENV for lib.mk
> v3 --> v4
> - comment reword
> - simplified documentation in README
> - dropped README about standalone
> ---
> tools/testing/selftests/Makefile | 1 +
> tools/testing/selftests/arm64/Makefile | 64 +++++++++++++++++--
> tools/testing/selftests/arm64/README | 25 ++++++++
> tools/testing/selftests/arm64/tags/Makefile | 7 ++
> .../arm64/{ => tags}/run_tags_test.sh | 0
> .../selftests/arm64/{ => tags}/tags_test.c | 0
> 6 files changed, 92 insertions(+), 5 deletions(-)
> create mode 100644 tools/testing/selftests/arm64/README
> create mode 100644 tools/testing/selftests/arm64/tags/Makefile
> rename tools/testing/selftests/arm64/{ => tags}/run_tags_test.sh (100%)
> rename tools/testing/selftests/arm64/{ => tags}/tags_test.c (100%)
Do you need to move the tags_test line in arm64/.gitignore to
arm64/tags/.gitignore?
With that change, FWIW:
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
(i.e., this looks reasonable, but I'm not a kselftest expert...)
[...]
Cheers
---Dave
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile
2019-10-09 11:15 ` Dave Martin
@ 2019-10-09 11:52 ` Cristian Marussi
0 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 11:52 UTC (permalink / raw)
To: Dave Martin
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On 09/10/2019 12:15, Dave Martin wrote:
> On Wed, Oct 09, 2019 at 09:26:00AM +0100, Cristian Marussi wrote:
>> Modify KSFT arm64 toplevel Makefile to maintain arm64 kselftests organized
>> by subsystem, keeping them into distinct subdirectories under arm64 custom
>> KSFT directory: tools/testing/selftests/arm64/
>>
>> Add to such toplevel Makefile a mechanism to guess the effective location
>> of Kernel headers as installed by KSFT framework.
>>
>> Fit existing arm64 tags kselftest into this new schema moving them into
>> their own subdirectory (arm64/tags).
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> Based on:
>> commit 9ce1263033cd ("selftests, arm64: add a selftest for passing
>> tagged pointers to kernel")
>> ---
>> v6 --> v7
>> - renamed SUBTARGETS to ARM64_SUBTARGETS to avoid name clashes
>> - rebased on v5.4-rc2 accounting for further new patches on top of commit 9ce1263033cd
>> v5 --> v6
>> - using realpath to avoid passing down relative paths
>> - fix commit msg & Copyright
>> - removed unneded Makefile export
>> - added SUBTARGETS specification, to allow building specific only some
>> arm64 test subsystems
>> v4 --> v5
>> - rebased on arm64/for-next/core
>> - merged this patch with KSFT arm64 tags patch, while moving the latter
>> into its own subdir
>> - moved kernel header includes search mechanism from KSFT arm64
>> SIGNAL Makefile
>> - export proper top_srcdir ENV for lib.mk
>> v3 --> v4
>> - comment reword
>> - simplified documentation in README
>> - dropped README about standalone
>> ---
>> tools/testing/selftests/Makefile | 1 +
>> tools/testing/selftests/arm64/Makefile | 64 +++++++++++++++++--
>> tools/testing/selftests/arm64/README | 25 ++++++++
>> tools/testing/selftests/arm64/tags/Makefile | 7 ++
>> .../arm64/{ => tags}/run_tags_test.sh | 0
>> .../selftests/arm64/{ => tags}/tags_test.c | 0
>> 6 files changed, 92 insertions(+), 5 deletions(-)
>> create mode 100644 tools/testing/selftests/arm64/README
>> create mode 100644 tools/testing/selftests/arm64/tags/Makefile
>> rename tools/testing/selftests/arm64/{ => tags}/run_tags_test.sh (100%)
>> rename tools/testing/selftests/arm64/{ => tags}/tags_test.c (100%)
>
> Do you need to move the tags_test line in arm64/.gitignore to
> arm64/tags/.gitignore?
>
Damn...I've not spotted that since it works anyway. I'll fix in v9.
Cristian
> With that change, FWIW:
>
> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>
> (i.e., this looks reasonable, but I'm not a kselftest expert...)
>
> [...]
>
> Cheers
> ---Dave
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 11:18 ` Dave Martin
2019-10-09 8:26 ` [PATCH v8 03/12] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
` (9 subsequent siblings)
11 siblings, 1 reply; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add some arm64/signal specific boilerplate and utility code to help
further testcases' development.
Introduce also one simple testcase mangle_pstate_invalid_compat_toggle
and some related helpers: it is a simple mangle testcase which messes
with the ucontext_t from within the signal handler, trying to toggle
PSTATE state bits to switch the system between 32bit/64bit execution
state. Expects SIGSEGV on test PASS.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v7 --> v8
- removed unused SSBS_SYSREG
v6 --> v7
- removed ambiguos fprintf in test_init
- fixed spacing
v5 --> v6
- fix commit msg
- feat_names is char const *const
- better supported options check and reporting
- removed critical asserts to avoid issues with NDEBUG
- more robust get_header
- fix validation for ESR_CONTEXT size
- add more explicit comment in GET_RESV_NEXT_HEAD() macro
- refactored default_handler()
- feats_ok() now public
- call always test_results() no matter the outcome of test_run()
v4 --> v5
- moved kernel headers include search to top level KSFT arm64 Makefile
- removed warning about kernel headers not found
- moved testcases/.gitignore up one level
v3 --> v4
- removed standalone mode
- fixed arm64/signal/README
- add file level comments: test layout / test description
- reduced verbosity
- removed spurious headers includes
- reviewed ID_AA64MMFR[1,2]_EL1 macros
- removed unused feats_ok
- simplified CPU features gathering
- reviewed included headers
- fixed/refactored get_header() and validation routines
- added test description
---
tools/testing/selftests/arm64/Makefile | 2 +-
.../testing/selftests/arm64/signal/.gitignore | 3 +
tools/testing/selftests/arm64/signal/Makefile | 32 ++
tools/testing/selftests/arm64/signal/README | 59 ++++
.../selftests/arm64/signal/test_signals.c | 29 ++
.../selftests/arm64/signal/test_signals.h | 109 +++++++
.../arm64/signal/test_signals_utils.c | 297 ++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 19 ++
.../mangle_pstate_invalid_compat_toggle.c | 31 ++
.../arm64/signal/testcases/testcases.c | 150 +++++++++
.../arm64/signal/testcases/testcases.h | 100 ++++++
11 files changed, 830 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 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/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 cd27ca689224..93b567d23c8b 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -4,7 +4,7 @@
ARCH ?= $(shell uname -m 2>/dev/null || echo not)
ifneq (,$(filter $(ARCH),aarch64 arm64))
-ARM64_SUBTARGETS ?= tags
+ARM64_SUBTARGETS ?= tags signal
else
ARM64_SUBTARGETS :=
endif
diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
new file mode 100644
index 000000000000..e5aeae45febb
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/.gitignore
@@ -0,0 +1,3 @@
+!*.[ch]
+mangle_*
+fake_sigreturn_*
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
new file mode 100644
index 000000000000..f78f5190e3d4
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# Additional include paths needed by kselftest.h and local headers
+CFLAGS += -D_GNU_SOURCE -std=gnu99 -I.
+
+SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
+PROGS := $(patsubst %.c,%,$(SRCS))
+
+# 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
+
+# Including KSFT lib.mk here 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)
+
+# 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
+ $(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..967a531b245c
--- /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 modifies the signal frame from inside the
+ signal handler 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_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
new file mode 100644
index 000000000000..cb970346b280
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Generic test wrapper for arm64 signal tests.
+ *
+ * Each test provides its own tde struct tdescr descriptor to link with
+ * this wrapper. Framework provides common helpers.
+ */
+#include <kselftest.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+
+struct tdescr *current;
+
+int main(int argc, char *argv[])
+{
+ current = &tde;
+
+ ksft_print_msg("%s :: %s\n", current->name, current->descr);
+ if (test_setup(current)) {
+ test_run(current);
+ test_result(current);
+ test_cleanup(current);
+ }
+
+ return current->pass ? KSFT_PASS : KSFT_FAIL;
+}
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..3fd4499f00bf
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_H__
+#define __TEST_SIGNALS_H__
+
+#include <signal.h>
+#include <stdbool.h>
+#include <ucontext.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>
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+#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 ID_AA64MMFR1_EL1_PAN_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
+#define ID_AA64MMFR2_EL1_UAO_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
+
+/*
+ * 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 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;
+ /* optional test private data */
+ void *priv;
+
+ /* a custom setup function to be called before test starts */
+ int (*setup)(struct tdescr *td);
+ /* a custom cleanup function called before test exits */
+ 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);
+};
+
+extern struct tdescr tde;
+#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..ff24db6f9d06
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -0,0 +1,297 @@
+// 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 const *const feats_names[FMAX_END] = {
+ " SSBS ",
+ " PAN ",
+ " UAO ",
+};
+
+#define MAX_FEATS_SZ 128
+static char feats_string[MAX_FEATS_SZ];
+
+static inline char *feats_to_string(unsigned long feats)
+{
+ size_t flen = MAX_FEATS_SZ - 1;
+
+ for (int i = 0; i < FMAX_END; i++) {
+ if (feats & (1UL << i)) {
+ size_t tlen = strlen(feats_names[i]);
+
+ assert(flen > tlen);
+ flen -= tlen;
+ strncat(feats_string, feats_names[i], flen);
+ }
+ }
+
+ 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)
+ fprintf(stderr, "==>> completed. PASS(1)\n");
+ else
+ fprintf(stdout, "==>> completed. FAIL(0)\n");
+ if (force_exit)
+ exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/*
+ * The following handle_signal_* helpers are used by main default_handler
+ * and are meant to return true when signal is handled successfully:
+ * when false is returned instead, it means that the signal was somehow
+ * unexpected in that context and it was NOT handled; default_handler will
+ * take care of such unexpected situations.
+ */
+
+static bool handle_signal_unsupported(struct tdescr *td,
+ siginfo_t *si, void *uc)
+{
+ if (feats_ok(td))
+ return false;
+
+ /* Mangling PC to avoid loops on original SIGILL */
+ ((ucontext_t *)uc)->uc_mcontext.pc += 4;
+
+ if (!td->initialized) {
+ fprintf(stderr,
+ "Got SIG_UNSUPP @test_init. Ignore.\n");
+ } else {
+ fprintf(stderr,
+ "-- RX SIG_UNSUPP on unsupported feat...OK\n");
+ td->pass = 1;
+ default_result(current, 1);
+ }
+
+ return true;
+}
+
+static bool handle_signal_trigger(struct tdescr *td,
+ siginfo_t *si, void *uc)
+{
+ td->triggered = 1;
+ /* ->run was asserted NON-NULL in test_setup() already */
+ td->run(td, si, uc);
+
+ return true;
+}
+
+static bool handle_signal_ok(struct tdescr *td,
+ siginfo_t *si, void *uc)
+{
+ /*
+ * it's a bug in the test code when this assert fail:
+ * if sig_trig was defined, it must have been used before getting here.
+ */
+ assert(!td->sig_trig || td->triggered);
+ fprintf(stderr,
+ "SIG_OK -- SP:0x%llX si_addr@:%p si_code:%d token@:%p offset:%ld\n",
+ ((ucontext_t *)uc)->uc_mcontext.sp,
+ si->si_addr, si->si_code, td->token, td->token - si->si_addr);
+ /*
+ * fake_sigreturn tests, which have sanity_enabled=1, set, at the very
+ * last time, the token field to the SP address used to place the fake
+ * sigframe: so token==0 means we never made it to the end,
+ * segfaulting well-before, and the test is possibly broken.
+ */
+ if (!td->sanity_disabled && !td->token) {
+ fprintf(stdout,
+ "current->token ZEROED...test is probably broken!\n");
+ abort();
+ }
+ /*
+ * Trying to narrow down the SEGV to the ones generated by Kernel itself
+ * via arm64_notify_segfault(). This is a best-effort check anyway, and
+ * the si_code check may need to change if this aspect of the kernel
+ * ABI changes.
+ */
+ if (td->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
+ fprintf(stdout,
+ "si_code != SEGV_ACCERR...test is probably broken!\n");
+ abort();
+ }
+ td->pass = 1;
+ /*
+ * Some tests can lead to SEGV loops: in such a case we want to
+ * terminate immediately exiting straight away; some others are not
+ * supposed to outlive the signal handler code, due to the content of
+ * the fake sigframe which caused the signal itself.
+ */
+ default_result(current, 1);
+
+ return true;
+}
+
+static void default_handler(int signum, siginfo_t *si, void *uc)
+{
+ if (current->sig_unsupp && signum == current->sig_unsupp &&
+ handle_signal_unsupported(current, si, uc)) {
+ fprintf(stderr, "Handled SIG_UNSUPP\n");
+ } else if (current->sig_trig && signum == current->sig_trig &&
+ handle_signal_trigger(current, si, uc)) {
+ fprintf(stderr, "Handled SIG_TRIG\n");
+ } else if (current->sig_ok && signum == current->sig_ok &&
+ handle_signal_ok(current, si, uc)) {
+ fprintf(stderr, "Handled SIG_OK\n");
+ } else {
+ if (signum == SIGALRM && current->timeout) {
+ fprintf(stderr, "-- 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 | SA_RESTART;
+ 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) {
+ 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_SSBS)
+ td->feats_supported |= FEAT_SSBS;
+ if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
+ uint64_t val = 0;
+
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR1_EL1, val);
+ if (ID_AA64MMFR1_EL1_PAN_SUPPORTED(val))
+ td->feats_supported |= FEAT_PAN;
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR2_EL1, val);
+ if (ID_AA64MMFR2_EL1_UAO_SUPPORTED(val))
+ td->feats_supported |= FEAT_UAO;
+ }
+ if (feats_ok(td))
+ fprintf(stderr,
+ "Required Features: [%s] supported\n",
+ feats_to_string(td->feats_required &
+ td->feats_supported));
+ else
+ fprintf(stderr,
+ "Required Features: [%s] NOT supported\n",
+ feats_to_string(td->feats_required &
+ ~td->feats_supported));
+ }
+
+ 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..47a7592b7c53
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_UTILS_H__
+#define __TEST_SIGNALS_UTILS_H__
+
+#include "test_signals.h"
+
+int test_setup(struct tdescr *td);
+void test_cleanup(struct tdescr *td);
+int test_run(struct tdescr *td);
+void test_result(struct tdescr *td);
+
+static inline bool feats_ok(struct tdescr *td)
+{
+ return (td->feats_required & td->feats_supported) == td->feats_required;
+}
+
+#endif
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..2cb118b0ba05
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the execution state bit: this attempt must be spotted by Kernel and
+ * the test case is expected to be terminated via SEGV.
+ */
+
+#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..1914a01222a1
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2019 ARM Limited */
+#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;
+
+ while (offs <= resv_sz - HDR_SZ &&
+ head->magic != magic && head->magic) {
+ offs += head->size;
+ head = GET_RESV_NEXT_HEAD(head);
+ }
+ if (head->magic == magic) {
+ found = head;
+ 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 = "Missing terminator after 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 terminator";
+ 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))
+ *err = "Bad size for esr_context";
+ 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..04987f7870bc
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+#ifndef __TESTCASES_H__
+#define __TESTCASES_H__
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <signal.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; \
+ if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) { \
+ if (err) \
+ fprintf(stderr, \
+ "Using badly built context - ERR: %s\n",\
+ err); \
+ } else { \
+ abort(); \
+ } \
+} 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);\
+ abort(); \
+ } else { \
+ fprintf(stderr, "uc context validated.\n"); \
+ } \
+} while (0)
+
+/*
+ * A simple record-walker for __reserved area: it walks through assuming
+ * only to find a proper struct __aarch64_ctx header descriptor.
+ *
+ * Instead it makes no assumptions on the content and ordering of the
+ * records, any needed bounds checking must be enforced by the caller
+ * if wanted: this way can be used by caller on any maliciously built bad
+ * contexts.
+ *
+ * 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] 21+ messages in thread
* Re: [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils
2019-10-09 8:26 ` [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils Cristian Marussi
@ 2019-10-09 11:18 ` Dave Martin
2019-10-09 11:55 ` Cristian Marussi
0 siblings, 1 reply; 21+ messages in thread
From: Dave Martin @ 2019-10-09 11:18 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On Wed, Oct 09, 2019 at 09:26:01AM +0100, Cristian Marussi wrote:
> Add some arm64/signal specific boilerplate and utility code to help
> further testcases' development.
>
> Introduce also one simple testcase mangle_pstate_invalid_compat_toggle
> and some related helpers: it is a simple mangle testcase which messes
> with the ucontext_t from within the signal handler, trying to toggle
> PSTATE state bits to switch the system between 32bit/64bit execution
> state. Expects SIGSEGV on test PASS.
>
> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> v7 --> v8
> - removed unused SSBS_SYSREG
[...]
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..e5aeae45febb
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,3 @@
> +!*.[ch]
> +mangle_*
> +fake_sigreturn_*
I think the !*.[ch] line needs to come last.
Re-including *.[ch] on the first line has no effect because no files
have been excluded yet.
(This looks like it was my mistake when I originally suggested using
wildcards here -- apologies for that!)
I'm happy for you to keey my Reviewed-by on that change.
[...]
Cheers
---Dave
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils
2019-10-09 11:18 ` Dave Martin
@ 2019-10-09 11:55 ` Cristian Marussi
0 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 11:55 UTC (permalink / raw)
To: Dave Martin
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On 09/10/2019 12:18, Dave Martin wrote:
> On Wed, Oct 09, 2019 at 09:26:01AM +0100, Cristian Marussi wrote:
>> Add some arm64/signal specific boilerplate and utility code to help
>> further testcases' development.
>>
>> Introduce also one simple testcase mangle_pstate_invalid_compat_toggle
>> and some related helpers: it is a simple mangle testcase which messes
>> with the ucontext_t from within the signal handler, trying to toggle
>> PSTATE state bits to switch the system between 32bit/64bit execution
>> state. Expects SIGSEGV on test PASS.
>>
>> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> v7 --> v8
>> - removed unused SSBS_SYSREG
>
> [...]
>
>> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
>> new file mode 100644
>> index 000000000000..e5aeae45febb
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/.gitignore
>> @@ -0,0 +1,3 @@
>> +!*.[ch]
>> +mangle_*
>> +fake_sigreturn_*
>
> I think the !*.[ch] line needs to come last.
>
> Re-including *.[ch] on the first line has no effect because no files
> have been excluded yet.
>
> (This looks like it was my mistake when I originally suggested using
> wildcards here -- apologies for that!)
>
> I'm happy for you to keey my Reviewed-by on that change.
>
Moved to last in v9
Cristian
> [...]
>
> Cheers
> ---Dave
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v8 03/12] kselftest: arm64: mangle_pstate_invalid_daif_bits
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 01/12] kselftest: arm64: extend toplevel skeleton Makefile Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 02/12] kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 04/12] kselftest: arm64: mangle_pstate_invalid_mode_el[123][ht] Cristian Marussi
` (8 subsequent siblings)
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add a simple mangle testcase which messes with the ucontext_t from within
the signal handler, trying to set PSTATE DAIF bits to an invalid value
(masking everything). Expects SIGSEGV on test PASS.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v3 --> v4
- fixed commit message
- added testcase comment description
---
.../mangle_pstate_invalid_daif_bits.c | 35 +++++++++++++++++++
1 file changed, 35 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/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..434b82597007
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, mangling the
+ * DAIF bits in an illegal manner: this attempt must be spotted by Kernel
+ * and the test case is expected to be terminated via SEGV.
+ *
+ */
+
+#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] 21+ messages in thread
* [PATCH v8 04/12] kselftest: arm64: mangle_pstate_invalid_mode_el[123][ht]
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (2 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 03/12] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities Cristian Marussi
` (7 subsequent siblings)
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add 6 simple mangle testcases that mess with the ucontext_t from within
the signal handler, trying to toggle PSTATE mode bits to trick the system
into switching to EL1/EL2/EL3 using both SP_EL0(t) and SP_ELx(h).
Expects SIGSEGV on test PASS.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v3 --> v4
- fixed commit message
- macroization
- splitted into 6 macro-ised testcases to address t/h SP selection modes
- added test description
---
.../mangle_pstate_invalid_mode_el1h.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_el1t.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_el2h.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_el2t.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_el3h.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_el3t.c | 15 ++++++++++
.../mangle_pstate_invalid_mode_template.h | 28 +++++++++++++++++++
7 files changed, 118 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1h.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1t.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2h.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2t.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3h.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3t.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_template.h
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1h.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1h.c
new file mode 100644
index 000000000000..95f821abdf46
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1h.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(1h);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1t.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1t.c
new file mode 100644
index 000000000000..cc222d8a618a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1t.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(1t);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2h.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2h.c
new file mode 100644
index 000000000000..2188add7d28c
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2h.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(2h);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2t.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2t.c
new file mode 100644
index 000000000000..df32dd5a479c
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2t.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(2t);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3h.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3h.c
new file mode 100644
index 000000000000..9e6829b7e5db
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3h.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(3h);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3t.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3t.c
new file mode 100644
index 000000000000..5685a4f10d06
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3t.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Try to mangle the ucontext from inside a signal handler, toggling
+ * the mode bit to escalate exception level: this attempt must be spotted
+ * by Kernel and the test case is expected to be termninated via SEGV.
+ */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+#include "mangle_pstate_invalid_mode_template.h"
+
+DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(3t);
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_template.h b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_template.h
new file mode 100644
index 000000000000..f5bf1804d858
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_template.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Utility macro to ease definition of testcases toggling mode EL
+ */
+
+#define DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(_mode) \
+ \
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si, \
+ ucontext_t *uc) \
+{ \
+ ASSERT_GOOD_CONTEXT(uc); \
+ \
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK; \
+ uc->uc_mcontext.pstate |= PSR_MODE_EL ## _mode; \
+ \
+ return 1; \
+} \
+ \
+struct tdescr tde = { \
+ .sanity_disabled = true, \
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL"#_mode, \
+ .descr = "Mangling uc_mcontext INVALID MODE EL"#_mode, \
+ .sig_trig = SIGUSR1, \
+ .sig_ok = SIGSEGV, \
+ .run = mangle_invalid_pstate_run, \
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (3 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 04/12] kselftest: arm64: mangle_pstate_invalid_mode_el[123][ht] Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 11:32 ` Dave Martin
2019-10-09 8:26 ` [PATCH v8 06/12] kselftest: arm64: add helper get_current_context Cristian Marussi
` (6 subsequent siblings)
11 siblings, 1 reply; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Extend signal testing framework to allow the definition of a custom per
test initialization function to be run at the end of the common test_init
after test setup phase has completed and before test-run routine.
This custom per-test initialization function also enables the test writer
to decide on its own when forcibly skip the test itself using standard KSFT
mechanism.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v7 --> v8
- per test .init() helper added new in v8 (splitted out of v7 05/11)
---
.../selftests/arm64/signal/test_signals.c | 6 ++--
.../selftests/arm64/signal/test_signals.h | 7 ++--
.../arm64/signal/test_signals_utils.c | 32 +++++++++++++------
.../arm64/signal/test_signals_utils.h | 1 +
4 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
index cb970346b280..416b1ff43199 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.c
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -19,11 +19,11 @@ int main(int argc, char *argv[])
current = &tde;
ksft_print_msg("%s :: %s\n", current->name, current->descr);
- if (test_setup(current)) {
+ if (test_setup(current) && test_init(current)) {
test_run(current);
- test_result(current);
test_cleanup(current);
}
+ test_result(current);
- return current->pass ? KSFT_PASS : KSFT_FAIL;
+ return current->result;
}
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 3fd4499f00bf..901521188202 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -84,17 +84,20 @@ struct tdescr {
unsigned int timeout;
bool triggered;
bool pass;
+ unsigned int result;
/* optional sa_flags for the installed handler */
int sa_flags;
ucontext_t saved_uc;
/* optional test private data */
void *priv;
- /* a custom setup function to be called before test starts */
+ /* a custom setup: called alternatively to default_setup */
int (*setup)(struct tdescr *td);
+ /* a custom init: called by default test init after test_setup */
+ bool (*init)(struct tdescr *td);
/* a custom cleanup function called before test exits */
void (*cleanup)(struct tdescr *td);
- /* an optional function to be used as a trigger for test starting */
+ /* an optional function to be used as a trigger for starting test */
int (*trigger)(struct tdescr *td);
/*
* the actual test-core: invoked differently depending on the
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index ff24db6f9d06..e8bbe36c2660 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -11,6 +11,8 @@
#include <linux/auxvec.h>
#include <ucontext.h>
+#include <kselftest.h>
+
#include "test_signals.h"
#include "test_signals_utils.h"
#include "testcases/testcases.h"
@@ -54,12 +56,18 @@ static void unblock_signal(int signum)
static void default_result(struct tdescr *td, bool force_exit)
{
- if (td->pass)
+ if (td->result == KSFT_SKIP) {
+ fprintf(stderr, "==>> completed. SKIP.\n");
+ } else if (td->pass) {
fprintf(stderr, "==>> completed. PASS(1)\n");
- else
+ td->result = KSFT_PASS;
+ } else {
fprintf(stdout, "==>> completed. FAIL(0)\n");
+ td->result = KSFT_FAIL;
+ }
+
if (force_exit)
- exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
+ exit(td->result);
}
/*
@@ -211,7 +219,7 @@ static inline int default_trigger(struct tdescr *td)
return !raise(td->sig_trig);
}
-static int test_init(struct tdescr *td)
+int test_init(struct tdescr *td)
{
td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
if (!td->minsigstksz)
@@ -224,8 +232,6 @@ static int test_init(struct tdescr *td)
* Checking for CPU required features using both the
* auxval and the arm64 MRS Emulation to read sysregs.
*/
- if (getauxval(AT_HWCAP) & HWCAP_SSBS)
- td->feats_supported |= FEAT_SSBS;
if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
uint64_t val = 0;
@@ -250,7 +256,14 @@ static int test_init(struct tdescr *td)
~td->feats_supported));
}
+ /* Perform test specific additional initialization */
+ if (td->init && !td->init(td)) {
+ fprintf(stderr, "FAILED Testcase initialization.\n");
+ return 0;
+ }
td->initialized = 1;
+ fprintf(stderr, "Testcase initialized.\n");
+
return 1;
}
@@ -262,9 +275,8 @@ int test_setup(struct tdescr *td)
assert(td->name);
assert(td->run);
- if (!test_init(td))
- return 0;
-
+ /* Default result is FAIL if test setup fails */
+ td->result = KSFT_FAIL;
if (td->setup)
return td->setup(td);
else
@@ -285,7 +297,7 @@ int test_run(struct tdescr *td)
void test_result(struct tdescr *td)
{
- if (td->check_result)
+ if (td->initialized && td->result != KSFT_SKIP && td->check_result)
td->check_result(td);
default_result(td, 0);
}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 47a7592b7c53..5e3a2b7aaa8b 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -6,6 +6,7 @@
#include "test_signals.h"
+int test_init(struct tdescr *td);
int test_setup(struct tdescr *td);
void test_cleanup(struct tdescr *td);
int test_run(struct tdescr *td);
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities
2019-10-09 8:26 ` [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities Cristian Marussi
@ 2019-10-09 11:32 ` Dave Martin
2019-10-09 11:57 ` Cristian Marussi
0 siblings, 1 reply; 21+ messages in thread
From: Dave Martin @ 2019-10-09 11:32 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On Wed, Oct 09, 2019 at 09:26:04AM +0100, Cristian Marussi wrote:
> Extend signal testing framework to allow the definition of a custom per
> test initialization function to be run at the end of the common test_init
> after test setup phase has completed and before test-run routine.
>
> This custom per-test initialization function also enables the test writer
> to decide on its own when forcibly skip the test itself using standard KSFT
> mechanism.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
> ---
> v7 --> v8
> - per test .init() helper added new in v8 (splitted out of v7 05/11)
> ---
> .../selftests/arm64/signal/test_signals.c | 6 ++--
> .../selftests/arm64/signal/test_signals.h | 7 ++--
> .../arm64/signal/test_signals_utils.c | 32 +++++++++++++------
> .../arm64/signal/test_signals_utils.h | 1 +
> 4 files changed, 31 insertions(+), 15 deletions(-)
>
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> index cb970346b280..416b1ff43199 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals.c
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -19,11 +19,11 @@ int main(int argc, char *argv[])
> current = &tde;
>
> ksft_print_msg("%s :: %s\n", current->name, current->descr);
> - if (test_setup(current)) {
> + if (test_setup(current) && test_init(current)) {
> test_run(current);
> - test_result(current);
> test_cleanup(current);
> }
> + test_result(current);
>
> - return current->pass ? KSFT_PASS : KSFT_FAIL;
> + return current->result;
> }
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> index 3fd4499f00bf..901521188202 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -84,17 +84,20 @@ struct tdescr {
> unsigned int timeout;
> bool triggered;
> bool pass;
> + unsigned int result;
> /* optional sa_flags for the installed handler */
> int sa_flags;
> ucontext_t saved_uc;
> /* optional test private data */
> void *priv;
>
> - /* a custom setup function to be called before test starts */
> + /* a custom setup: called alternatively to default_setup */
> int (*setup)(struct tdescr *td);
> + /* a custom init: called by default test init after test_setup */
> + bool (*init)(struct tdescr *td);
> /* a custom cleanup function called before test exits */
> void (*cleanup)(struct tdescr *td);
> - /* an optional function to be used as a trigger for test starting */
> + /* an optional function to be used as a trigger for starting test */
> int (*trigger)(struct tdescr *td);
> /*
> * the actual test-core: invoked differently depending on the
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> index ff24db6f9d06..e8bbe36c2660 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -11,6 +11,8 @@
> #include <linux/auxvec.h>
> #include <ucontext.h>
>
> +#include <kselftest.h>
> +
> #include "test_signals.h"
> #include "test_signals_utils.h"
> #include "testcases/testcases.h"
> @@ -54,12 +56,18 @@ static void unblock_signal(int signum)
>
> static void default_result(struct tdescr *td, bool force_exit)
> {
> - if (td->pass)
> + if (td->result == KSFT_SKIP) {
> + fprintf(stderr, "==>> completed. SKIP.\n");
> + } else if (td->pass) {
> fprintf(stderr, "==>> completed. PASS(1)\n");
> - else
> + td->result = KSFT_PASS;
> + } else {
> fprintf(stdout, "==>> completed. FAIL(0)\n");
> + td->result = KSFT_FAIL;
> + }
> +
> if (force_exit)
> - exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> + exit(td->result);
> }
>
> /*
> @@ -211,7 +219,7 @@ static inline int default_trigger(struct tdescr *td)
> return !raise(td->sig_trig);
> }
>
> -static int test_init(struct tdescr *td)
> +int test_init(struct tdescr *td)
> {
> td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> if (!td->minsigstksz)
> @@ -224,8 +232,6 @@ static int test_init(struct tdescr *td)
> * Checking for CPU required features using both the
> * auxval and the arm64 MRS Emulation to read sysregs.
> */
> - if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> - td->feats_supported |= FEAT_SSBS;
> if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> uint64_t val = 0;
>
> @@ -250,7 +256,14 @@ static int test_init(struct tdescr *td)
> ~td->feats_supported));
> }
>
> + /* Perform test specific additional initialization */
> + if (td->init && !td->init(td)) {
> + fprintf(stderr, "FAILED Testcase initialization.\n");
> + return 0;
> + }
> td->initialized = 1;
> + fprintf(stderr, "Testcase initialized.\n");
> +
> return 1;
> }
>
> @@ -262,9 +275,8 @@ int test_setup(struct tdescr *td)
> assert(td->name);
> assert(td->run);
>
> - if (!test_init(td))
> - return 0;
> -
> + /* Default result is FAIL if test setup fails */
> + td->result = KSFT_FAIL;
> if (td->setup)
> return td->setup(td);
> else
> @@ -285,7 +297,7 @@ int test_run(struct tdescr *td)
>
> void test_result(struct tdescr *td)
> {
> - if (td->check_result)
> + if (td->initialized && td->result != KSFT_SKIP && td->check_result)
> td->check_result(td);
> default_result(td, 0);
> }
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> index 47a7592b7c53..5e3a2b7aaa8b 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -6,6 +6,7 @@
>
> #include "test_signals.h"
>
> +int test_init(struct tdescr *td);
> int test_setup(struct tdescr *td);
> void test_cleanup(struct tdescr *td);
> int test_run(struct tdescr *td);
> --
> 2.17.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities
2019-10-09 11:32 ` Dave Martin
@ 2019-10-09 11:57 ` Cristian Marussi
0 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 11:57 UTC (permalink / raw)
To: Dave Martin
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On 09/10/2019 12:32, Dave Martin wrote:
> On Wed, Oct 09, 2019 at 09:26:04AM +0100, Cristian Marussi wrote:
>> Extend signal testing framework to allow the definition of a custom per
>> test initialization function to be run at the end of the common test_init
>> after test setup phase has completed and before test-run routine.
>>
>> This custom per-test initialization function also enables the test writer
>> to decide on its own when forcibly skip the test itself using standard KSFT
>> mechanism.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>
> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>
Thanks
Cristian
>> ---
>> v7 --> v8
>> - per test .init() helper added new in v8 (splitted out of v7 05/11)
>> ---
>> .../selftests/arm64/signal/test_signals.c | 6 ++--
>> .../selftests/arm64/signal/test_signals.h | 7 ++--
>> .../arm64/signal/test_signals_utils.c | 32 +++++++++++++------
>> .../arm64/signal/test_signals_utils.h | 1 +
>> 4 files changed, 31 insertions(+), 15 deletions(-)
>>
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
>> index cb970346b280..416b1ff43199 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals.c
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
>> @@ -19,11 +19,11 @@ int main(int argc, char *argv[])
>> current = &tde;
>>
>> ksft_print_msg("%s :: %s\n", current->name, current->descr);
>> - if (test_setup(current)) {
>> + if (test_setup(current) && test_init(current)) {
>> test_run(current);
>> - test_result(current);
>> test_cleanup(current);
>> }
>> + test_result(current);
>>
>> - return current->pass ? KSFT_PASS : KSFT_FAIL;
>> + return current->result;
>> }
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>> index 3fd4499f00bf..901521188202 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>> @@ -84,17 +84,20 @@ struct tdescr {
>> unsigned int timeout;
>> bool triggered;
>> bool pass;
>> + unsigned int result;
>> /* optional sa_flags for the installed handler */
>> int sa_flags;
>> ucontext_t saved_uc;
>> /* optional test private data */
>> void *priv;
>>
>> - /* a custom setup function to be called before test starts */
>> + /* a custom setup: called alternatively to default_setup */
>> int (*setup)(struct tdescr *td);
>> + /* a custom init: called by default test init after test_setup */
>> + bool (*init)(struct tdescr *td);
>> /* a custom cleanup function called before test exits */
>> void (*cleanup)(struct tdescr *td);
>> - /* an optional function to be used as a trigger for test starting */
>> + /* an optional function to be used as a trigger for starting test */
>> int (*trigger)(struct tdescr *td);
>> /*
>> * the actual test-core: invoked differently depending on the
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> index ff24db6f9d06..e8bbe36c2660 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -11,6 +11,8 @@
>> #include <linux/auxvec.h>
>> #include <ucontext.h>
>>
>> +#include <kselftest.h>
>> +
>> #include "test_signals.h"
>> #include "test_signals_utils.h"
>> #include "testcases/testcases.h"
>> @@ -54,12 +56,18 @@ static void unblock_signal(int signum)
>>
>> static void default_result(struct tdescr *td, bool force_exit)
>> {
>> - if (td->pass)
>> + if (td->result == KSFT_SKIP) {
>> + fprintf(stderr, "==>> completed. SKIP.\n");
>> + } else if (td->pass) {
>> fprintf(stderr, "==>> completed. PASS(1)\n");
>> - else
>> + td->result = KSFT_PASS;
>> + } else {
>> fprintf(stdout, "==>> completed. FAIL(0)\n");
>> + td->result = KSFT_FAIL;
>> + }
>> +
>> if (force_exit)
>> - exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
>> + exit(td->result);
>> }
>>
>> /*
>> @@ -211,7 +219,7 @@ static inline int default_trigger(struct tdescr *td)
>> return !raise(td->sig_trig);
>> }
>>
>> -static int test_init(struct tdescr *td)
>> +int test_init(struct tdescr *td)
>> {
>> td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>> if (!td->minsigstksz)
>> @@ -224,8 +232,6 @@ static int test_init(struct tdescr *td)
>> * Checking for CPU required features using both the
>> * auxval and the arm64 MRS Emulation to read sysregs.
>> */
>> - if (getauxval(AT_HWCAP) & HWCAP_SSBS)
>> - td->feats_supported |= FEAT_SSBS;
>> if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
>> uint64_t val = 0;
>>
>> @@ -250,7 +256,14 @@ static int test_init(struct tdescr *td)
>> ~td->feats_supported));
>> }
>>
>> + /* Perform test specific additional initialization */
>> + if (td->init && !td->init(td)) {
>> + fprintf(stderr, "FAILED Testcase initialization.\n");
>> + return 0;
>> + }
>> td->initialized = 1;
>> + fprintf(stderr, "Testcase initialized.\n");
>> +
>> return 1;
>> }
>>
>> @@ -262,9 +275,8 @@ int test_setup(struct tdescr *td)
>> assert(td->name);
>> assert(td->run);
>>
>> - if (!test_init(td))
>> - return 0;
>> -
>> + /* Default result is FAIL if test setup fails */
>> + td->result = KSFT_FAIL;
>> if (td->setup)
>> return td->setup(td);
>> else
>> @@ -285,7 +297,7 @@ int test_run(struct tdescr *td)
>>
>> void test_result(struct tdescr *td)
>> {
>> - if (td->check_result)
>> + if (td->initialized && td->result != KSFT_SKIP && td->check_result)
>> td->check_result(td);
>> default_result(td, 0);
>> }
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> index 47a7592b7c53..5e3a2b7aaa8b 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -6,6 +6,7 @@
>>
>> #include "test_signals.h"
>>
>> +int test_init(struct tdescr *td);
>> int test_setup(struct tdescr *td);
>> void test_cleanup(struct tdescr *td);
>> int test_run(struct tdescr *td);
>> --
>> 2.17.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v8 06/12] kselftest: arm64: add helper get_current_context
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (4 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 05/12] kselftest: arm64: extend test_init functionalities Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 11:32 ` Dave Martin
2019-10-09 8:26 ` [PATCH v8 07/12] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
` (5 subsequent siblings)
11 siblings, 1 reply; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Introduce a new common utility function get_current_context() which can be
used to grab a ucontext without the help of libc, and also to detect if
such ucontext has been successfully used by placing it on the stack as a
fake sigframe.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v7 --> v8
- added new in v8 (splitted out from v7 05/11)
---
.../selftests/arm64/signal/test_signals.h | 6 +-
.../arm64/signal/test_signals_utils.c | 31 ++++++
.../arm64/signal/test_signals_utils.h | 98 +++++++++++++++++++
3 files changed, 134 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 901521188202..4fd3ba01e3b1 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -88,8 +88,12 @@ 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 sig_atomic_t live_uc_valid;
/* optional test private data */
- void *priv;
+ void *priv;
/* a custom setup: called alternatively to default_setup */
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 e8bbe36c2660..222148568adf 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -11,14 +11,19 @@
#include <linux/auxvec.h>
#include <ucontext.h>
+#include <asm/unistd.h>
+
#include <kselftest.h>
#include "test_signals.h"
#include "test_signals_utils.h"
#include "testcases/testcases.h"
+
extern struct tdescr *current;
+static int sig_copyctx = SIGTRAP;
+
static char const *const feats_names[FMAX_END] = {
" SSBS ",
" PAN ",
@@ -156,6 +161,20 @@ static bool handle_signal_ok(struct tdescr *td,
return true;
}
+static bool handle_signal_copyctx(struct tdescr *td,
+ siginfo_t *si, void *uc)
+{
+ /* Mangling PC to avoid loops on original BRK instr */
+ ((ucontext_t *)uc)->uc_mcontext.pc += 4;
+ memcpy(td->live_uc, uc, td->live_sz);
+ ASSERT_GOOD_CONTEXT(td->live_uc);
+ td->live_uc_valid = 1;
+ fprintf(stderr,
+ "GOOD CONTEXT grabbed from sig_copyctx handler\n");
+
+ return true;
+}
+
static void default_handler(int signum, siginfo_t *si, void *uc)
{
if (current->sig_unsupp && signum == current->sig_unsupp &&
@@ -167,6 +186,9 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
} else if (current->sig_ok && signum == current->sig_ok &&
handle_signal_ok(current, si, uc)) {
fprintf(stderr, "Handled SIG_OK\n");
+ } else if (signum == sig_copyctx && current->live_uc &&
+ handle_signal_copyctx(current, si, uc)) {
+ fprintf(stderr, "Handled SIG_COPYCTX\n");
} else {
if (signum == SIGALRM && current->timeout) {
fprintf(stderr, "-- Timeout !\n");
@@ -221,6 +243,15 @@ static inline int default_trigger(struct tdescr *td)
int test_init(struct tdescr *td)
{
+ if (td->sig_trig == sig_copyctx) {
+ fprintf(stdout,
+ "Signal %d is RESERVED, cannot be used as a trigger. Aborting\n",
+ sig_copyctx);
+ return 0;
+ }
+ /* just in case */
+ unblock_signal(sig_copyctx);
+
td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
if (!td->minsigstksz)
td->minsigstksz = MINSIGSTKSZ;
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 5e3a2b7aaa8b..fd67b1f23c41 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -4,6 +4,10 @@
#ifndef __TEST_SIGNALS_UTILS_H__
#define __TEST_SIGNALS_UTILS_H__
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
#include "test_signals.h"
int test_init(struct tdescr *td);
@@ -17,4 +21,98 @@ static inline bool feats_ok(struct tdescr *td)
return (td->feats_required & td->feats_supported) == td->feats_required;
}
+/*
+ * 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.
+ *
+ * As service-signal is used a SIGTRAP induced by a 'brk' instruction,
+ * because here we have to avoid syscalls to trigger the signal since
+ * they would cause any SVE sigframe content (if any) to be removed.
+ *
+ * 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 this 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 hitting a SEGV.
+ *
+ * Note that the case of runtime dynamically sized sigframes (like in SVE
+ * context) is still NOT addressed: sigframe size is supposed to be fixed
+ * at sizeof(ucontext_t).
+ */
+static __always_inline bool get_current_context(struct tdescr *td,
+ ucontext_t *dest_uc)
+{
+ static volatile bool seen_already;
+
+ assert(td && dest_uc);
+ /* it's a genuine invocation..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 SIGTRAP.
+ *
+ * Note that:
+ * - live_uc_valid is declared volatile sig_atomic_t in
+ * struct tdescr since it will be changed inside the
+ * sig_copyctx handler
+ * - the additional 'memory' clobber is there to avoid possible
+ * compiler's assumption on live_uc_valid and the content
+ * pointed by dest_uc, which are all changed inside the signal
+ * handler
+ * - BRK causes a debug exception which is handled by the Kernel
+ * and finally causes the SIGTRAP signal to be delivered to this
+ * test thread. Since such delivery happens on the ret_to_user()
+ * /do_notify_resume() debug exception return-path, we are sure
+ * that the registered SIGTRAP handler has been run to completion
+ * before the execution path is restored here: as a consequence
+ * we can be sure that the volatile sig_atomic_t live_uc_valid
+ * carries a meaningful result. Being in a single thread context
+ * we'll also be sure that any access to memory modified by the
+ * handler (namely ucontext_t) will be visible once returned.
+ * - note that since we are using a breakpoint instruction here
+ * to cause a SIGTRAP, the ucontext_t grabbed from the signal
+ * handler would naturally contain a PC pointing exactly to this
+ * BRK line, which means that, on return from the signal handler,
+ * or if we place the ucontext_t on the stack to fake a sigreturn,
+ * we'll end up in an infinite loop of BRK-SIGTRAP-handler.
+ * For this reason we take care to artificially move forward the
+ * PC to the next instruction while inside the signal handler.
+ */
+ asm volatile ("brk #666"
+ : "+m" (*dest_uc)
+ :
+ : "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 live_uc does not
+ * point to a just acquired copy of ucontext_t...so return 0
+ */
+ if (seen_already) {
+ fprintf(stdout,
+ "Unexpected successful sigreturn detected: live_uc is stale !\n");
+ return 0;
+ }
+ seen_already = 1;
+
+ return td->live_uc_valid;
+}
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v8 06/12] kselftest: arm64: add helper get_current_context
2019-10-09 8:26 ` [PATCH v8 06/12] kselftest: arm64: add helper get_current_context Cristian Marussi
@ 2019-10-09 11:32 ` Dave Martin
2019-10-09 11:57 ` Cristian Marussi
0 siblings, 1 reply; 21+ messages in thread
From: Dave Martin @ 2019-10-09 11:32 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On Wed, Oct 09, 2019 at 09:26:05AM +0100, Cristian Marussi wrote:
> Introduce a new common utility function get_current_context() which can be
> used to grab a ucontext without the help of libc, and also to detect if
> such ucontext has been successfully used by placing it on the stack as a
> fake sigframe.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> v7 --> v8
> - added new in v8 (splitted out from v7 05/11)
> ---
> .../selftests/arm64/signal/test_signals.h | 6 +-
> .../arm64/signal/test_signals_utils.c | 31 ++++++
> .../arm64/signal/test_signals_utils.h | 98 +++++++++++++++++++
> 3 files changed, 134 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> index 901521188202..4fd3ba01e3b1 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -88,8 +88,12 @@ 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 sig_atomic_t live_uc_valid;
> /* optional test private data */
> - void *priv;
> + void *priv;
>
> /* a custom setup: called alternatively to default_setup */
> 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 e8bbe36c2660..222148568adf 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -11,14 +11,19 @@
> #include <linux/auxvec.h>
> #include <ucontext.h>
>
> +#include <asm/unistd.h>
> +
> #include <kselftest.h>
>
> #include "test_signals.h"
> #include "test_signals_utils.h"
> #include "testcases/testcases.h"
>
> +
> extern struct tdescr *current;
>
> +static int sig_copyctx = SIGTRAP;
> +
> static char const *const feats_names[FMAX_END] = {
> " SSBS ",
> " PAN ",
> @@ -156,6 +161,20 @@ static bool handle_signal_ok(struct tdescr *td,
> return true;
> }
>
> +static bool handle_signal_copyctx(struct tdescr *td,
> + siginfo_t *si, void *uc)
> +{
> + /* Mangling PC to avoid loops on original BRK instr */
> + ((ucontext_t *)uc)->uc_mcontext.pc += 4;
> + memcpy(td->live_uc, uc, td->live_sz);
> + ASSERT_GOOD_CONTEXT(td->live_uc);
> + td->live_uc_valid = 1;
> + fprintf(stderr,
> + "GOOD CONTEXT grabbed from sig_copyctx handler\n");
> +
> + return true;
> +}
> +
> static void default_handler(int signum, siginfo_t *si, void *uc)
> {
> if (current->sig_unsupp && signum == current->sig_unsupp &&
> @@ -167,6 +186,9 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
> } else if (current->sig_ok && signum == current->sig_ok &&
> handle_signal_ok(current, si, uc)) {
> fprintf(stderr, "Handled SIG_OK\n");
> + } else if (signum == sig_copyctx && current->live_uc &&
> + handle_signal_copyctx(current, si, uc)) {
> + fprintf(stderr, "Handled SIG_COPYCTX\n");
> } else {
> if (signum == SIGALRM && current->timeout) {
> fprintf(stderr, "-- Timeout !\n");
> @@ -221,6 +243,15 @@ static inline int default_trigger(struct tdescr *td)
>
> int test_init(struct tdescr *td)
> {
> + if (td->sig_trig == sig_copyctx) {
> + fprintf(stdout,
> + "Signal %d is RESERVED, cannot be used as a trigger. Aborting\n",
> + sig_copyctx);
> + return 0;
> + }
> + /* just in case */
> + unblock_signal(sig_copyctx);
> +
> td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> if (!td->minsigstksz)
> td->minsigstksz = MINSIGSTKSZ;
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> index 5e3a2b7aaa8b..fd67b1f23c41 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -4,6 +4,10 @@
> #ifndef __TEST_SIGNALS_UTILS_H__
> #define __TEST_SIGNALS_UTILS_H__
>
> +#include <assert.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> #include "test_signals.h"
>
> int test_init(struct tdescr *td);
> @@ -17,4 +21,98 @@ static inline bool feats_ok(struct tdescr *td)
> return (td->feats_required & td->feats_supported) == td->feats_required;
> }
>
> +/*
> + * 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.
> + *
> + * As service-signal is used a SIGTRAP induced by a 'brk' instruction,
> + * because here we have to avoid syscalls to trigger the signal since
> + * they would cause any SVE sigframe content (if any) to be removed.
> + *
> + * 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 this 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 hitting a SEGV.
> + *
> + * Note that the case of runtime dynamically sized sigframes (like in SVE
> + * context) is still NOT addressed: sigframe size is supposed to be fixed
> + * at sizeof(ucontext_t).
> + */
> +static __always_inline bool get_current_context(struct tdescr *td,
> + ucontext_t *dest_uc)
> +{
> + static volatile bool seen_already;
> +
> + assert(td && dest_uc);
> + /* it's a genuine invocation..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 SIGTRAP.
> + *
> + * Note that:
> + * - live_uc_valid is declared volatile sig_atomic_t in
> + * struct tdescr since it will be changed inside the
> + * sig_copyctx handler
> + * - the additional 'memory' clobber is there to avoid possible
> + * compiler's assumption on live_uc_valid and the content
> + * pointed by dest_uc, which are all changed inside the signal
> + * handler
> + * - BRK causes a debug exception which is handled by the Kernel
> + * and finally causes the SIGTRAP signal to be delivered to this
> + * test thread. Since such delivery happens on the ret_to_user()
> + * /do_notify_resume() debug exception return-path, we are sure
> + * that the registered SIGTRAP handler has been run to completion
> + * before the execution path is restored here: as a consequence
> + * we can be sure that the volatile sig_atomic_t live_uc_valid
> + * carries a meaningful result. Being in a single thread context
> + * we'll also be sure that any access to memory modified by the
> + * handler (namely ucontext_t) will be visible once returned.
> + * - note that since we are using a breakpoint instruction here
> + * to cause a SIGTRAP, the ucontext_t grabbed from the signal
> + * handler would naturally contain a PC pointing exactly to this
> + * BRK line, which means that, on return from the signal handler,
> + * or if we place the ucontext_t on the stack to fake a sigreturn,
> + * we'll end up in an infinite loop of BRK-SIGTRAP-handler.
> + * For this reason we take care to artificially move forward the
> + * PC to the next instruction while inside the signal handler.
> + */
> + asm volatile ("brk #666"
> + : "+m" (*dest_uc)
> + :
> + : "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 live_uc does not
> + * point to a just acquired copy of ucontext_t...so return 0
> + */
> + if (seen_already) {
> + fprintf(stdout,
> + "Unexpected successful sigreturn detected: live_uc is stale !\n");
> + return 0;
> + }
> + seen_already = 1;
> +
> + return td->live_uc_valid;
> +}
> #endif
> --
> 2.17.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v8 06/12] kselftest: arm64: add helper get_current_context
2019-10-09 11:32 ` Dave Martin
@ 2019-10-09 11:57 ` Cristian Marussi
0 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 11:57 UTC (permalink / raw)
To: Dave Martin
Cc: linux-kselftest, linux-arm-kernel, shuah, amit.kachhap, andreyknvl
On 09/10/2019 12:32, Dave Martin wrote:
> On Wed, Oct 09, 2019 at 09:26:05AM +0100, Cristian Marussi wrote:
>> Introduce a new common utility function get_current_context() which can be
>> used to grab a ucontext without the help of libc, and also to detect if
>> such ucontext has been successfully used by placing it on the stack as a
>> fake sigframe.
>
> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>
Thanks
Cristian
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> v7 --> v8
>> - added new in v8 (splitted out from v7 05/11)
>> ---
>> .../selftests/arm64/signal/test_signals.h | 6 +-
>> .../arm64/signal/test_signals_utils.c | 31 ++++++
>> .../arm64/signal/test_signals_utils.h | 98 +++++++++++++++++++
>> 3 files changed, 134 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>> index 901521188202..4fd3ba01e3b1 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>> @@ -88,8 +88,12 @@ 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 sig_atomic_t live_uc_valid;
>> /* optional test private data */
>> - void *priv;
>> + void *priv;
>>
>> /* a custom setup: called alternatively to default_setup */
>> 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 e8bbe36c2660..222148568adf 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -11,14 +11,19 @@
>> #include <linux/auxvec.h>
>> #include <ucontext.h>
>>
>> +#include <asm/unistd.h>
>> +
>> #include <kselftest.h>
>>
>> #include "test_signals.h"
>> #include "test_signals_utils.h"
>> #include "testcases/testcases.h"
>>
>> +
>> extern struct tdescr *current;
>>
>> +static int sig_copyctx = SIGTRAP;
>> +
>> static char const *const feats_names[FMAX_END] = {
>> " SSBS ",
>> " PAN ",
>> @@ -156,6 +161,20 @@ static bool handle_signal_ok(struct tdescr *td,
>> return true;
>> }
>>
>> +static bool handle_signal_copyctx(struct tdescr *td,
>> + siginfo_t *si, void *uc)
>> +{
>> + /* Mangling PC to avoid loops on original BRK instr */
>> + ((ucontext_t *)uc)->uc_mcontext.pc += 4;
>> + memcpy(td->live_uc, uc, td->live_sz);
>> + ASSERT_GOOD_CONTEXT(td->live_uc);
>> + td->live_uc_valid = 1;
>> + fprintf(stderr,
>> + "GOOD CONTEXT grabbed from sig_copyctx handler\n");
>> +
>> + return true;
>> +}
>> +
>> static void default_handler(int signum, siginfo_t *si, void *uc)
>> {
>> if (current->sig_unsupp && signum == current->sig_unsupp &&
>> @@ -167,6 +186,9 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
>> } else if (current->sig_ok && signum == current->sig_ok &&
>> handle_signal_ok(current, si, uc)) {
>> fprintf(stderr, "Handled SIG_OK\n");
>> + } else if (signum == sig_copyctx && current->live_uc &&
>> + handle_signal_copyctx(current, si, uc)) {
>> + fprintf(stderr, "Handled SIG_COPYCTX\n");
>> } else {
>> if (signum == SIGALRM && current->timeout) {
>> fprintf(stderr, "-- Timeout !\n");
>> @@ -221,6 +243,15 @@ static inline int default_trigger(struct tdescr *td)
>>
>> int test_init(struct tdescr *td)
>> {
>> + if (td->sig_trig == sig_copyctx) {
>> + fprintf(stdout,
>> + "Signal %d is RESERVED, cannot be used as a trigger. Aborting\n",
>> + sig_copyctx);
>> + return 0;
>> + }
>> + /* just in case */
>> + unblock_signal(sig_copyctx);
>> +
>> td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>> if (!td->minsigstksz)
>> td->minsigstksz = MINSIGSTKSZ;
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> index 5e3a2b7aaa8b..fd67b1f23c41 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -4,6 +4,10 @@
>> #ifndef __TEST_SIGNALS_UTILS_H__
>> #define __TEST_SIGNALS_UTILS_H__
>>
>> +#include <assert.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +
>> #include "test_signals.h"
>>
>> int test_init(struct tdescr *td);
>> @@ -17,4 +21,98 @@ static inline bool feats_ok(struct tdescr *td)
>> return (td->feats_required & td->feats_supported) == td->feats_required;
>> }
>>
>> +/*
>> + * 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.
>> + *
>> + * As service-signal is used a SIGTRAP induced by a 'brk' instruction,
>> + * because here we have to avoid syscalls to trigger the signal since
>> + * they would cause any SVE sigframe content (if any) to be removed.
>> + *
>> + * 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 this 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 hitting a SEGV.
>> + *
>> + * Note that the case of runtime dynamically sized sigframes (like in SVE
>> + * context) is still NOT addressed: sigframe size is supposed to be fixed
>> + * at sizeof(ucontext_t).
>> + */
>> +static __always_inline bool get_current_context(struct tdescr *td,
>> + ucontext_t *dest_uc)
>> +{
>> + static volatile bool seen_already;
>> +
>> + assert(td && dest_uc);
>> + /* it's a genuine invocation..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 SIGTRAP.
>> + *
>> + * Note that:
>> + * - live_uc_valid is declared volatile sig_atomic_t in
>> + * struct tdescr since it will be changed inside the
>> + * sig_copyctx handler
>> + * - the additional 'memory' clobber is there to avoid possible
>> + * compiler's assumption on live_uc_valid and the content
>> + * pointed by dest_uc, which are all changed inside the signal
>> + * handler
>> + * - BRK causes a debug exception which is handled by the Kernel
>> + * and finally causes the SIGTRAP signal to be delivered to this
>> + * test thread. Since such delivery happens on the ret_to_user()
>> + * /do_notify_resume() debug exception return-path, we are sure
>> + * that the registered SIGTRAP handler has been run to completion
>> + * before the execution path is restored here: as a consequence
>> + * we can be sure that the volatile sig_atomic_t live_uc_valid
>> + * carries a meaningful result. Being in a single thread context
>> + * we'll also be sure that any access to memory modified by the
>> + * handler (namely ucontext_t) will be visible once returned.
>> + * - note that since we are using a breakpoint instruction here
>> + * to cause a SIGTRAP, the ucontext_t grabbed from the signal
>> + * handler would naturally contain a PC pointing exactly to this
>> + * BRK line, which means that, on return from the signal handler,
>> + * or if we place the ucontext_t on the stack to fake a sigreturn,
>> + * we'll end up in an infinite loop of BRK-SIGTRAP-handler.
>> + * For this reason we take care to artificially move forward the
>> + * PC to the next instruction while inside the signal handler.
>> + */
>> + asm volatile ("brk #666"
>> + : "+m" (*dest_uc)
>> + :
>> + : "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 live_uc does not
>> + * point to a just acquired copy of ucontext_t...so return 0
>> + */
>> + if (seen_already) {
>> + fprintf(stdout,
>> + "Unexpected successful sigreturn detected: live_uc is stale !\n");
>> + return 0;
>> + }
>> + seen_already = 1;
>> +
>> + return td->live_uc_valid;
>> +}
>> #endif
>> --
>> 2.17.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v8 07/12] kselftest: arm64: fake_sigreturn_bad_magic
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (5 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 06/12] kselftest: arm64: add helper get_current_context Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 08/12] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
` (4 subsequent siblings)
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add 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.
Introduce a common utility assembly trampoline function to invoke a
sigreturn while placing the provided sigframe at wanted alignment and
also an helper to make space when needed inside the sigframe reserved
area.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v6 --> v7
- fix fake_sigreturn alignment routines (+15)
v5 --> v6
- fake_sigreturn: cleaned up, avoiding excessive SP misalignments
- fake_sigreturn: better formatting and prologue
- get_starting_header: cleand up and commented
- avoid timeout on failure
v3 --> v4
- fix commit
- fix signal.S, handle misalign requests too
- remove unneeded comments
- add signal.h include
- added get_starting_head() helper
- added test description
---
tools/testing/selftests/arm64/signal/Makefile | 2 +-
.../testing/selftests/arm64/signal/signals.S | 64 +++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 2 +
.../testcases/fake_sigreturn_bad_magic.c | 52 +++++++++++++++
.../arm64/signal/testcases/testcases.c | 46 +++++++++++++
.../arm64/signal/testcases/testcases.h | 4 ++
6 files changed, 169 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 f78f5190e3d4..b497cfea4643 100644
--- a/tools/testing/selftests/arm64/signal/Makefile
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -28,5 +28,5 @@ clean:
# 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
$(CC) $(CFLAGS) $^ -o $@
diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
new file mode 100644
index 000000000000..9f8c1aefc3b9
--- /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 SP @%08lX\n"
+
+.text
+
+.globl fake_sigreturn
+
+/* fake_sigreturn x0:&sigframe, x1:sigframe_size, x2:misalign_bytes */
+fake_sigreturn:
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ mov x20, x0
+ mov x21, x1
+ mov x22, x2
+
+ /* create space on the stack for fake sigframe 16 bytes-aligned */
+ add x0, x21, x22
+ add x0, x0, #15
+ bic x0, x0, #15 /* round_up(sigframe_size + misalign_bytes, 16) */
+ sub sp, sp, x0
+ add x23, sp, x22 /* new sigframe base with misaligment if any */
+
+ ldr x0, =call_fmt
+ mov x1, x21
+ mov x2, x23
+ bl printf
+
+ /* memcpy the provided content, while still keeping SP aligned */
+ mov x0, x23
+ 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 possibly 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]
+ /* finally move SP to misaligned address...if any requested */
+ mov sp, x23
+
+ 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 fd67b1f23c41..6772b5c8d274 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -115,4 +115,6 @@ static __always_inline bool get_current_context(struct tdescr *td,
return td->live_uc_valid;
}
+
+int fake_sigreturn(void *sigframe, size_t sz, int misalign_bytes);
#endif
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..8dc600a7d4fd
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack including a BAD Unknown magic
+ * record: on sigreturn Kernel must spot this attempt and the test
+ * case is expected to be terminated via SEGV.
+ */
+
+#include <signal.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)
+{
+ 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;
+
+ /* need at least 2*HDR_SZ space: KSFT_BAD_MAGIC + terminator. */
+ head = get_starting_head(shead, HDR_SZ * 2, GET_SF_RESV_SIZE(sf), NULL);
+ if (!head)
+ return 0;
+
+ /*
+ * 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), 0);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_MAGIC",
+ .descr = "Trigger a sigreturn with a sigframe with a bad magic",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_magic_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
index 1914a01222a1..e3521949b800 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.c
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -148,3 +148,49 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
return true;
}
+
+/*
+ * This function walks through the records inside the provided reserved area
+ * trying to find enough space to fit @need_sz bytes: if not enough space is
+ * available and an extra_context record is present, it throws away the
+ * extra_context record.
+ *
+ * It returns a pointer to a new header where it is possible to start storing
+ * our need_sz bytes.
+ *
+ * @shead: points to the start of reserved area
+ * @need_sz: needed bytes
+ * @resv_sz: reserved area size in bytes
+ * @offset: if not null, this will be filled with the offset of the return
+ * head pointer from @shead
+ *
+ * @return: pointer to a new head where to start storing need_sz bytes, or
+ * NULL if space could not be made available.
+ */
+struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,
+ size_t need_sz, size_t resv_sz,
+ size_t *offset)
+{
+ size_t offs = 0;
+ struct _aarch64_ctx *head;
+
+ head = get_terminator(shead, resv_sz, &offs);
+ /* not found a terminator...no need to update offset if any */
+ if (!head)
+ return head;
+ if (resv_sz - offs < need_sz) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offs);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs);
+ if (!head || resv_sz - offs < need_sz) {
+ fprintf(stderr,
+ "Failed to reclaim space on sigframe.\n");
+ return NULL;
+ }
+ }
+
+ fprintf(stderr, "Available space:%zd\n", resv_sz - offs);
+ if (offset)
+ *offset = offs;
+ return head;
+}
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
index 04987f7870bc..ad884c135314 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.h
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -97,4 +97,8 @@ static inline void write_terminator_record(struct _aarch64_ctx *tail)
tail->size = 0;
}
}
+
+struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,
+ size_t need_sz, size_t resv_sz,
+ size_t *offset);
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 08/12] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (6 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 07/12] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 09/12] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
` (3 subsequent siblings)
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add a simple fake_sigreturn testcase which builds a ucontext_t with a
badly sized terminator record and place it onto the stack.
Expects a SIGSEGV on test PASS.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v5 --> v6
- removed unneeded locals
- removed unneeded timeout on failure
v3 --> v4
- fix commit
- add signal.h include
- using new get_starting_head() helper
- added test description
---
.../fake_sigreturn_bad_size_for_magic0.c | 46 +++++++++++++++++++
1 file changed, 46 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/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..a44b88bfc81a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack including a badly sized terminator
+ * record: on sigreturn Kernel must spot this attempt and the test case
+ * is expected to be terminated via SEGV.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ 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;
+
+ /* at least HDR_SZ for the badly sized terminator. */
+ head = get_starting_head(shead, HDR_SZ, GET_SF_RESV_SIZE(sf), NULL);
+ if (!head)
+ return 0;
+
+ head->magic = 0;
+ head->size = HDR_SZ;
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 0);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE_FOR_TERMINATOR",
+ .descr = "Trigger a sigreturn using non-zero size terminator",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_for_magic0_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 09/12] kselftest: arm64: fake_sigreturn_missing_fpsimd
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (7 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 08/12] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 10/12] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
` (2 subsequent siblings)
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add 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.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v3 --> v4
- fix commit
- added signal.h
- added test description
---
.../testcases/fake_sigreturn_missing_fpsimd.c | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
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..08ecd8073a1a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack missing the mandatory FPSIMD
+ * record: on sigreturn Kernel must spot this attempt and the test
+ * case is expected to be terminated via SEGV.
+ */
+
+#include <stdio.h>
+#include <signal.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);
+ 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), 0);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_MISSING_FPSIMD",
+ .descr = "Triggers a sigreturn with a missing fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_missing_fpsimd_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 10/12] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (8 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 09/12] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 11/12] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 12/12] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add 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.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v6 --> v7
- fixed typo
v5 --> v6
- removed unneeded locals
- avoid timeout on failure
v3 --> v4
- fix commit
- missing include
- using new get_starting_head() helper
- added test description
---
.../fake_sigreturn_duplicated_fpsimd.c | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
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..afe8915f0998
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack including an additional FPSIMD
+ * record: on sigreturn Kernel must spot this attempt and the test
+ * case is expected to be terminated via SEGV.
+ */
+
+#include <signal.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)
+{
+ 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;
+
+ head = get_starting_head(shead, sizeof(struct fpsimd_context) + HDR_SZ,
+ GET_SF_RESV_SIZE(sf), NULL);
+ if (!head)
+ return 0;
+
+ /* Add a spurious 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), 0);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_DUPLICATED_FPSIMD",
+ .descr = "Triggers a sigreturn including two fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_duplicated_fpsimd_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 11/12] kselftest: arm64: fake_sigreturn_bad_size
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (9 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 10/12] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
2019-10-09 8:26 ` [PATCH v8 12/12] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add 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.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v5 --> v6
- avoid timeout on failure
v3 --> v4
- fix commit
- missing include
- using new get_starting_head() helper
- added test description
---
.../testcases/fake_sigreturn_bad_size.c | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
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..b3c362100666
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack including a bad record overflowing
+ * the __reserved space: on sigreturn Kernel must spot this attempt and
+ * the test case is expected to be terminated via SEGV.
+ */
+
+#include <signal.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);
+ /* at least HDR_SZ + bad sized esr_context needed */
+ need_sz = sizeof(struct esr_context) + HDR_SZ;
+ head = get_starting_head(shead, need_sz, resv_sz, &offset);
+ if (!head)
+ return 0;
+
+ /*
+ * 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
+ * needed while 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), 0);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE",
+ .descr = "Triggers a sigreturn with a overrun __reserved area",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v8 12/12] kselftest: arm64: fake_sigreturn_misaligned_sp
2019-10-09 8:25 [PATCH v8 00/12] Add arm64/signal initial kselftest support Cristian Marussi
` (10 preceding siblings ...)
2019-10-09 8:26 ` [PATCH v8 11/12] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
@ 2019-10-09 8:26 ` Cristian Marussi
11 siblings, 0 replies; 21+ messages in thread
From: Cristian Marussi @ 2019-10-09 8:26 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah
Cc: andreyknvl, dave.martin, amit.kachhap
Add a simple fake_sigreturn testcase which places a valid sigframe on a
non-16 bytes aligned SP. Expects a SIGSEGV on test PASS.
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v3 --> v4
- fix commit
- use new fake_sigreturn misalig_bytes params
- removed TODO
- added test description
---
.../testcases/fake_sigreturn_misaligned_sp.c | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
new file mode 100644
index 000000000000..1e089e66f9f3
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 ARM Limited
+ *
+ * Place a fake sigframe on the stack at a misaligned SP: on sigreturn
+ * Kernel must spot this attempt and the test case is expected to be
+ * terminated via SEGV.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_misaligned_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ /* Forcing sigframe on misaligned SP (16 + 3) */
+ fake_sigreturn(&sf, sizeof(sf), 3);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_MISALIGNED_SP",
+ .descr = "Triggers a sigreturn with a misaligned sigframe",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_misaligned_run,
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 21+ messages in thread