From nobody Mon Feb 9 05:52:58 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6781B15FA8D; Fri, 5 Apr 2024 08:49:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712306993; cv=none; b=G+GzrbX35Ua8ai4SUqWwsaMcHc0VRpehoLvjg+CmszTuiOid7tkj8XAAIgyn3hOZ1b7cyI0u4Dd9hq4WpZjBTrHVkookL9e/qnF8+u6+MQUj5Yz2SbOziyV1SDVfr6jjMN9Z9dh+u9NXW2oJ9cqFO07hwBkHzRGghkHIdKZJ7PA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712306993; c=relaxed/simple; bh=u+HUzxYLCfySfWM6T+hRKqGJDsoBpjm+5Q0bROj9OYY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HlA/1h7Mccq6ymwpc5bH27eiVbXkyMApANe+k3TWB4wHHnr9UVe0Q4kMQcNEbUMh0B/7iUYlOOxmgb4fPiE8JFhQtmu29KK067ivMs1S9KjhNGWVVmlVkMlOxO8xv1AzPjNzRRFkFiiOrLfD0W00cTl60JcqqtFrO1SLP6uXGDc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 73E7A1007; Fri, 5 Apr 2024 01:50:21 -0700 (PDT) Received: from e116581.blr.arm.com (e116581.arm.com [10.162.43.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6B2C73F64C; Fri, 5 Apr 2024 01:49:46 -0700 (PDT) From: Dev Jain To: shuah@kernel.org, linux-arm-kernel@lists.infradead.org Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Anshuman.Khandual@arm.com, suzuki.poulose@arm.com, ryan.roberts@arm.com, rob.herring@arm.com, Catalin.Marinas@arm.com, broonie@kernel.org, will@kernel.org, mark.rutland@arm.com, Dev Jain Subject: [PATCH 1/4] selftests/arm: Add mm test Date: Fri, 5 Apr 2024 14:14:07 +0530 Message-Id: <20240405084410.256788-2-dev.jain@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240405084410.256788-1-dev.jain@arm.com> References: <20240405084410.256788-1-dev.jain@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch tests the 4GB VA restriction for 32-bit processes; it is required to test the compat layer, whether the kernel knows that it is running a 32-= bit process or not. Chunks are allocated until the VA gets exhausted; mmap must fail beyond 4GB. This is asserted against the VA mappings found in /proc/self/maps. Signed-off-by: Dev Jain --- tools/testing/selftests/arm/mm/compat_va.c | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tools/testing/selftests/arm/mm/compat_va.c diff --git a/tools/testing/selftests/arm/mm/compat_va.c b/tools/testing/sel= ftests/arm/mm/compat_va.c new file mode 100644 index 000000000000..3a78f240bc87 --- /dev/null +++ b/tools/testing/selftests/arm/mm/compat_va.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 ARM Limited + * + * Author : Dev Jain + * + * Tests 4GB VA restriction for 32 bit process + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include + +#define MAP_CHUNK_SIZE SZ_1M +#define NR_CHUNKS_4G (SZ_1G / MAP_CHUNK_SIZE) * 4 /* prevent overflow */ + +static int validate_address_hint(void) +{ + char *ptr; + + ptr =3D mmap((void *) (1UL << 29), MAP_CHUNK_SIZE, PROT_READ | + PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (ptr =3D=3D MAP_FAILED) + return 0; + + return 1; +} + +int main(int argc, char *argv[]) +{ + char *ptr[NR_CHUNKS_4G + 3]; + char line[1000]; + const char *file_name; + int chunks; + FILE *file; + int i; + + ksft_print_header(); + ksft_set_plan(1); + + /* try allocation beyond 4 GB */ + for (i =3D 0; i < NR_CHUNKS_4G + 3; ++i) { + ptr[i] =3D mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (ptr[i] =3D=3D MAP_FAILED) { + if (validate_address_hint()) + ksft_exit_fail_msg("VA exhaustion failed\n"); + break; + } + } + + chunks =3D i; + if (chunks >=3D NR_CHUNKS_4G) { + ksft_test_result_fail("mmapped chunks beyond 4GB\n"); + ksft_finished(); + } + + /* parse /proc/self/maps, confirm 32 bit VA mappings */ + file_name =3D "/proc/self/maps"; + file =3D fopen(file_name, "r"); + if (file =3D=3D NULL) + ksft_exit_fail_msg("/proc/self/maps cannot be opened\n"); + + while (fgets(line, sizeof(line), file)) { + const char *whitespace_loc, *hyphen_loc; + + hyphen_loc =3D strchr(line, '-'); + whitespace_loc =3D strchr(line, ' '); + + if (!(hyphen_loc && whitespace_loc)) { + ksft_test_result_skip("Unexpected format"); + ksft_finished(); + } + + if ((hyphen_loc - line > 8) || + (whitespace_loc - hyphen_loc) > 9) { + ksft_test_result_fail("Memory map more than 32 bits\n"); + ksft_finished(); + } + } + + for (int i =3D 0; i < chunks; ++i) + munmap(ptr[i], MAP_CHUNK_SIZE); + + ksft_test_result_pass("Test\n"); + ksft_finished(); +} --=20 2.39.2 From nobody Mon Feb 9 05:52:58 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CDED415FA99; Fri, 5 Apr 2024 08:49:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712306999; cv=none; b=TRIXl1cD+/kAAciyA0dGkltVZKn6MGzBdHFhEnx8IX3El5pFEIOZfAL9mWe70najvBfMqXJbXJBxUHU0TnThJndQrst7alJzDBxDuknfmJ5N8FYnvfPkEi7Io+2KVMCSFGIYzjy0+v9P+8fBOYbHnsePwfa4o0bM6kiu+rKtq8A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712306999; c=relaxed/simple; bh=tX6E2H8buOjrri9YyhAc10zMB6t29GgqGgvvPgqaBdo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SNcLHq2Wr9vnJaugABW7zw9tpG+UsW0C/5HTEzBovK2Hja9TngVpNz1J0JCvALfWo0/otrarZcO8bRA4fnjuJdeIQa/0KUR8XFn+0meYp763U9FyKQI4duJ7OCXF4iv46LMrg/wiBr7d+2nxWe6o3t4jua0FhepPcwedrYCJ1YU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AA807FEC; Fri, 5 Apr 2024 01:50:26 -0700 (PDT) Received: from e116581.blr.arm.com (e116581.arm.com [10.162.43.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 879953F64C; Fri, 5 Apr 2024 01:49:51 -0700 (PDT) From: Dev Jain To: shuah@kernel.org, linux-arm-kernel@lists.infradead.org Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Anshuman.Khandual@arm.com, suzuki.poulose@arm.com, ryan.roberts@arm.com, rob.herring@arm.com, Catalin.Marinas@arm.com, broonie@kernel.org, will@kernel.org, mark.rutland@arm.com, Dev Jain Subject: [PATCH 2/4] selftests/arm: Add signal tests Date: Fri, 5 Apr 2024 14:14:08 +0530 Message-Id: <20240405084410.256788-3-dev.jain@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240405084410.256788-1-dev.jain@arm.com> References: <20240405084410.256788-1-dev.jain@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch introduces two signal tests, and generic test wrappers similar to selftests/arm64/signal directory, along with the mangling testcases found therein. arm_cpsr, dumped by the kernel to user space in the ucontext struc= ture to the signal handler, is mangled with. The kernel must spot this illegal attempt and the testcases are expected to terminate via SEGV. Signed-off-by: Dev Jain --- .../selftests/arm/signal/test_signals.c | 27 ++ .../selftests/arm/signal/test_signals.h | 74 +++++ .../selftests/arm/signal/test_signals_utils.c | 257 ++++++++++++++++++ .../selftests/arm/signal/test_signals_utils.h | 128 +++++++++ .../signal/testcases/mangle_cpsr_aif_bits.c | 33 +++ .../mangle_cpsr_invalid_compat_toggle.c | 29 ++ 6 files changed, 548 insertions(+) create mode 100644 tools/testing/selftests/arm/signal/test_signals.c create mode 100644 tools/testing/selftests/arm/signal/test_signals.h create mode 100644 tools/testing/selftests/arm/signal/test_signals_utils.c create mode 100644 tools/testing/selftests/arm/signal/test_signals_utils.h create mode 100644 tools/testing/selftests/arm/signal/testcases/mangle_cps= r_aif_bits.c create mode 100644 tools/testing/selftests/arm/signal/testcases/mangle_cps= r_invalid_compat_toggle.c diff --git a/tools/testing/selftests/arm/signal/test_signals.c b/tools/test= ing/selftests/arm/signal/test_signals.c new file mode 100644 index 000000000000..1ecf1e9f041c --- /dev/null +++ b/tools/testing/selftests/arm/signal/test_signals.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 ARM Limited + * + * Generic test wrapper for arm signal tests. + * + * Each test provides its own tde struct tdescr descriptor to link with + * this wrapper. Framework provides common helpers. + */ +#include + +#include "test_signals.h" +#include "test_signals_utils.h" + +struct tdescr *current =3D &tde; + +int main(int argc, char *argv[]) +{ + ksft_print_msg("%s :: %s\n", current->name, current->descr); + if (test_setup(current) && test_init(current)) { + test_run(current); + test_cleanup(current); + } + test_result(current); + + return current->result; +} diff --git a/tools/testing/selftests/arm/signal/test_signals.h b/tools/test= ing/selftests/arm/signal/test_signals.h new file mode 100644 index 000000000000..bbd147127d66 --- /dev/null +++ b/tools/testing/selftests/arm/signal/test_signals.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2024 ARM Limited */ + +#ifndef __TEST_SIGNALS_H__ +#define __TEST_SIGNALS_H__ + +#include +#include +#include + +/* + * Using ARCH specific and sanitized Kernel headers from the tree. + */ +#include +#include + +/* + * 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; + + 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; + unsigned int result; + /* 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; + + /* 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 starting test */ + 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/arm/signal/test_signals_utils.c b/tool= s/testing/selftests/arm/signal/test_signals_utils.c new file mode 100644 index 000000000000..96aeb11de151 --- /dev/null +++ b/tools/testing/selftests/arm/signal/test_signals_utils.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2024 ARM Limited */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "test_signals.h" +#include "test_signals_utils.h" + + +extern struct tdescr *current; + +static int sig_copyctx =3D SIGTRAP; + +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->result =3D=3D KSFT_SKIP) { + fprintf(stderr, "=3D=3D>> completed. SKIP.\n"); + } else if (td->pass) { + fprintf(stderr, "=3D=3D>> completed. PASS(1)\n"); + td->result =3D KSFT_PASS; + } else { + fprintf(stdout, "=3D=3D>> completed. FAIL(0)\n"); + td->result =3D KSFT_FAIL; + } + + if (force_exit) + exit(td->result); +} + +/* + * 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) +{ + + /* Mangling PC to avoid loops on original SIGILL */ + ((ucontext_t *)uc)->uc_mcontext.arm_pc +=3D 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 =3D 1; + default_result(current, 1); + } + + return true; +} + +static bool handle_signal_trigger(struct tdescr *td, + siginfo_t *si, void *uc) +{ + td->triggered =3D 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%lX si_addr@:%p si_code:%d token@:%p offset:%d\n", + ((ucontext_t *)uc)->uc_mcontext.arm_sp, + si->si_addr, si->si_code, td->token, td->token - si->si_addr); + + /* + * 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 =3D=3D SIGSEGV && si->si_code !=3D SEGV_ACCERR) { + fprintf(stdout, + "si_code !=3D SEGV_ACCERR...test is probably broken!\n"); + abort(); + } + td->pass =3D 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 =3D=3D current->sig_unsupp && + handle_signal_unsupported(current, si, uc)) { + fprintf(stderr, "Handled SIG_UNSUPP\n"); + } else if (current->sig_trig && signum =3D=3D current->sig_trig && + handle_signal_trigger(current, si, uc)) { + fprintf(stderr, "Handled SIG_TRIG\n"); + } else if (current->sig_ok && signum =3D=3D current->sig_ok && + handle_signal_ok(current, si, uc)) { + fprintf(stderr, "Handled SIG_OK\n"); + } else if (signum =3D=3D sig_copyctx && current->live_uc) { + fprintf(stderr, "Handled SIG_COPYCTX\n"); + } else { + if (signum =3D=3D SIGALRM && current->timeout) { + fprintf(stderr, "-- Timeout !\n"); + } else { + fprintf(stderr, + "-- RX UNEXPECTED SIGNAL: %d code %d address %p\n", + signum, si->si_code, si->si_addr); + } + default_result(current, 1); + } +} + +static int default_setup(struct tdescr *td) +{ + struct sigaction sa; + + sa.sa_sigaction =3D default_handler; + sa.sa_flags =3D SA_SIGINFO | SA_RESTART; + sa.sa_flags |=3D td->sa_flags; + sigemptyset(&sa.sa_mask); + /* uncatchable signals naturally skipped ... */ + for (int sig =3D 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 =3D SIGRTMIN; sig <=3D 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); +} + +int test_init(struct tdescr *td) +{ + if (td->sig_trig =3D=3D 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 =3D getauxval(AT_MINSIGSTKSZ); + if (!td->minsigstksz) + td->minsigstksz =3D MINSIGSTKSZ; + fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz); + + /* Perform test specific additional initialization */ + if (td->init && !td->init(td)) { + fprintf(stderr, "FAILED Testcase initialization.\n"); + return 0; + } + td->initialized =3D 1; + fprintf(stderr, "Testcase initialized.\n"); + + 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); + + /* Default result is FAIL if test setup fails */ + td->result =3D KSFT_FAIL; + if (td->setup) + return td->setup(td); + else + return default_setup(td); +} + +int test_run(struct tdescr *td) +{ + if (td->trigger) + return td->trigger(td); + else if (td->sig_trig) + return default_trigger(td); + else + return td->run(td, NULL, NULL); +} + +void test_result(struct tdescr *td) +{ + if (td->initialized && td->result !=3D KSFT_SKIP && 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/arm/signal/test_signals_utils.h b/tool= s/testing/selftests/arm/signal/test_signals_utils.h new file mode 100644 index 000000000000..386dcc6c268d --- /dev/null +++ b/tools/testing/selftests/arm/signal/test_signals_utils.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2024 ARM Limited */ + +#ifndef __TEST_SIGNALS_UTILS_H__ +#define __TEST_SIGNALS_UTILS_H__ + +#include +#include +#include + +#include +#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); +void test_result(struct tdescr *td); + +/* + * 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= =3D=3D1): + * 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, + size_t dest_sz) +{ + static volatile bool seen_already; + int i; + char *uc =3D (char *)dest_uc; + + assert(td && dest_uc); + /* it's a genuine invocation..reinit */ + seen_already =3D 0; + td->live_uc_valid =3D 0; + td->live_sz =3D dest_sz; + + /* + * This is a memset() but we don't want the compiler to + * optimise it into either instructions or a library call + * which might be incompatible with streaming mode. + */ + for (i =3D 0; i < td->live_sz; i++) { + uc[i] =3D 0; + OPTIMIZER_HIDE_VAR(uc[0]); + } + + td->live_uc =3D 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=3D=3D1 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 =3D 1; + + return td->live_uc_valid; +} + +#endif diff --git a/tools/testing/selftests/arm/signal/testcases/mangle_cpsr_aif_b= its.c b/tools/testing/selftests/arm/signal/testcases/mangle_cpsr_aif_bits.c new file mode 100644 index 000000000000..f422cd11ccf2 --- /dev/null +++ b/tools/testing/selftests/arm/signal/testcases/mangle_cpsr_aif_bits.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 ARM Limited + * + * Try to mangle the ucontext from inside a signal handler, mangling the + * AIF 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" + +static int mangle_invalid_cpsr_run(struct tdescr *td, siginfo_t *si, + ucontext_t *uc) +{ + + /* + * This config should trigger a SIGSEGV by Kernel when it checks + * the sigframe consistency in valid_user_regs() routine. + */ + uc->uc_mcontext.arm_cpsr |=3D PSR_A_BIT | PSR_I_BIT | PSR_F_BIT; + + return 1; +} + +struct tdescr tde =3D { + .sanity_disabled =3D true, + .name =3D "MANGLE_CPSR_INVALID_AIF_BITS", + .descr =3D "Mangling uc_mcontext with INVALID AIF_BITS", + .sig_trig =3D SIGUSR1, + .sig_ok =3D SIGSEGV, + .run =3D mangle_invalid_cpsr_run, +}; diff --git a/tools/testing/selftests/arm/signal/testcases/mangle_cpsr_inval= id_compat_toggle.c b/tools/testing/selftests/arm/signal/testcases/mangle_cp= sr_invalid_compat_toggle.c new file mode 100644 index 000000000000..cb7eb8aec7f2 --- /dev/null +++ b/tools/testing/selftests/arm/signal/testcases/mangle_cpsr_invalid_comp= at_toggle.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 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" + +static int mangle_invalid_cpsr_run(struct tdescr *td, siginfo_t *si, + ucontext_t *uc) +{ + + /* This config should trigger a SIGSEGV by Kernel */ + uc->uc_mcontext.arm_cpsr ^=3D MODE32_BIT; + + return 1; +} + +struct tdescr tde =3D { + .sanity_disabled =3D true, + .name =3D "MANGLE_CPSR_INVALID_STATE_TOGGLE", + .descr =3D "Mangling uc_mcontext with INVALID STATE_TOGGLE", + .sig_trig =3D SIGUSR1, + .sig_ok =3D SIGSEGV, + .run =3D mangle_invalid_cpsr_run, +}; --=20 2.39.2 From nobody Mon Feb 9 05:52:58 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CF61A15FD0A; Fri, 5 Apr 2024 08:50:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712307003; cv=none; b=jhtTyvblDRH/07NDbgaW3gHgTIu82+NWA+CTaQ5IPpNjtt3+JMqYUAOcKelTO02zwcqmhGrj7j84hy8DS68fCXtCi2kg2Dpyb9EDvqvr7GUTM6rYKJm8XG/w6YG9zy/a5gZRe74HOBaaKP+hQUoQKXSZsyXl/IVUYq7wupaeKh0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712307003; c=relaxed/simple; bh=p/8Fq+jpurELJ6V7Gi3YxX1mI3RCEZP5MKqChiEaFz0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sfDqEbJMUnNfIkhtgYmouD1/Z5g79Iu+O2xK0fsB446Z6rJQuxY2aaykeIUq/8UmLHlMwj+wiwYuCmy//6GVFE8ilW1nNNqXWpJ3w8t+vaSAuJRy/YgWmJeBaDgwV2oOp2AulVlTzKwD5of14HDzDjo8ATQ6txLVXD9ocHFjW3A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C73FFFEC; Fri, 5 Apr 2024 01:50:31 -0700 (PDT) Received: from e116581.blr.arm.com (e116581.arm.com [10.162.43.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id BF8443F64C; Fri, 5 Apr 2024 01:49:56 -0700 (PDT) From: Dev Jain To: shuah@kernel.org, linux-arm-kernel@lists.infradead.org Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Anshuman.Khandual@arm.com, suzuki.poulose@arm.com, ryan.roberts@arm.com, rob.herring@arm.com, Catalin.Marinas@arm.com, broonie@kernel.org, will@kernel.org, mark.rutland@arm.com, Dev Jain Subject: [PATCH 3/4] selftests/arm: Add elf test Date: Fri, 5 Apr 2024 14:14:09 +0530 Message-Id: <20240405084410.256788-4-dev.jain@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240405084410.256788-1-dev.jain@arm.com> References: <20240405084410.256788-1-dev.jain@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch introduces an ELF parsing test; the 5th byte of the ELF header must be 0x01 for a 32-bit process. A basic sanity check is required to ensu= re that we are actually testing a 32-bit build. Signed-off-by: Dev Jain --- tools/testing/selftests/arm/elf/parse_elf.c | 75 +++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tools/testing/selftests/arm/elf/parse_elf.c diff --git a/tools/testing/selftests/arm/elf/parse_elf.c b/tools/testing/se= lftests/arm/elf/parse_elf.c new file mode 100644 index 000000000000..decd65699858 --- /dev/null +++ b/tools/testing/selftests/arm/elf/parse_elf.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 ARM Limited + * + * Author : Dev Jain + * + * Parse elf header to confirm 32-bit process + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include + +/* The ELF file header. This appears at the start of every ELF file. */ + +struct elf_header { + unsigned char e_ident[16]; /* Magic number and other info */ + uint16_t e_type; /* Object file type */ + uint16_t e_machine; /* Architecture */ + uint32_t e_version; /* Object file version */ + uint64_t e_entry; /* Entry point virtual address */ + uint64_t e_phoff; /* Program header table file offset */ + uint64_t e_shoff; /* Section header table file offset */ + uint32_t e_flags; /* Processor-specific flags */ + uint16_t e_ehsize; /* ELF header size in bytes */ + uint16_t e_phentsize; /* Program header table entry size */ + uint16_t e_phnum; /* Program header table entry count */ + uint16_t e_shentsize; /* Section header table entry size */ + uint16_t e_shnum; /* Section header table entry count */ + uint16_t e_shstrndx; /* Section header string table index */ +}; + +static int read_elf_header(const char *elfFile) +{ + struct elf_header header; + FILE *file; + + file =3D fopen(elfFile, "r"); + if (file) { + + /* store header in struct */ + fread(&header, 1, sizeof(header), file); + fclose(file); + + /* sanity check: does it really follow ELF format */ + if (header.e_ident[0] =3D=3D 0x7f && + header.e_ident[1] =3D=3D 'E' && + header.e_ident[2] =3D=3D 'L' && + header.e_ident[3] =3D=3D 'F') { + if (header.e_ident[4] =3D=3D 0x01) + return 0; + return 1; + } + ksft_exit_fail_msg("Cannot parse /proc/self/exe\n"); + } + ksft_exit_fail_msg("Cannot open /proc/self/exe\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + const char *file_name; + + ksft_print_header(); + ksft_set_plan(1); + + file_name =3D "/proc/self/exe"; + ksft_test_result(read_elf_header(file_name) =3D=3D 0, "ELF is 32 bit\n"); + ksft_finished(); +} --=20 2.39.2 From nobody Mon Feb 9 05:52:58 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id AAEE215FCE5; Fri, 5 Apr 2024 08:50:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712307009; cv=none; b=KbonToAGYINBXgzLBEKl6rG5hzFiMUVXHf/UNXpddiBhrBwoL1WxQBDOc9TGidwxY90J6BWgyQ0XJQFCMmWFGBQXpCnGVD6doGWuXMxvrsGFcOyPjzj1qiNqpb7J5AAL2cnL0OUsonix5sDMWK29Dn5KeLEQFaiXDWH/sp9o9M0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712307009; c=relaxed/simple; bh=9XmSaTIPqe9Pt3FDDTmsRHsZ/7wIjsNeFBiZvnO0NS0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ejfReHN5dsx0wgCKAyMMWaQiJhQhyvEnz0tgGfBfBwnrwerIQ7qzoh5x7iHYN+xelMOnrNyEnEYslczwxR1nfKyYdAwlxniSHVQ/AvST4rdLBj8QjzFDyNzqH1daOLvo4MtBOm3Vrq70C1twtLIeGp8gCb4qQW2ksadpWfPn8dg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B34F5FEC; Fri, 5 Apr 2024 01:50:36 -0700 (PDT) Received: from e116581.blr.arm.com (e116581.arm.com [10.162.43.7]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id DB4553F64C; Fri, 5 Apr 2024 01:50:01 -0700 (PDT) From: Dev Jain To: shuah@kernel.org, linux-arm-kernel@lists.infradead.org Cc: linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Anshuman.Khandual@arm.com, suzuki.poulose@arm.com, ryan.roberts@arm.com, rob.herring@arm.com, Catalin.Marinas@arm.com, broonie@kernel.org, will@kernel.org, mark.rutland@arm.com, Dev Jain Subject: [PATCH 4/4] selftests: Add build infrastructure along with README Date: Fri, 5 Apr 2024 14:14:10 +0530 Message-Id: <20240405084410.256788-5-dev.jain@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240405084410.256788-1-dev.jain@arm.com> References: <20240405084410.256788-1-dev.jain@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add arm target, individual Makefile targets, and instructions to build the tests. Signed-off-by: Dev Jain --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/arm/Makefile | 57 +++++++++++++++++++++ tools/testing/selftests/arm/README | 31 +++++++++++ tools/testing/selftests/arm/elf/Makefile | 6 +++ tools/testing/selftests/arm/mm/Makefile | 6 +++ tools/testing/selftests/arm/signal/Makefile | 30 +++++++++++ 6 files changed, 131 insertions(+) create mode 100644 tools/testing/selftests/arm/Makefile create mode 100644 tools/testing/selftests/arm/README create mode 100644 tools/testing/selftests/arm/elf/Makefile create mode 100644 tools/testing/selftests/arm/mm/Makefile create mode 100644 tools/testing/selftests/arm/signal/Makefile diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Mak= efile index 15b6a111c3be..8478d94cda4c 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 TARGETS +=3D alsa TARGETS +=3D amd-pstate +TARGETS +=3D arm TARGETS +=3D arm64 TARGETS +=3D bpf TARGETS +=3D breakpoints diff --git a/tools/testing/selftests/arm/Makefile b/tools/testing/selftests= /arm/Makefile new file mode 100644 index 000000000000..039224bc006e --- /dev/null +++ b/tools/testing/selftests/arm/Makefile @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0 + +# When ARCH not overridden for crosscompiling, lookup machine +ARCH ?=3D $(shell uname -m 2>/dev/null || echo not) + +ifneq (,$(filter $(ARCH),aarch64 arm64 arm armv7l armv8l)) +ARM_SUBTARGETS ?=3D mm signal elf +else +ARM_SUBTARGETS :=3D +endif + +CFLAGS :=3D -Wall -O2 -g -static + +# A proper top_srcdir is needed by KSFT(lib.mk) +top_srcdir =3D $(realpath ../../../../) + +# Additional include paths needed by kselftest.h and local headers +CFLAGS +=3D -I$(top_srcdir)/tools/testing/selftests/ + +CFLAGS +=3D -I$(top_srcdir)/tools/include + +export CFLAGS +export top_srcdir + +all: + @for DIR in $(ARM_SUBTARGETS); do \ + BUILD_TARGET=3D$(OUTPUT)/$$DIR; \ + mkdir -p $$BUILD_TARGET; \ + make OUTPUT=3D$$BUILD_TARGET -C $$DIR $@; \ + done + +install: all + @for DIR in $(ARM_SUBTARGETS); do \ + BUILD_TARGET=3D$(OUTPUT)/$$DIR; \ + make OUTPUT=3D$$BUILD_TARGET -C $$DIR $@; \ + done + +run_tests: all + @for DIR in $(ARM_SUBTARGETS); do \ + BUILD_TARGET=3D$(OUTPUT)/$$DIR; \ + make OUTPUT=3D$$BUILD_TARGET -C $$DIR $@; \ + done + +# Avoid any output on non arm on emit_tests +emit_tests: + @for DIR in $(ARM_SUBTARGETS); do \ + BUILD_TARGET=3D$(OUTPUT)/$$DIR; \ + make OUTPUT=3D$$BUILD_TARGET -C $$DIR $@; \ + done + +clean: + @for DIR in $(ARM_SUBTARGETS); do \ + BUILD_TARGET=3D$(OUTPUT)/$$DIR; \ + make OUTPUT=3D$$BUILD_TARGET -C $$DIR $@; \ + done + +.PHONY: all clean install run_tests emit_tests diff --git a/tools/testing/selftests/arm/README b/tools/testing/selftests/a= rm/README new file mode 100644 index 000000000000..1a05c043d7ee --- /dev/null +++ b/tools/testing/selftests/arm/README @@ -0,0 +1,31 @@ +KSelfTest ARM +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +- This is a series of compatibility tests, wherein the source files are + built statically into a 32 bit ELF; they should pass on both 32 and 64 + bit kernels. They are not built or run but just skipped completely when + env-variable ARCH is found to be different than 'arm64' or 'arm' and + `uname -m` reports other than 'aarch64', 'armv7l' or 'armv8l'. + +- Please ensure that the test kernel is built with CONFIG_COMPAT enabled. + +- Holding true the above, ARM KSFT tests can be run within the KSelfTest + framework using standard Linux top-level-makefile targets. Please set + $(CROSS_COMPILE) to 'arm-linux-gnueabi-' or 'arm-linux-gnueabihf-'. + + $ make TARGETS=3Darm kselftest-clean + $ make $(CROSS_COMPILE) TARGETS=3Darm kselftest + + or + + $ make $(CROSS_COMPILE) -C tools/testing/selftests TARGETS=3Darm \ + INSTALL_PATH=3D install + + or, alternatively, only specific arm/ subtargets can be picked: + + $ make $(CROSS_COMPILE) -C tools/testing/selftests TARGETS=3Darm \ + ARM_SUBTARGETS=3D"signal" INSTALL_PATH=3D \ + install + + Further details on building and running KFST can be found in: + Documentation/dev-tools/kselftest.rst diff --git a/tools/testing/selftests/arm/elf/Makefile b/tools/testing/selft= ests/arm/elf/Makefile new file mode 100644 index 000000000000..86636fe02994 --- /dev/null +++ b/tools/testing/selftests/arm/elf/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024 ARM Limited + +TEST_GEN_PROGS :=3D parse_elf + +include ../../lib.mk diff --git a/tools/testing/selftests/arm/mm/Makefile b/tools/testing/selfte= sts/arm/mm/Makefile new file mode 100644 index 000000000000..d8bfa45df98c --- /dev/null +++ b/tools/testing/selftests/arm/mm/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024 ARM Limited + +TEST_GEN_PROGS :=3D compat_va + +include ../../lib.mk diff --git a/tools/testing/selftests/arm/signal/Makefile b/tools/testing/se= lftests/arm/signal/Makefile new file mode 100644 index 000000000000..3540a25de75a --- /dev/null +++ b/tools/testing/selftests/arm/signal/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024 ARM Limited + +# Additional include paths needed by kselftest.h and local headers +CFLAGS +=3D -D_GNU_SOURCE -std=3Dgnu99 -I. + +SRCS :=3D $(filter-out testcases/testcases.c,$(wildcard testcases/*.c)) +PROGS :=3D $(patsubst %.c,%,$(SRCS)) + +# Generated binaries to be installed by top KSFT script +TEST_GEN_PROGS :=3D $(notdir $(PROGS)) + +# Get Kernel headers installed and use them. + +# 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)/ + +# Common test-unit targets to build common-layout test-cases executables +# Needs secondary expansion to properly include the testcase c-file in pre= -reqs +COMMON_SOURCES :=3D test_signals.c test_signals_utils.c +COMMON_HEADERS :=3D test_signals.h test_signals_utils.h + +.SECONDEXPANSION: +$(PROGS): $$@.c ${COMMON_SOURCES} ${COMMON_HEADERS} + $(CC) $(CFLAGS) ${@}.c ${COMMON_SOURCES} -o $@ --=20 2.39.2