From patchwork Thu Aug 1 12:07:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13750416 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 F10C1C3DA64 for ; Thu, 1 Aug 2024 13:01:41 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id F116E6B00D5; Thu, 1 Aug 2024 09:01:37 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id E997E6B00D7; Thu, 1 Aug 2024 09:01:37 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id D3A746B00D8; Thu, 1 Aug 2024 09:01:37 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id B009B6B00D5 for ; Thu, 1 Aug 2024 09:01:37 -0400 (EDT) Received: from smtpin28.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 48BE2A7796 for ; Thu, 1 Aug 2024 13:01:37 +0000 (UTC) X-FDA: 82403688234.28.64078CC Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf11.hostedemail.com (Postfix) with ESMTP id 08EBF40043 for ; Thu, 1 Aug 2024 13:01:34 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=TRZMtadn; spf=pass (imf11.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 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=1722517289; 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=KkEkDkri0bO70mdGX9dZRnmVQuI77dzdQdtc0ZdcvJZVnqWypprVlsYGBLRE8Nj9AO5xw+ z4ru0CIYoI6mglL1CODvSO6LYCkD+GiPXbANWjZinGBSfpbgjtHDMvlcve4odf12zqZjNI q4iluQZ2Hr1AaCaSg1CF/iFTd4EqUI8= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=TRZMtadn; spf=pass (imf11.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1722517289; a=rsa-sha256; cv=none; b=WagTcOswu7WeSDtXDTVltmIA+8Ni9NwUEU4X3jsKMWo/WYQGGea1UzMkGoem3/s69RD889 d8qsvLVVGCbTFIEFBG/dlCRoY3ehxZ45+YyowQm0WLY60xAChJ0uVIiaOXRDp2qHhdNhOB xkuyLx95t18D3WxPtSV/ozSLidvTSKY= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 09CC162862; Thu, 1 Aug 2024 13:01:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D11CC4AF16; Thu, 1 Aug 2024 13:01:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722517293; bh=/b4fLgBxrOG/LTGvqBDUXcUFQWiOWxSYArOHQoaOV+E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=TRZMtadndFAu91GtDPbe4hs8r0BhRJ1xXnKfpX3TNlmP1OMNvhjnmqGpuLOFiIt0l YioayN2cPoiE12vzJ4GIZptBIWXuUff6UPAGEgtxd/IjWbfGsO7Pe+wwwPapXqm1Cw HVycdeBhdDef4rT52xtGIoPQ5mFaXUx4/+P8cEPSDDuNGxUWupMpRH6k//MhDhBi7Z u7itQgCkCvyhxoNX+k4lqz2kzvwB0L8gIpzGeSQfdh5kJCcBLJQTAl37PzbYZQfU4e iSZFYDMyt/78oQeZNzVdEq38vY0d1XJvOg8GKVlCMnDuyuDG/cB+BhJgAolgbFWBiM AJPAQqcjwU7zA== From: Mark Brown Date: Thu, 01 Aug 2024 13:07:03 +0100 Subject: [PATCH v10 36/40] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20240801-arm64-gcs-v10-36-699e2bd2190b@kernel.org> References: <20240801-arm64-gcs-v10-0-699e2bd2190b@kernel.org> In-Reply-To: <20240801-arm64-gcs-v10-0-699e2bd2190b@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.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/pANAwAKASTWi3JdVIfQAcsmYgBmq4YhfQLguYdwaf40RAFxGT++va2Yk/g2Je2Nj4M2 0FHHERGJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZquGIQAKCRAk1otyXVSH0MSKB/ wIa+YZJDrdKEOJe1WZdjPgO+Y9XcfDcFjbwA1+VQm6G4V9R8aHmjbirJvqlNfwvNnFSBMsL4Uqywax /OLM9xW7BnMyPQ37h1Fhytv/+jQHhcFiB2XWre9jBJhVora2g7H9HC03qHhfVWF5YhhUEw130IT14w TKbmOsVuQvaEVsmNLQwaz7Op1S60YopvZIOul7P+Uh+jvyB22NfyEXWT4pFiNqEAWrXoUbXo8BZQai /p1D2+A8dWPJSbiMnF9HAbNSQWFHFnnxUpNOGc8L/4C489WMgcSIPGoO/6GSeqZ6uZjZYu8KdXvQvc C3Mf3nJVFT5d/AabfAWFXNhOnapFmS X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspam-User: X-Stat-Signature: uuo47iws7u8ocxzq9hp5gy1ofrjikxoh X-Rspamd-Queue-Id: 08EBF40043 X-Rspamd-Server: rspam11 X-HE-Tag: 1722517294-201460 X-HE-Meta: U2FsdGVkX19w/+eXno1REkehJ2fl8UvtCdKRdhEoHaDVpYjHGb0mL/3wZBHmY6u39BqKxFYZXkHGxnhc2FEBJPxy1JtfEBQR+hJoCX+mcJrbx8pEkDy30RnLi4FfWqch3Ccid8eYCqmcfDQGGCABP1BxioHlbhc2HpEdhDY3tO2gwnFaGg5cqnJ6Xl3NEFWwH4zTPbYG8Yk5uCSTrTs+idWs0a6p9UlZ8bHQMcVuksmFDCATPz/4dwL168K7Sf8Z9kuaBhwsGVdwLsqgRiLaHJKFiqnDCc+hnk6J+bBOT5ChPxNwZniH86RnMO5BMhNSkQGDasTcr6Sc8LrefRB+tQSj7a4WjnuHf4FayBmc09etvNCnVk27Pm5scRcmQTZpS4W1OwAKBg4nuL8fQdPfOVFhlbzJ5DHOt2JM5GnvIG07g/kfpyEnEfJcGcojFPZC5+AvS59YydVbhQiNIQYRBdbrG/9K7Dc0M/AuNPo2luKE53GZaxy3qZGGfCFksPlOHVah+DxGs/GUyXO4Rj1hDs4CbZ54Ojp/TEFEjx+t/FQzSlwRw4IkVH+3NwvQTwrDDpCqOAV4dVq+bBR4U9xfnk2cwB3Yq5yFGnIkoCMnF1v2CAhBD5QtndgdXfF8766KHE9Ts/0ZYp14j7V1iqDcGlxZL8Z5YdvlqBPIDCMQw6OL7eQJYUqzmCn5KVPRsJIh18QAYsdZhbQHfKVVRhLrr6EwqUXL2xLoyoDxFLNl0UiroTTkSA9EI8r3gOtJcCixu+3VXbIG/vG1iYlQnZipSEb19JNGtiTKs/jey6sW7ZFlcgvtWsaugaCYimyWLe8Wysg8CU9aVYL7HVP23cZ5Z+iq/4THQw8f9T/CWIBk+M4oTMnvOZfoNYGDtmaJ/Jl035faotGmnJg0WiOATSSWK6k12dDHNmWPrier1IubtqPxWopGDOyCQTa328eNoTVk/m2/hudM5E6gU5DLD/g a9lF65fx SOL8HWuDdG23om1WxWh5eLOeHZlS9SR899sCkWLu2rOk/wODuyqgWONY9CuMQFXzZbisxM/RcfIlnEMN77NJ2ZF4PHIpCHqeYIDhYh37P37aIxljkbJVJCbZLdeq7gbRmK5k0XzInFHXHasKVqRXNg+R5iisJ/eArxSxASultlPycUqo6psG1IktlMrxBSsubLXZ2CPEYfHn/tNlS7HplxMvlgaEN5rFYJ5PD6FLKqDcSxW+hGyNhImpnGmIQ7mHyuU50pZou/Dy6hwxGbeatsRy2AVtOMqTOJ5t4DhU9HlZmRx2scDoQzSXJjIlpXZVO47X+8tuOl5jo4NGonrgLgx7MSEH515iSZtyUELXuhR6uOF/jmWtXfG8fLK8IKs06g1sW 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); +}