From patchwork Mon Jul 31 13:43:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13334755 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 BBEB1C001DE for ; Mon, 31 Jul 2023 13:54:20 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5C1A4280061; Mon, 31 Jul 2023 09:54:20 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5722B280023; Mon, 31 Jul 2023 09:54:20 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 41375280061; Mon, 31 Jul 2023 09:54:20 -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 32C38280023 for ; Mon, 31 Jul 2023 09:54:20 -0400 (EDT) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id F247140BF1 for ; Mon, 31 Jul 2023 13:54:19 +0000 (UTC) X-FDA: 81072051438.06.23F4880 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf29.hostedemail.com (Postfix) with ESMTP id 92D4812000E for ; Mon, 31 Jul 2023 13:54:17 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=RMXweSck; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf29.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=1690811657; 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=XJbY1bFU7w0cPaQF6eYkdTRefgro7AfSI1KvzwfLPNE=; b=Us6e2hZ7G2zRPoMQVW/N26gwXcGEzpyAG0qfXWc4M8UWQWs4NLaM+2Gd1i6IGPisAxTuBF g/M/RuOkPoeTeQOn7tyz5J4KpPPyKLjTHvHcOqj71Hs0rcE6NyE2ZjjZ+K576HLU93u8qn YPdqCZxJz0dCL4q6kudAXpgAqxvDVCs= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=RMXweSck; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf29.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=1690811657; a=rsa-sha256; cv=none; b=aafde4ol2HCCGzBF9Y3eZ49AVVasRuuZbl9sysLQwTlNG9UxTb/THBKoOJJNFvpiEC2aKQ V0ARsSul5ARHDe+Y1/5kd4ZpX/LAoB9IaluvWJMj/997Twaf/mjCU+DRLDoLyoNs+YBL1c ZJUkLxsVxxwM0kiX8aPktGaTOnlQdMo= 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 CDE5561158; Mon, 31 Jul 2023 13:54:16 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BF9AAC433C8; Mon, 31 Jul 2023 13:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1690811656; bh=h9bKdgMYA3yorcV7MRrWgctU4KZ0wYlnm+mQUdEZpv0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RMXweSckzauEJRb840x4AR0huO5H7yfavmLxKVXMyd0CAFl7cpebVFEWGwuAXaky1 lJaIksXE4fig6jEP66n3SV/fg1xV3dTuYVk5H56hVYGiHgatUOHCaiZHkyiyE6q0Ss t1kkRXARrsD+tLy23IYMwBdqAdz5BeWeailItHkX783fxwjhWROjumQbUtu8o+3BK7 /CCF7w9PcE/CKDVSIkF2i8rvzhxzG8msvISWclRugUmc8j73wfuvFDhNHb7rMuWklM fKd2AL/JE7wngUbzXuTt4vqri66yQK7n280kXCUA53H71dEV/0TvepbgPDHUdc776x ylgsQzqHK1CrA== From: Mark Brown Date: Mon, 31 Jul 2023 14:43:42 +0100 Subject: [PATCH v3 33/36] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20230731-arm64-gcs-v3-33-cddf9f980d98@kernel.org> References: <20230731-arm64-gcs-v3-0-cddf9f980d98@kernel.org> In-Reply-To: <20230731-arm64-gcs-v3-0-cddf9f980d98@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-099c9 X-Developer-Signature: v=1; a=openpgp-sha256; l=7316; i=broonie@kernel.org; h=from:subject:message-id; bh=h9bKdgMYA3yorcV7MRrWgctU4KZ0wYlnm+mQUdEZpv0=; b=owEBbQGS/pANAwAKASTWi3JdVIfQAcsmYgBkx7wu00InVhHIHLEqB+nwnxI5YpOf/1mGfldLVoai 0tbFyUqJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZMe8LgAKCRAk1otyXVSH0OElB/ 9LnvPQwszI1MaevBl4Tn7mQ072S0+MxAgoweAbOg5GV6xMyIMVxPyAc4DBgVRO9zaMOxjjs71zeXtG X6U9f52BKVDC0eUjSZPDmUzTZXkldN+FSsJ73HIJgn9Zm+3uKg1405ELAchNX7h5EXuuhiaHn64vh5 B0P3JGaNUEM3aJoj7GXZnBzgKu/1c3tz/KsmZWAQDahhlk/IgtAyMexjfoJql+rdLUE2TejZlwtHLH 1zgVP0O9964VGMx0OM/d3nFpGYp9w10RIwjSIBK8hOGtwiYG36rWaeK7RU0IvnSd3ZLHn/cXLJU823 J2zx0JCRxTUoc7b+fo73olJGThBaDG X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Queue-Id: 92D4812000E X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: bgey9edrtdqa4hbssz1w4ztqf8846jpo X-HE-Tag: 1690811657-683442 X-HE-Meta: U2FsdGVkX19Z6BYS/B5z8diJMAWf7ZIc3bltUP3wRSpI7nDz/+kyeI+DFNaTy2zCJRQISLRfgGa7iAbfT7b3D9EvsMi4+OsgtI78nmlotAeDg2bgVGSDfYxwlU4bGNjDCYg744X7LAuAouPMH9+UkmXyMuq2Li60g+PAHVRpk7+cZ4fnSm2HeWXD1AqzYGzDhw2d0KWprszrXnUNfvGWb1ezVIXM89LrTg5LCYgUOLT1WiHtsJJM/k7pCI7ULpq4B96uhBSenciEpFElC0j6BBs2nTMeAgHBNrzaXGOtUpTi5a1JEuRC1iHwT+17wYFpdpZAh2swnzO+tGqZIizzjwHcyXvnhvheRtITGWGQrQ1SbraH+rz5NT94+EmKw4xwgHxRsefLEY4WV3AoljZgl7f6Nrzo+cZg5Ag5S/txEqEr2t+4y648yb8Po+CzCasPDZFWsc5m0IybJAQyo2cH/1BaS1O1SgPDEZR6UIUUF2objRmBX6SvJRt54Q4LwOhkt1VYOBXBBY/TydMJFqLLiSX2pPftODGpZRXdJYJb8a+82wYMRxDoujVjWOI/+EKzjGuu216MlWvQG0dvVjLD2bCVwWfeNjfS8is3EmK1r26yCnxE3A7emYryr4nzrxlTI9PW9IVCc/isKTy3e8KrLE42r53kt7NEG6+RkplNcrDFnnu0JJ7k3UK083omgaFuRQBbjBlA0A+QxU962Sf1cL8/iV/47bX05E9h+Zpmp4/pfmgnq2JQj9KWpHm7AMpSYLbUCaNGyEl8h9WSRIthqLNxFfLCC3gO3UCYMwo3tCGu9QXwMfOxHKB/m6m1Me3doHfBfgeY1y9gnDCCRnAaSpOMN6rxUsbGZ40KCaTf6fnrdlXLaNjLfxw1VeXqWcuXpZ88HaBpRfpUEnVQeLIgMe9VfY5YEkaOJESRVgnX2E+rInDIpQlTcDaGPswdNpHlFQIaGCL79Sq7UhyV/JN X9vMa4aT c97iVBNj4iM3KDps2qbjOUFnGYqz6qRzy6HW/SH2Tqjn9uTHVr8OZdEuZ3K1ifUSit+roayXkTq0BEHnGaA6gwqnAuzCFLrZumh4rUNB8wruNKFYAqELXx3xYsTxbpqxC4KQe/48jAgr6KpiFNpH6x0jVQ0E9YPioRcZvuQdT3vurf2WweO6N6gCAAPKCT1mSyHGvpTraUblqHSVnIEXkeRcQCvEagfsZ4gvHRqaC8CBrHJW3A+yPfO2YQZh27h3nzaG6VovIuy5nhLyNqZqdF0zA9vRen4jYXqwzZSScJ/O3HjFfIhSBzdCrPeKe4z83prQJtkhcCkxJ/9RYVcmOpBj8d6icwrgoHq04pVPDJ4U2VyfqiHMOuJx5Ls0EQXvkSuMiRJDVO44nEQhufMni3K7Bfx8zKWodt7b4OtTX33w/bEw= 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 31fbd3a6bf27..340c6cca6cc9 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); +}