From patchwork Mon Oct 9 12:09:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13413536 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 78CEFE95A96 for ; Mon, 9 Oct 2023 12:14:45 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 1934F8D006F; Mon, 9 Oct 2023 08:14:45 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 11CAD8D0031; Mon, 9 Oct 2023 08:14:45 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id ED7D48D006F; Mon, 9 Oct 2023 08:14:44 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id D7CF28D0031 for ; Mon, 9 Oct 2023 08:14:44 -0400 (EDT) Received: from smtpin24.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 7737F1CA6FE for ; Mon, 9 Oct 2023 12:14:44 +0000 (UTC) X-FDA: 81325816488.24.70EBE6E Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by imf13.hostedemail.com (Postfix) with ESMTP id 422CA2001C for ; Mon, 9 Oct 2023 12:14:41 +0000 (UTC) Authentication-Results: imf13.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=DChGwy54; spf=pass (imf13.hostedemail.com: domain of broonie@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1696853682; 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=SDEc7N8Ns8h5PlAz3i1gZd1UGAiODw6RMzcnkleEN+YyeY7g4uakUekVo7fqq4O6NRTbSi T04XaFbsoXyTsWs2s44aWmc/7siD2LrVBvBLVgqKmGiB4/lWk4isdIoSyVFd4qMivW97FO NLO5doDzS23LRSzpE3d3+qwXVYehqio= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1696853682; a=rsa-sha256; cv=none; b=K9afrTIzHi3t0UMMe8nxC2L7tm+/yH2pUpMOaFCyup0BYEd6plwiQI120m4stoSuawuT3V x4hyDX8gEVU1mrrw/drXjDTr9mt4VaOC5hdQhSQNPjDDofmio3HJ1OzIuWuooTUGnwWZHJ fz8yygEWr4ub9o3KNKwo9ALYHx++7ZU= ARC-Authentication-Results: i=1; imf13.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=DChGwy54; spf=pass (imf13.hostedemail.com: domain of broonie@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=none) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by ams.source.kernel.org (Postfix) with ESMTP id BD90DB81145; Mon, 9 Oct 2023 12:14:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DD54FC433AD; Mon, 9 Oct 2023 12:14:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1696853680; bh=IP7maWyjZ0dh+q8gDfrxLaUB03tkGEoqGc+9eYXpRWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DChGwy54V0b4BgtZhNZZ9xJbzN3wvK2YneofZB502s8nrd72kcPpqodDzPMFkwyke UMS/n+rOcCVMoz3fuO03SemIkooC6X/bNtO0s+NAQZyz/J7Ee4gS0JmsQC5uB3FY3f yxxDNOhWSx/+OvjKL8pM69cgh4gBcgvY4PVOk8A9UelthnB2zd9Y0CCiJ+BrXwXipA +garoQcJrhJ1oR9+Mvil+mw4todBsnmbPzlspvN9frCFIgptIOfuonzgQW7Ye20ZBi +H6VwyywgTd3Z05TfLl73qYYQyEcwiBJSH3BjenUKkj2Y1wHOtcpRZ3hvOjIU/gxrs UnKsBZUAUGRiA== From: Mark Brown Date: Mon, 09 Oct 2023 13:09:09 +0100 Subject: [PATCH v6 35/38] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20231009-arm64-gcs-v6-35-78e55deaa4dd@kernel.org> References: <20231009-arm64-gcs-v6-0-78e55deaa4dd@kernel.org> In-Reply-To: <20231009-arm64-gcs-v6-0-78e55deaa4dd@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 , Florian Weimer , Christian Brauner , 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-0438c 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/pANAwAKASTWi3JdVIfQAcsmYgBlI+2taCv2B+2H7fAdfg/F+IO8oChQUTzeBbQPa77s M8VoqqCJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZSPtrQAKCRAk1otyXVSH0EwGB/ oCCnAxOJpgYrPdil/7YZ9YwnC8tbu788NatCLD1oX4LQH/N7wB8drf0c7WRg4IIRM9hIis7vXLuzpJ K/tL4XYk1GO8hGVOnKVEIo08DlCLaOUCvs8Q69oKBqRwlBPvKOg9qCwcRQkYEM3PTBAD+ew1J5RdkH QTiDurH8UhTMrjCnSEn9Fnb3jv2zruygol7bQeIvJ8u88erLOBl+ZhE8o0J8fHJ1ek8iCHDHqvFmSU wiXduHLy/IpBBJ+RWdnY3prQ8F3wdI7apKnB+imrMf712m0nyJaLWjICYW97ovu+uqkvUqF24+MFps cLG1kHg0az04GLQs4IqXp/saO/Tw1s X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Queue-Id: 422CA2001C X-Rspam-User: X-Rspamd-Server: rspam11 X-Stat-Signature: p7ojgetskyjkptppn7qupyuwtzydonac X-HE-Tag: 1696853681-144006 X-HE-Meta: U2FsdGVkX1+m+MKz4U3PbiSzj4tmMpCErkd4ZvpsOIyYm3vKJteABWFyHxkn0zEOyNzBxk9EVuTl4A9D/853xd7s2S+pMXE3S+JRDyL2hDrz8WlZcxJAdJ7DxKkrmk+lEK7GrieJELFghB85yyJ6m7444HFG2P+EcrOjOen3qCt0Z9tHY+rI2Z1mlo1rrD/vGowcny7673p3BvcPC4/xwlubfoF1VmvEtZW1poavi89Te0nZEa4g6N0ltm/ZgHSIyK0qEf211V1H0ubCR/WYxUOX5eGqhxh0e34FlJiJZCW50EO5TpUwOpEHsZRVQJT78HCGn0kJNO+Qp2PqZWvUrLmszOf/V/hMUZykCuWJkEwRWlcGxHsWznMeCLRMy5IyyaimXDkKj8a/yJUxsOEHrsMns5aMbL9im/bosh2CAUrV7BIwUFc0hx3u0N4CyFQfZkMyWsT4MGk/XxsKY1kBBrpgZNL6u3N03bHZOQz2sIaVNmNdiV8L3y7r8Cg94KOnqdUH/RW7LUqDgln2mkTLYi98S2AWPCICPRyB8NYDMtXexY3ktY2vtbrCW+7QAc0J2VeID/t55BGhr+yfujQssEXhV1JJd5thqgTvqMz3t1B86sYwN8eceDDrqYKbNeZpzogMyon9NDNTW8Z47uJ0S0twSoA77TpLysvIlKoe3WvqaYatUMn51xsM6GtkN9iywN06OSiN8wV9UZFpryDeLeRIvv2VNV99sduXasJMSRcPrMy7id75i8nrOdrRzKc3D1vBkn01xNItD683C6QctLdr3Vd+Q/qeLBT+eY++28BE3ViV/+C4vCfF0WCnbYiKCGwXM7AnPlxYzKal11Vnb0VZIHAJAFx0tprETvmWxijYeREp5Lk3M6U8LMXDD382Xsel7TmhckhtfIn91X6z3dPlaW2Ax+FfDnyNIl2hcsUNv2sU4gd6pfYrhofYQqwuaPWJlRPnYl/qoP6KDCj FwcvLnfd p7rCu7O3+v7hLjiE+//srLCZ3SPbig3LSXCdSLK6qQHJDoPVXjIgsugp75u1fSyVrwenGFLsLIIbbNFlzE3VYib4EnCljPHz+Jyf9YYFscHHw6N1FWeawI3H6ENk7UzwMkElMdBWVLWtcUsgEtofV2X6UCfXNYPUnbfkOh+zRy7ORBpbYnlyn46Hj8NRsqoBbC/SDYRWCv+l4MT7M96eqdLyIzhkKKVZG7z5PUhmNiEl/u3iG++6bAfxBaqkBbdt2tqmI6mmfg1Ek3BuKaVKAk6cFQVSCqygDgndEqnY35fdomRb2UNRYf1MNjyzym4z4+6+DsomayNX+WaI= 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); +}