From patchwork Sat Feb 3 12:26:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13544160 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 065D1C4828D for ; Sat, 3 Feb 2024 12:33:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 91BBB6B00C6; Sat, 3 Feb 2024 07:33:42 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 8CCCF6B00C7; Sat, 3 Feb 2024 07:33:42 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 746E76B00C8; Sat, 3 Feb 2024 07:33:42 -0500 (EST) 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 600946B00C6 for ; Sat, 3 Feb 2024 07:33:42 -0500 (EST) Received: from smtpin18.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 3423B14035E for ; Sat, 3 Feb 2024 12:33:42 +0000 (UTC) X-FDA: 81750433884.18.3DFED20 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf29.hostedemail.com (Postfix) with ESMTP id 9E23A120014 for ; Sat, 3 Feb 2024 12:33:39 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="lUf867/I"; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf29.hostedemail.com: domain of broonie@kernel.org designates 145.40.73.55 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=1706963620; 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=AMQDQBZwsPLJIRtdr1bxOR1QY3BOan9WAcBGiY3AuD0easnMAup3CK4soXdZCRtCbS6OX+ 7C927tvmito62/1M5n/UlgCrsHAySPuv5NwRCR5SnPg+x4NHXk4ZbHfw5Rm9kJZVvsghNR kR6rhcWj2RcRPg8euBsU6SUfXyGOCZY= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="lUf867/I"; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf29.hostedemail.com: domain of broonie@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=broonie@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1706963620; a=rsa-sha256; cv=none; b=pg1jXFraIa2ArD4nV72Nh22AzK/pLywxKU6QJ5YHGOwLO3i4bON1Ih6euCTO6QiohMrav3 5223LhO8LOqVMP2S+YN/C9H6cuJNf4DFQ+es1Lm0K04yFy1QEhnv+cPBFtvn4lHNUhkL0a oWLC97iGtIhwQgHRIpoEgCLym27TnCo= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 44905CE1F18; Sat, 3 Feb 2024 12:33:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 34C1BC43390; Sat, 3 Feb 2024 12:33:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1706963614; bh=IP7maWyjZ0dh+q8gDfrxLaUB03tkGEoqGc+9eYXpRWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=lUf867/IYTnlmfivw2vcu+gZCvSb7GVG5VRnmQDFmQg6rYyaC9H9noFVLBOwGRPQI FTgk6uVmgHEzoBo5+x//TTBxchZUYb8rWezBMc+hvg0rx8WxU39eU51BdH8BD9k7sW 8qodxPwPm0Jx+45GESf1OyDZGmNm12Q/SOwOnkRXNo42ZE+L3jayyH5Iff8Zqbyid6 WOqq7+RRoF5xs92MjUIQbI91kvt2KIm26eh8schxQ7aYO6kR56T3+85QU+sOh8oxC5 T4bIi+jyGxhMDvseI96rjz0oMMKWn5cboQVu28GB8sxKQ37hXTjdputCgIq5Ev23PO TxMYEyrbPaoAQ== From: Mark Brown Date: Sat, 03 Feb 2024 12:26:00 +0000 Subject: [PATCH v8 34/38] kselftest/arm64: Add test coverage for GCS mode locking MIME-Version: 1.0 Message-Id: <20240203-arm64-gcs-v8-34-c9fec77673ef@kernel.org> References: <20240203-arm64-gcs-v8-0-c9fec77673ef@kernel.org> In-Reply-To: <20240203-arm64-gcs-v8-0-c9fec77673ef@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 , Thiago Jung Bauermann , 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-a684c 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/pANAwAKASTWi3JdVIfQAcsmYgBlvjDrVwGlTHFqGQFU5FQOcbAFNfn+d/ZZXmK+epCj TesXUFaJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZb4w6wAKCRAk1otyXVSH0Dp6B/ 427Q1kr1wSJrS9lqpLcIsIugUm1F07V9fnO08lyEDhIoUIji9R5YD/X5W6x86fryWV8QRrEURJNnch ff8OKTlfNgiK7I+P3kCBoH4XrthYuaP8TkHOZWBmVbzMcoiSqUWfsNrOWFSjkmUr5cl4XIvtsqBQXw 2eWAzZ4hG2rS9zSe2MeiuPOuV7Hlthlni0UXqgxDv7tzVpqG/DE3TCaglGxznDe+3HUvzVY2eqCaV1 ph4usWgUpK6+iQ7es7F1ve/a05w0HiDlk0fYq7Mo4hT2RFBko+oU+XW9NLjekEWFgSQk9bxV2EFvpl UhzbHjSupx5rz7/Dq/m7m00Y2RCq71 X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Rspamd-Queue-Id: 9E23A120014 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: kq77soukscz8nd7ayzk4gmtufa3rasq8 X-HE-Tag: 1706963619-14337 X-HE-Meta: U2FsdGVkX180tfR1lQuRzklGfpoeNVEzIRfAGPldzKPepoMYH50uWKYGan9VlK+x5tpztVMai03QRbCCDcGu/N6Xan0PmQsrtWivKzZes5sMXHv55ytcpll/izyL7eiAUaUkEOXxyRzoZ1bYlip87U2jk37V3Mov/TOeChlKXpvTWm5kM27w2+b/WryqHZa0cdxCxJqrcmN0HydjGUBrGRDONeOexJsfZBTMY45NXp8jX4X8meItHhPAg4v4av7K9Adls5EBAnlbw6IAzNvm5qKHT2JcqU4XNwq89Sp+dTL9aIiNRHoSXyJK671p2SUJUrq8eDnszwVxyxugSaKAxvhPziqe0wKg9kPaRLPvNgwiCjY4mu3RfP2EmxmRrhn/BmIC0wk5AyLk8LAtkMUR6OBP3SWvjBMg0D4Fl1BRMM51hQWhVrBMkTIE7Z2SnfcWt9uXjQFT7ZA0vQnskzt9mgtY5DW6V3NV+uKfhmC+uvFMW+4Doub34Urc5lm+P6DG6/4niqIjw8k0R/UAv23BmHhiDG7f3MJjlKKdZxo4N8S3/csq+Imthdc360oKtk81nE/hvxabaO6wBqeQPbuPf/zJmT9OwBMTC/eb/wJXrnIBr5JZFRl6GHBZRCfDH06FWt1MUyCaB2a1J0ilIzXQGr4zRD8CmGi5IkY2N25BZFvGMj9ld52haXY5L21ySF6vDYZm6fgF2NhAX8TyX0+NY4Xekw5e3C7Tk70Yw9GFU21hN4F7fDrfmyQaLosvwVQWdNYlWv4RzhSSjfDnkDpMPyIRv0DGZbZXMQDPh4e+KQ2Cg6YjOrAwjU8DrQIyIBj3jV/jrEIl6A2154O6qZwjkzQUybdF4hZ3Y2tWhHHnkPByPJbDyFE6BZjiW1+BGz7N7vj8hIJ5AhUS+vHek2eHBBBp2rP5d0t4hs+LemQDuLg+fCY/Dw/+DepvfMyrT7BeWCLwsxYd0aVhJ0eFhx6 I7irsUBl 6WpJCSR5ICVbMNuGMquTei3OfZLOjdMkbAOvNut4pEX5wz/aC9V3XJPbnhnt8hR3qCu0J8i/Fds9Wun5TxHJy9RXYpfEPvA9F8aPPKt2VJSBEuBkt4WGN+vV9JjUk/ZQUM0Y0qic6YEfkJfZcEuVkdkTz7ihVPSLkYhiuTcWPgIBNftNowxyrf8opgK73sPmYGFB30jPVQiTXx6FodpR4Vt2hCItNL14282kzokqqEG5+3JVHJWqh/2wOsG0YhJ2dlGuoHqoUGJ8VK1M1t7bzzdV0sT/uZ1F2xtnR6q4mpZ1rWUFzPdeQtSYW1HbwYn2G3lB8 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. 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); +}