From patchwork Wed Aug 28 23:27:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13782197 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 B130EC7114C for ; Wed, 28 Aug 2024 23:32:52 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3E22F8D0003; Wed, 28 Aug 2024 19:32:52 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 392848D0001; Wed, 28 Aug 2024 19:32:52 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 1E5738D0003; Wed, 28 Aug 2024 19:32:52 -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 F2FBE8D0001 for ; Wed, 28 Aug 2024 19:32:51 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id B60681A08A5 for ; Wed, 28 Aug 2024 23:32:51 +0000 (UTC) X-FDA: 82503256542.27.948B72F Received: from nyc.source.kernel.org (nyc.source.kernel.org [147.75.193.91]) by imf06.hostedemail.com (Postfix) with ESMTP id 04431180008 for ; Wed, 28 Aug 2024 23:32:49 +0000 (UTC) Authentication-Results: imf06.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=B8sQUJUd; spf=pass (imf06.hostedemail.com: domain of broonie@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1724887852; 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=qeTei2+Rv9TmGzFj/jgAMv84+i3cbC0I/TqETm/VMk4=; b=Y7sSK+SSNszPa7DO+ldRkutZKwmhzzBUEr7Om0LCm/nnFGxXY++bK89Mq4aiqzRpfv/aZP LzavdMSquI95sMFjR+W7i7ojwx4hLtB6WBOVSbvUoK4h6cdRKr/GmAl74BsScmZPdZaakR qL85droxwXeonyE9Vit+Uvfl3Z3+yyY= ARC-Authentication-Results: i=1; imf06.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=B8sQUJUd; spf=pass (imf06.hostedemail.com: domain of broonie@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1724887852; a=rsa-sha256; cv=none; b=g24W1uLF5F9M2Wn4ojYDrI2Yxcupvju1SAHg2QfRzjJfaCKXlk2w5pxQmkYjS5Nqbcq3Xg gcoXTivUQ7c8HpYkVUGY27gOUsQUn36DkuYs8ACvXMND3ZaYr6yjY3YcSj6h6hvvqIDrRj JHX2KjCzTNucrmV3qMGC7dJlS7JxagE= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id 5CCBEA43770; Wed, 28 Aug 2024 23:32:42 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5FB1AC4CECA; Wed, 28 Aug 2024 23:32:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1724887969; bh=/b4fLgBxrOG/LTGvqBDUXcUFQWiOWxSYArOHQoaOV+E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=B8sQUJUdJrIq3kDN7sUh3HHu0mhJ4Jd+UrRgHYpWc27Eed9Nh0hMsK9hSUY7W2vHy 1r/+Y1gJyV64pvptv1GSFq3NRHVO40J5KTaGFi6BODVolyQ3xt/bFoDyo3bBS2iEP5 zqldseG7AMiZSM0nqm5M73VBv91Zy5W9kAOphbTsAK85NmjicWVlNNdyqZiyGbpuSq RMMmnBBi6nbbWOxJ3Q7iumoHiKOxoQlk1CNAXtlDYT834bgE3i4Bos6WTLhIg5knkb kmbTkM36wW3DPbGuE1vb/rtaqTYYAuqTpcKDxDc7Y0knAul81SjC4O+ML7w7UeDhka EYW6WtESbPUKQ== From: Mark Brown Date: Thu, 29 Aug 2024 00:27:51 +0100 Subject: [PATCH v12 35/39] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20240829-arm64-gcs-v12-35-42fec947436a@kernel.org> References: <20240829-arm64-gcs-v12-0-42fec947436a@kernel.org> In-Reply-To: <20240829-arm64-gcs-v12-0-42fec947436a@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 , Shuah Khan , "Rick P. Edgecombe" , Deepak Gupta , Ard Biesheuvel , Szabolcs Nagy , Kees Cook Cc: "H.J. Lu" , Paul Walmsley , Palmer Dabbelt , Albert Ou , Florian Weimer , Christian Brauner , Thiago Jung Bauermann , Ross Burton , Yury Khrustalev , Wilco Dijkstra , 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.15-dev-37811 X-Developer-Signature: v=1; a=openpgp-sha256; l=7382; i=broonie@kernel.org; h=from:subject:message-id; bh=/b4fLgBxrOG/LTGvqBDUXcUFQWiOWxSYArOHQoaOV+E=; b=owEBbQGS/pANAwAKASTWi3JdVIfQAcsmYgBmz7KTTBzejW12XGn0R8A/TgK+9iUS5Ghlf3XF2oy1 1adAtFeJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZs+ykwAKCRAk1otyXVSH0JJsB/ 0eM7WVMsUO+EFuPZkhQZskgNdND4fyOirkCOfMx+RFthoSK5U58rOgDeQQOWc+Zf6zTSltu90zvySL t+c3PWaUjfuFq/K8K4iH0y+nLkkPWEykIuJI4Dq0zq0fV9IPwOrnm5b4bvsIk7/torxDwqE2rowOKz FSv1uHI8g127V3cNTZuORqXY+4IOZiKJwnqHhkN8K76Pogl9D1En4SfJwZlgPNOjHWasevIr0xVQBj H+KeqtPacUHlBUREYmsaOb5n6MN8UGUDRavtrSETeuaPjhvi7EjUD4fqg3zErL8hdsfj/OkF/rMDaH 7FUyA5Y9hSsggEtuli7QAylvK1ug2G X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 04431180008 X-Stat-Signature: zw1fb8fznxocuidpzctqop4whpyhcxoc X-Rspam-User: X-HE-Tag: 1724887969-515980 X-HE-Meta: U2FsdGVkX1/GgyRs95AT5HxV1CpDV0dTZR3DapxMRDly8UmQIVGDDmgyYlvRwcgzFg78rMrtiUmqX6qGgmRH1pkpWWlO7Jn2O3EF22pgwB3L1VdsLrpoT6/Z1y1c8JUoEDlL+GbGn9LAXNBxeIMtcStKXg3ugBc1k6O9ZLApiuFlM3JxWIGsdx7YAwQBmMGgbhsga4OgXWk6PI+OM8KjgRqxIXGhWspdyg1TAClyQQ+9jiY38FTp4WT77UGY0lUl7rQuQxYHG0GeHDKSHL3nxgyyZ1f7/HsYkofesEl3YY1bgr7QUf2WunPliS00EFR/m/YR8KnhvkqFyWxSrHP4Jp+gYcKViF9imNav2eCYL2zzIkgKAfvOE7FW39ZR++3+VB29SBaMQZxTCqDT2Bm5KJiX2f9kndqXtZ+JhDrR99/Ql81EzYwnUQarm0ugRAvMqWIH/CruIuumhM9k+w1JCo9LqWH+8wsOJXnoLd0TB6pOU1/rZ4kli6LbtRzDKlApbmt9K8U+2rBH0novTbHzI5ngotfNShHRduWSr8A/zGWWBK1eNuz4prUkJZaJ1JRdL8b/QXo4tsf08q9tQ97RARwpzeGmp7a4tFxy3feOTzRc9uu26EQhExPXrwX6gk5/VjzoDxNQI+JxWNHPW2cymJlxNbOh+8KIKoBWZiYIt2My+AZ928KEQua1Wsbhj5jsIluUQYsOTnkUrXLp2L1hfFpzSmdCbx6SSVbyi+aRCSGp84T1VrGSwaqYSdENEOQbWY9PwdbJT0oRdEYtYP4Hni+IdIRwplgGvmVQyIcfEtGOfpCkKcb07GmD8iAU5WPj2CQHwdtiiMsrlu3MVvAbyDzLSlxlnzi7/0E2S4HwJfx2T+adfGXiItIi2Cv+YiWWi0fszgYAUwF88TuPumBB2lpukVEoylocVMxGabVwq2QofWC5foM6xMg+kWHJu4ua6+ELo5RnA1kdfxCzi/S /HfkiWYw y0Cw4/o5ueimLHFtWANO8CkhgO8Ia+g5T0fKzoq2v08JKqStjGR56kjBTG5TA2FN9kdCj+s3TsLPNSMa1HNUKWWF0DnBIfnJjU+EVaR/vMQdHvsmRv7bXJGRUwd3ga2DpNJPFgyK3ZLH3xmBdjqcb22W3AazB9Le97kSGEtmo0KLyZ//h4r6LdcXKjCNXkfFKaDd0uAD+F7NJwTK1wzLrxm389nN1YQpDJPuj4sWv0rQQMC8K7ukxNm91uDJVzTzAwLByzJPyVpv4QJ8saXaJ6CTdJrphNduN75uGGRF1EI8RXjE28VgAW75g57zg58SIvW+9B0HruXBdbKmTYzmW1V8AudKX6+euGMidx5vS9ivY9pc5/Zr8gT34ShyRiu8r2Msz8uED8wfAhViodVmdhX5Kh6xcL7qEPNcj 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: List-Subscribe: List-Unsubscribe: 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. Reviewed-by: Thiago Jung Bauermann 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); +}