From patchwork Mon Aug 7 22:00:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13345155 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10F41C04A94 for ; Mon, 7 Aug 2023 22:05:02 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 9BAD88D000C; Mon, 7 Aug 2023 18:05:01 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 990938D0001; Mon, 7 Aug 2023 18:05:01 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7E3FD8D000C; Mon, 7 Aug 2023 18:05:01 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 6D6DB8D0001 for ; Mon, 7 Aug 2023 18:05:01 -0400 (EDT) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 49BC940C11 for ; Mon, 7 Aug 2023 22:05:01 +0000 (UTC) X-FDA: 81098689602.18.3223072 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf24.hostedemail.com (Postfix) with ESMTP id 6DD2D180013 for ; Mon, 7 Aug 2023 22:04:59 +0000 (UTC) Authentication-Results: imf24.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=Viub0+3Y; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf24.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=broonie@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1691445899; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=wVIQOatPna0iFL3WRNbrJxMJgExIxYsZk6uwuE1VaNI=; b=N0Eshm+KijAACKqEMXqcmXiJbrXdrasPgkWFFL2JbsygnKAvxj3uO3k+ct8Sl4DjRovfhy Yk+w2F6vVqdHXcHZRoSrgti1TI8sYFrznwmdUSoXsgAQZQu9TpfaHLVC9Mz0XEfkS9EIKP AnRj1oN1uM2qERHUnGuyfpUjppjAqgQ= ARC-Authentication-Results: i=1; imf24.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=Viub0+3Y; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf24.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=broonie@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1691445899; a=rsa-sha256; cv=none; b=qpgb3aPov8z6gYpOGi6Mh5jAqwM4LbGixe71pQhL81E4aDH7MFbAjG6V0OKRtS2nFu7X3m BZJu56TWKEudLFx3lMdPF4cpGLumNFcBhoHkfM2JojT2hyHeldfsQrocIYavVfCF9A7py5 /irirBOJvdFuqmN4/03pYfk1opJJoKM= Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 9CF8E622B7; Mon, 7 Aug 2023 22:04:58 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4CE5BC433C7; Mon, 7 Aug 2023 22:04:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1691445898; bh=IP7maWyjZ0dh+q8gDfrxLaUB03tkGEoqGc+9eYXpRWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Viub0+3YDdK96RLbvcjS48dbEXvfC5pa4QoAORz0LyXsMAVUG/1zaxs0PxUrdcUiX NCjOXJfXYjXr7amwGBUMbzpr8BvJe8lFacFAe06AYCVERrNDx7zI7VRwwVD4bawlQP M48sWzBfrzWqs6MZ9Yz1mcHhXzt3SMHVxRFWzw3TEti5LfaPhFR4NsrYaM6gQbu++o YFxFB9SJvBeQWMPrswz++R27gWk7HgZren2w97TDPZV4RcOee5zEku1tkCjqiiBjwd lOnDaqcdOwmP/h1UVDDEfNdlYZ37MfXEHJafRMBUOkibjZYhZF3TgsMnZL62xzgI3X GRm7UXieTEefw== From: Mark Brown Date: Mon, 07 Aug 2023 23:00:38 +0100 Subject: [PATCH v4 33/36] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20230807-arm64-gcs-v4-33-68cfa37f9069@kernel.org> References: <20230807-arm64-gcs-v4-0-68cfa37f9069@kernel.org> In-Reply-To: <20230807-arm64-gcs-v4-0-68cfa37f9069@kernel.org> To: Catalin Marinas , Will Deacon , Jonathan Corbet , Andrew Morton , Marc Zyngier , Oliver Upton , James Morse , Suzuki K Poulose , Arnd Bergmann , Oleg Nesterov , Eric Biederman , Kees Cook , Shuah Khan , "Rick P. Edgecombe" , Deepak Gupta , Ard Biesheuvel , Szabolcs Nagy Cc: "H.J. Lu" , Paul Walmsley , Palmer Dabbelt , Albert Ou , linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, kvmarm@lists.linux.dev, linux-fsdevel@vger.kernel.org, linux-arch@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org, Mark Brown X-Mailer: b4 0.13-dev-034f2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7316; i=broonie@kernel.org; h=from:subject:message-id; bh=IP7maWyjZ0dh+q8gDfrxLaUB03tkGEoqGc+9eYXpRWY=; b=owEBbQGS/pANAwAKASTWi3JdVIfQAcsmYgBk0Wmy833RI05pBQJNTz7t1U3vX5cr4i3ZM+8P5Xms Y5DjP0qJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZNFpsgAKCRAk1otyXVSH0FcMB/ 43hvcuUQh5Evd2eYzgjYV0lbil23x9rREejqSJUUALiEoOFErGVQ6fa6WHJEJAj1dId34JBlPbxfhk GFdJtCNFxXrQ0Y7EoCyP0Xfto4Ej2fanrsOxMzOTXMQVF1I3G0i/4ZE4wJg0QzWZ80s2wOy8M2zYtR sSQS52tRAwNx86hra9QGVZ8Cngx47vZXC6sNyeKRP5sn9ulHNtOfMxt68VPkpoVep13UNJVcZbpF31 BdgSWDEH+K/Bg3z6asIFWnV9C3i2Y60ONLoOVBu00A673IoDdp7ygVa4bTiWzyfRRWUYxM9BzoSdtm bhZVw8/PeXFKs8u3ehyXx3aAPzorvW X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Server: rspam09 X-Rspamd-Queue-Id: 6DD2D180013 X-Stat-Signature: sng4pwhghz5fcx7emsbj81zbanx513xh X-Rspam-User: X-HE-Tag: 1691445899-838045 X-HE-Meta: U2FsdGVkX18l5O85pDDOejyg8wX9qYbAGlM8vgAdnip/t48sOKIdwrwndkrA9A+cxtcT9ZJ3XMJUTRDFo8RRJOZgAPtLe5vlXWUFvd0TiBYe5eO0jRIDEUqkQtBcLOPsGjF1Xti22DAMDdojcjHmKZCS55jkj7Nz9QBvYyjRvXkEzrXb8+8Sk+5zQ8+0sNZcP+823EepOemZbWjafpfCe5SmEovP3RXcL+fC5MeY9n/WKOBNylkwi1L4RLQk3dJxP4GTT0pFzeeZGx7PqRERlgRUGm8upX3ubKjqoGjtlnnh6Zc+d3HcVKTD3WP0LvUmo7ClyO+ZaRsJyiI04XYltui77obGYUTkE/ybpSXXSm0ex1Gq9Jr9aaia0ufuEA9EXqBoteW1z9TkJEmK1SesMaA97iPuAStVjvRj5y/U7VneoMqhfrYfkp2bxK+J2DIg/oXVl8Uo53J89O+r6RtJwRRn3hZ3Hpm0TDSfRxRuX9oxmbYpB1VsBWTgVZrUIzLM94GFf/d5tUUqhzNqmhoZtLrHmvrdsaLT88K4ASOqbL8I9uMyBoNO43qk1IpRM5VWOP24QfjZjuJv+O1CNLUQFS2eJFrPxT6OdjQz7MQLWeekUmUkpwbdEADvjy7xEv86MDd0D2xa3tFo7mb0tXHnOUZK9Rka5ZqeoE5/1335wpl5TBmmbvKlric6fS4WmhUrU3zJkRmfJcnW8QWZNRpnj+Es2tY05ysOTKl91fmVn/wQNspLpPao5bqUgn9nrIxi26JJxGuYrjsgfht6vcrqh5WPY1//Z0JfhXH8qk4AWK4THkyk1yh7wd3QnL5XKR/g3Ama583daczq64xj9VgzrEdvqQYRdt3zt8hJMUsrol4UNmhLj/r2Q9CYriOIYp5pRhwzqzeDvvQtdyBvaZUXz74hc0IJAxAVJyaRTSeq78yuVFBEN7Dkq/JqsLK6d6KXALfJ1dTzG/oykvlSc6F fK4N27yA /z0e2N2FpHbkF7giNeigdTzzwrOi9rsvzhz4a4p9SKZyL+NqfPUH3XTxS86gZdQgOl/bl/Su39x94FamdizUepPgLyjSs4KShBU4/iND/pjfd9r2MZ+ElbQSG9I9X8Ojj2oEVldL4b7wFPuUAAOtchneMxjZxwewkNzk+wyi1OZ7gp2acOcxRQVqTYboEWq+7AWWURJ8Dy/H1DpiKl+WVooJTJt5c1bFNqY2cuSP9Nx+EEyt8CMptIKXvq/1fyoHgiQtkZM0zUneLYyz0ZX7qYrB5BEO484iqT11qjQrPPFnPtoPqQFwOsI0MzklsU77/XVwiZHwG6C6V0s6AKDcIGr6Eda5VaNjYXPQXA1m8MZmIbw0o7yrw6aekd7mfa3j3n9a5R/InfWfIS+NRz1occaYGIB4E48VasoBlW4csP4DsOzQ= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Verify that we can lock individual GCS mode bits, that other modes aren't affected and as a side effect also that every combination of modes can be enabled. Normally the inability to reenable GCS after disabling it would be an issue with testing but fortunately the kselftest_harness runs each test within a fork()ed child. This can be inconvenient for some kinds of testing but here it means that each test is in a separate thread and therefore won't be affected by other tests in the suite. Once we get toolchains with support for enabling GCS by default we will need to take care to not do that in the build system but there are no such toolchains yet so it is not yet an issue. Signed-off-by: Mark Brown --- tools/testing/selftests/arm64/gcs/.gitignore | 1 + tools/testing/selftests/arm64/gcs/Makefile | 2 +- tools/testing/selftests/arm64/gcs/gcs-locking.c | 200 ++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/arm64/gcs/.gitignore b/tools/testing/selftests/arm64/gcs/.gitignore index 5810c4a163d4..0c86f53f68ad 100644 --- a/tools/testing/selftests/arm64/gcs/.gitignore +++ b/tools/testing/selftests/arm64/gcs/.gitignore @@ -1,2 +1,3 @@ basic-gcs libc-gcs +gcs-locking diff --git a/tools/testing/selftests/arm64/gcs/Makefile b/tools/testing/selftests/arm64/gcs/Makefile index a8fdf21e9a47..2173d6275956 100644 --- a/tools/testing/selftests/arm64/gcs/Makefile +++ b/tools/testing/selftests/arm64/gcs/Makefile @@ -6,7 +6,7 @@ # nolibc. # -TEST_GEN_PROGS := basic-gcs libc-gcs +TEST_GEN_PROGS := basic-gcs libc-gcs gcs-locking LDLIBS+=-lpthread diff --git a/tools/testing/selftests/arm64/gcs/gcs-locking.c b/tools/testing/selftests/arm64/gcs/gcs-locking.c new file mode 100644 index 000000000000..f6a73254317e --- /dev/null +++ b/tools/testing/selftests/arm64/gcs/gcs-locking.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 ARM Limited. + * + * Tests for GCS mode locking. These tests rely on both having GCS + * unconfigured on entry and on the kselftest harness running each + * test in a fork()ed process which will have it's own mode. + */ + +#include + +#include +#include + +#include + +#include "kselftest_harness.h" + +#include "gcs-util.h" + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("x8") = (num); \ + register long _arg1 __asm__ ("x0") = (long)(arg1); \ + register long _arg2 __asm__ ("x1") = (long)(arg2); \ + register long _arg3 __asm__ ("x2") = 0; \ + register long _arg4 __asm__ ("x3") = 0; \ + register long _arg5 __asm__ ("x4") = 0; \ + \ + __asm__ volatile ( \ + "svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), \ + "r"(_arg3), "r"(_arg4), \ + "r"(_arg5), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +/* No mode bits are rejected for locking */ +TEST(lock_all_modes) +{ + int ret; + + ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, ULONG_MAX, 0, 0, 0); + ASSERT_EQ(ret, 0); +} + +FIXTURE(valid_modes) +{ +}; + +FIXTURE_VARIANT(valid_modes) +{ + unsigned long mode; +}; + +FIXTURE_VARIANT_ADD(valid_modes, enable) +{ + .mode = PR_SHADOW_STACK_ENABLE, +}; + +FIXTURE_VARIANT_ADD(valid_modes, enable_write) +{ + .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE, +}; + +FIXTURE_VARIANT_ADD(valid_modes, enable_push) +{ + .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH, +}; + +FIXTURE_VARIANT_ADD(valid_modes, enable_write_push) +{ + .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | + PR_SHADOW_STACK_PUSH, +}; + +FIXTURE_SETUP(valid_modes) +{ +} + +FIXTURE_TEARDOWN(valid_modes) +{ +} + +/* We can set the mode at all */ +TEST_F(valid_modes, set) +{ + int ret; + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + variant->mode); + ASSERT_EQ(ret, 0); + + _exit(0); +} + +/* Enabling, locking then disabling is rejected */ +TEST_F(valid_modes, enable_lock_disable) +{ + unsigned long mode; + int ret; + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + variant->mode); + ASSERT_EQ(ret, 0); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + ASSERT_EQ(mode, variant->mode); + + ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0); + ASSERT_EQ(ret, -EBUSY); + + _exit(0); +} + +/* Locking then enabling is rejected */ +TEST_F(valid_modes, lock_enable) +{ + unsigned long mode; + int ret; + + ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + variant->mode); + ASSERT_EQ(ret, -EBUSY); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + ASSERT_EQ(mode, 0); + + _exit(0); +} + +/* Locking then changing other modes is fine */ +TEST_F(valid_modes, lock_enable_disable_others) +{ + unsigned long mode; + int ret; + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + variant->mode); + ASSERT_EQ(ret, 0); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + ASSERT_EQ(mode, variant->mode); + + ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + PR_SHADOW_STACK_ALL_MODES); + ASSERT_EQ(ret, 0); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + ASSERT_EQ(mode, PR_SHADOW_STACK_ALL_MODES); + + + ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, + variant->mode); + ASSERT_EQ(ret, 0); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + ASSERT_EQ(ret, 0); + ASSERT_EQ(mode, variant->mode); + + _exit(0); +} + +int main(int argc, char **argv) +{ + unsigned long mode; + int ret; + + if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS)) + ksft_exit_skip("SKIP GCS not supported\n"); + + ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + if (ret) { + ksft_print_msg("Failed to read GCS state: %d\n", ret); + return EXIT_FAILURE; + } + + if (mode & PR_SHADOW_STACK_ENABLE) { + ksft_print_msg("GCS was enabled, test unsupported\n"); + return KSFT_SKIP; + } + + return test_harness_run(argc, argv); +}