From patchwork Tue Jun 25 14:58:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13711462 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 8F87EC2BBCA for ; Tue, 25 Jun 2024 15:05:12 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2EB1E6B00D1; Tue, 25 Jun 2024 11:05:06 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 29B6C6B00CF; Tue, 25 Jun 2024 11:05:06 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 04EC46B00D1; Tue, 25 Jun 2024 11:05:05 -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 D15076B00CF for ; Tue, 25 Jun 2024 11:05:05 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 88754C021B for ; Tue, 25 Jun 2024 15:05:05 +0000 (UTC) X-FDA: 82269733770.27.DD81224 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf02.hostedemail.com (Postfix) with ESMTP id A366D80019 for ; Tue, 25 Jun 2024 15:05:03 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=LScJejdD; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf02.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=1719327892; a=rsa-sha256; cv=none; b=toF8JMAKZoj34j1Aabn/3T9L90zIGEB0AqxxIvyhk/8iFaY8c3Sam8H+HygrjrEVuWqFnj 8OPIMTLpvXIeCNdjgGisSSgjsBbeA1XysHHr1pdE1WR4wjFPxyn41e0aY3uJa9XhdBrDh9 Xv7G8ES5xH0GBrgZv6Wip2pB3fyOliE= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=LScJejdD; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf02.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=1719327892; 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=Bpi3T4aK+vmHztAnT8u2ruTl4TnHDxuQIdmEf/RdaMr96vb7SGpAlTigHT6E+DZWnGy/je mPtA0aksrKXjVLDdglmeKyDU+tvBvzttP7z21oaVR9JV38c5CorOijDSNjfdWptXkkCSnX u+1Rc4/HZUAhEAIHxY499hzP5WHQ/g8= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id DA0E76148F; Tue, 25 Jun 2024 15:05:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D1B34C32781; Tue, 25 Jun 2024 15:04:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719327902; bh=/b4fLgBxrOG/LTGvqBDUXcUFQWiOWxSYArOHQoaOV+E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=LScJejdD0HsZ3gyagi0rdW5pplz2PKWUJe8IoFvycuuSj/u3cFyDLfPdQcf4w5Mqe xMchm+nA0c9Hmjw0cv5xcufOcwq8JmOTLGQ1lXNBFRcr7p2xHoQ1GRXrySBCYGIhA2 T7noj+uLdOOmmr5sThHzXr47H4CSzQb6NgS7IDMuWnhYwi9m95QA900m2yBpVACnfI 3GQ6h0HEJMfWStlzDzpr7XjONMjBvcfg4E3N1/slYYIPFAXpfHcpt534ymmVH5j5cG KFtuW0qou0XRhW9nea+YWGxrbueheQfTboHq2B8+IUsQLroPpJl74JHh9WEuqyRe86 NJcUOmfT8I77A== From: Mark Brown Date: Tue, 25 Jun 2024 15:58:04 +0100 Subject: [PATCH v9 36/39] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20240625-arm64-gcs-v9-36-0f634469b8f0@kernel.org> References: <20240625-arm64-gcs-v9-0-0f634469b8f0@kernel.org> In-Reply-To: <20240625-arm64-gcs-v9-0-0f634469b8f0@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 , 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.14-dev-d4707 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/pANAwAKASTWi3JdVIfQAcsmYgBmetuOwdGPwVGSgR7/GFysax2XSd4oP4cz4jyzMVOP q7a8LN+JATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZnrbjgAKCRAk1otyXVSH0NZNB/ wNusK30jfSyo+Ir8/SJNPOAXC/+46V8h9+O1cMCaLRq8wlD993ZX9/fPX5gTEn3cE355CTBHcrqkyk nDIpqx5lFgJNyhvm6uwlLVCRwTq6cD1VjktVqQZ96Oj6aUd/IzJGM2WNA7oOwENMLf3Wk7tSf3FEOW tDJHCw1FyhkcllPEx1DndTFFdxltVCvohXS6iHoK0OXQUV5/Y/LSO+kdWN331YgDKYonyN1nrmjDNa xRxn7uT6JUoE3p0xgIC1zQ6mdo1Fg9sGv7KyakStN1KEb7bHbyh/c9mCLwII095y0KFTehAzZ/Nu19 t202vqXMVu+OWT7r07rREuZLfyEABp X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Queue-Id: A366D80019 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: a1t3w5i9gbbg34wn7b7nc7s9ko75t6er X-HE-Tag: 1719327903-660243 X-HE-Meta: U2FsdGVkX1+udZ5G+SHSgni6NfSwUrJuSBjO2KrNwzfhibfatP2ATzCDsfVTZZUvqBXcy0XNlw8/Y3BzbMRgF0WNiWTFD+99I4qJQVikodaS4Zfj1kEfti844SHNEf7UE92fvW+GWCazXmzEDomYAZWjRBu9xnl4GBrUvkY/Y3+bUS3hBj+TMY/5+hMHOOh3UkTBJwy9KxOCYMfnVRVHZRFgZGXJfD91NIu9AdYCHGc4xn/OhcFO83GuI4g+Rt70RA6jWvlP55jswVwd2yLyMqDOSLfl1Uj72WnSq680cFFMv/Ah+fbcULlEeCdAwX+4toFl1me93uXYmFILBNilJbqGJEnZs4SH6vR4wKSmeXUWAjvbqQd+DHRYIpRxV2XgpnX02lcRg9dU5s3WUHdPifBET3M82hcPYgLdMrUCCuNWXuKyrcTLd8+OQcpkUxcJgj7yurB7id+ggGLQI/ockX9kv1b/k5rWvUz6p69fWqwoSYhiqtKR2wuucVH9bLYIG5wxYgaYN5LQSxZ6q5EACkMXtod3JLUYHttGxHJce41NeJ8w4GoZ4H131uAzmc7jmkqm9g1J0Je7KFqotVaM+vFjrpyF4tgnGL2qZIUko1cV2MyfO91jrCMuTX5w/eGIyISARCoYJd2rIYaps751U1gmyhuajSGylYfiDlRri4Ds6eVaswitbiejUOXo7FmjKHudNU2/ag0/zGWuv/XdtnVDhswlXXDqpi6/2MukIEPuTeLEvRKcmat9xtpt8l71w4OtEDIddITcNJUoQTHycsNkV+dX+GKdWWEXInrUAT6UdE4gW05k9IyCOwFHW0uC/UtMp8WuucOQZ8cQkI7hxQvQXhrY2FvGLj/X/3XeKAQaZCZIkRKpnTT/QZELGHvtCasCGAEYHeAgSTCReQt06f+FPeO/A+A3I6E28zSxtNF6V/dpR/JPtbPtuIltMFtuklHzEmyAY2ZshHin0V1 FsvCX7rS dkvaLJMPuddAWIwHOEsEV21YwK2pBnLiPN/NLmSc7IAyKP7aaNO2Xq2fqz7MO9b0UZm0MD+ETKeGNOxrGkr0395RGxV0N7unWWCFOgJc+CiErN1vsQVlbzZA61ebtq6lAwSL8Fw1bhdn2Xv1Qvi5Kfvkaia5iRPAbsPnUVKiBhGrVRF9Gk2E65sHdObhIhFZnpwcZUb5lNLEu/D0FxmkIywh3ZjipLZFhG0d4Z7f/D3Tpvjc28JCCPopNDPamV1240HHXjaKQb+oZ6HUl+HdE0JpbNJrwv/eVVXNyx//OjHBx9vWVzCRciZdOm5b33KTGtXcAGO8l1qNoP+Ut/01gplQ4D0u9eQy/Lm8QGSkAoxt7s3z6s8i8GAw9SRlM8KBWqSoM 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); +}