All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Gray <bgray@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: ajd@linux.ibm.com, ruscur@russell.cc,
	linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org,
	cmr@bluescreens.de, Benjamin Gray <bgray@linux.ibm.com>
Subject: [RFC PATCH 11/13] selftests/powerpc: Add DEXCR prctl, sysctl interface test
Date: Mon, 28 Nov 2022 13:44:56 +1100	[thread overview]
Message-ID: <20221128024458.46121-12-bgray@linux.ibm.com> (raw)
In-Reply-To: <20221128024458.46121-1-bgray@linux.ibm.com>

Test the prctl and sysctl interfaces of the DEXCR.

This adds a new capabilities util for getting and setting CAP_SYS_ADMIN.
Adding this avoids depending on an external libcap package. There is a
similar implementation (and reason) in the tools/testing/selftests/bpf
subtree but there's no obvious place to move it for sharing.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../selftests/powerpc/dexcr/.gitignore        |   1 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   4 +-
 tools/testing/selftests/powerpc/dexcr/cap.c   |  72 ++++++
 tools/testing/selftests/powerpc/dexcr/cap.h   |  18 ++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |   2 +
 .../selftests/powerpc/dexcr/dexcr_test.c      | 241 ++++++++++++++++++
 6 files changed, 336 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/powerpc/dexcr/cap.c
 create mode 100644 tools/testing/selftests/powerpc/dexcr/cap.h
 create mode 100644 tools/testing/selftests/powerpc/dexcr/dexcr_test.c

diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore
index 37adb7f47832..035a1fcd8fb3 100644
--- a/tools/testing/selftests/powerpc/dexcr/.gitignore
+++ b/tools/testing/selftests/powerpc/dexcr/.gitignore
@@ -1 +1,2 @@
+dexcr_test
 hashchk_user
diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 4b4380d4d986..9814e72a4afa 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := hashchk_test
+TEST_GEN_PROGS := dexcr_test hashchk_test
 
 TEST_FILES := settings
 top_srcdir = ../../../../..
@@ -6,4 +6,4 @@ include ../../lib.mk
 
 HASHCHK_TEST_CFLAGS = -no-pie $(call cc-option,-mno-rop-protect)
 
-$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
+$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c ./cap.c
diff --git a/tools/testing/selftests/powerpc/dexcr/cap.c b/tools/testing/selftests/powerpc/dexcr/cap.c
new file mode 100644
index 000000000000..3c9b1f27345d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/cap.c
@@ -0,0 +1,72 @@
+#include <linux/capability.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include "cap.h"
+#include "utils.h"
+
+struct kernel_capabilities {
+	struct __user_cap_header_struct header;
+
+	struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
+};
+
+static void get_caps(struct kernel_capabilities *caps)
+{
+	FAIL_IF_EXIT_MSG(syscall(SYS_capget, &caps->header, &caps->data),
+			 "cannot get capabilities");
+}
+
+static void set_caps(struct kernel_capabilities *caps)
+{
+	FAIL_IF_EXIT_MSG(syscall(SYS_capset, &caps->header, &caps->data),
+			 "cannot set capabilities");
+}
+
+static void init_caps(struct kernel_capabilities *caps, pid_t pid)
+{
+	memset(caps, 0, sizeof(*caps));
+
+	caps->header.version = _LINUX_CAPABILITY_VERSION_3;
+	caps->header.pid = pid;
+
+	get_caps(caps);
+}
+
+static bool has_cap(struct kernel_capabilities *caps, size_t cap)
+{
+	size_t data_index = cap / 32;
+	size_t offset = cap % 32;
+
+	FAIL_IF_EXIT_MSG(data_index >= ARRAY_SIZE(caps->data), "cap out of range");
+
+	return caps->data[data_index].effective & (1 << offset);
+}
+
+static void drop_cap(struct kernel_capabilities *caps, size_t cap)
+{
+	size_t data_index = cap / 32;
+	size_t offset = cap % 32;
+
+	FAIL_IF_EXIT_MSG(data_index >= ARRAY_SIZE(caps->data), "cap out of range");
+
+	caps->data[data_index].effective &= ~(1 << offset);
+}
+
+bool check_cap_sysadmin(void)
+{
+	struct kernel_capabilities caps;
+
+	init_caps(&caps, 0);
+
+	return has_cap(&caps, CAP_SYS_ADMIN);
+}
+
+void drop_cap_sysadmin(void)
+{
+	struct kernel_capabilities caps;
+
+	init_caps(&caps, 0);
+	drop_cap(&caps, CAP_SYS_ADMIN);
+	set_caps(&caps);
+}
diff --git a/tools/testing/selftests/powerpc/dexcr/cap.h b/tools/testing/selftests/powerpc/dexcr/cap.h
new file mode 100644
index 000000000000..41f41dda9862
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/cap.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Simple capabilities getter/setter
+ *
+ * This header file contains helper functions and macros
+ * required to get and set capabilities(7). Introduced so
+ * we aren't the first to rely on libcap.
+ */
+#ifndef _SELFTESTS_POWERPC_DEXCR_CAP_H
+#define _SELFTESTS_POWERPC_DEXCR_CAP_H
+
+#include <stdbool.h>
+
+bool check_cap_sysadmin(void);
+
+void drop_cap_sysadmin(void);
+
+#endif  /* _SELFTESTS_POWERPC_DEXCR_CAP_H */
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h
index fb8007bf19f8..b90633ae49e9 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.h
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h
@@ -21,6 +21,8 @@
 #define DEXCR_PRO_SRAPD		DEXCR_PRO_MASK(4)
 #define DEXCR_PRO_NPHIE		DEXCR_PRO_MASK(5)
 
+#define SYSCTL_DEXCR_SBHE	"/proc/sys/kernel/speculative_branch_hint_enable"
+
 enum DexcrSource {
 	UDEXCR,		/* Userspace DEXCR value */
 	ENFORCED,	/* Enforced by hypervisor */
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr_test.c b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
new file mode 100644
index 000000000000..5446cb350c84
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
@@ -0,0 +1,241 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "cap.h"
+#include "dexcr.h"
+#include "utils.h"
+
+/*
+ * Test that an editable aspect
+ * - Current prctl state reported by the getter
+ * - Can be toggled on and off when process has CAP_SYS_ADMIN
+ * - Can't be edited if CAP_SYS_ADMIN not present
+ * - Can't be modified after force set
+ */
+static int dexcr_prctl_editable_aspect_test(unsigned long which)
+{
+	pid_t pid;
+
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(which), "aspect not supported");
+
+	FAIL_IF_MSG(!(pr_aspect_get(which) & PR_PPC_DEXCR_PRCTL), "aspect not editable");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(which, UDEXCR),
+		    "resetting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_SET_ASPECT), "prctl failed");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "setting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(which, UDEXCR),
+		    "clearing aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	pid = fork();
+	if (pid == 0) {
+		drop_cap_sysadmin();
+		FAIL_IF_EXIT_MSG(pr_aspect_edit(which, PR_PPC_DEXCR_SET_ASPECT),
+				 "prctl success when nonprivileged");
+		FAIL_IF_EXIT_MSG(pr_aspect_check(which, UDEXCR),
+				 "edited aspect when nonprivileged");
+		_exit(0);
+	}
+	await_child_success(pid);
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_FORCE_SET_ASPECT), "prctl force set failed");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "force setting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl success when forced");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "edited aspect when forced");
+
+	return 0;
+}
+
+static int dexcr_prctl_sbhe_test(void)
+{
+	sysctl_set_sbhe(-1);
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_SBHE);
+}
+
+static int dexcr_prctl_ibrtpd_test(void)
+{
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_IBRTPD);
+}
+
+static int dexcr_prctl_srapd_test(void)
+{
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_SRAPD);
+}
+
+static int dexcr_sysctl_sbhe_test(void)
+{
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(PR_PPC_DEXCR_SBHE), "aspect not supported");
+
+	sysctl_set_sbhe(0);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 0, "failed to clear sysctl SBHE");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to clear");
+
+	sysctl_set_sbhe(1);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 1, "failed to set sysctl SBHE");
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to set");
+
+	sysctl_set_sbhe(-1);
+	FAIL_IF_MSG(sysctl_get_sbhe() != -1, "failed to default sysctl SBHE");
+	FAIL_IF_MSG(!pr_aspect_edit(PR_PPC_DEXCR_SBHE, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to default to prctl clear setting");
+
+	FAIL_IF_MSG(!pr_aspect_edit(PR_PPC_DEXCR_SBHE, PR_PPC_DEXCR_SET_ASPECT), "prctl failed");
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to default to prctl set setting");
+
+	sysctl_set_sbhe(0);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 0, "failed to clear sysctl SBHE");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to override prctl setting");
+
+	return 0;
+}
+
+static int dexcr_test_inherit_execve(char expected_dexcr)
+{
+	switch (expected_dexcr) {
+	case '0':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "clearing IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "clearing IBRTPD across exec not applied");
+		break;
+	case '1':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "setting IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "setting IBRTPD across exec not applied");
+		break;
+	case '2':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "force setting IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "force setting IBRTPD across exec not applied");
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Check that a child process inherits the DEXCR over fork and execve
+ */
+static int dexcr_inherit_test(void)
+{
+	pid_t pid;
+
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(PR_PPC_DEXCR_IBRTPD), "IBRTPD not supported");
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_CLEAR_ASPECT);
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to clear");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "0", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "clearing IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "clearing IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_SET_ASPECT);
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to set");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "1", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "setting IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "setting IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_FORCE_SET_ASPECT);
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to force set");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "2", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "force setting IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "force setting IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int err = 0;
+
+	if (argc >= 2 && strcmp(argv[0], "dexcr_test_inherit_execve") == 0)
+		return dexcr_test_inherit_execve(argv[1][0]);
+
+	err |= test_harness(dexcr_prctl_sbhe_test, "dexcr_prctl_sbhe");
+	err |= test_harness(dexcr_prctl_ibrtpd_test, "dexcr_prctl_ibrtpd");
+	err |= test_harness(dexcr_prctl_srapd_test, "dexcr_prctl_srapd");
+	err |= test_harness(dexcr_sysctl_sbhe_test, "dexcr_sysctl_sbhe");
+	err |= test_harness(dexcr_inherit_test, "dexcr_inherit");
+
+	return err;
+}
-- 
2.38.1


WARNING: multiple messages have this Message-ID (diff)
From: Benjamin Gray <bgray@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: ajd@linux.ibm.com, linux-kernel@vger.kernel.org,
	linux-hardening@vger.kernel.org, cmr@bluescreens.de,
	Benjamin Gray <bgray@linux.ibm.com>
Subject: [RFC PATCH 11/13] selftests/powerpc: Add DEXCR prctl, sysctl interface test
Date: Mon, 28 Nov 2022 13:44:56 +1100	[thread overview]
Message-ID: <20221128024458.46121-12-bgray@linux.ibm.com> (raw)
In-Reply-To: <20221128024458.46121-1-bgray@linux.ibm.com>

Test the prctl and sysctl interfaces of the DEXCR.

This adds a new capabilities util for getting and setting CAP_SYS_ADMIN.
Adding this avoids depending on an external libcap package. There is a
similar implementation (and reason) in the tools/testing/selftests/bpf
subtree but there's no obvious place to move it for sharing.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../selftests/powerpc/dexcr/.gitignore        |   1 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   4 +-
 tools/testing/selftests/powerpc/dexcr/cap.c   |  72 ++++++
 tools/testing/selftests/powerpc/dexcr/cap.h   |  18 ++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |   2 +
 .../selftests/powerpc/dexcr/dexcr_test.c      | 241 ++++++++++++++++++
 6 files changed, 336 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/powerpc/dexcr/cap.c
 create mode 100644 tools/testing/selftests/powerpc/dexcr/cap.h
 create mode 100644 tools/testing/selftests/powerpc/dexcr/dexcr_test.c

diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore
index 37adb7f47832..035a1fcd8fb3 100644
--- a/tools/testing/selftests/powerpc/dexcr/.gitignore
+++ b/tools/testing/selftests/powerpc/dexcr/.gitignore
@@ -1 +1,2 @@
+dexcr_test
 hashchk_user
diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 4b4380d4d986..9814e72a4afa 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := hashchk_test
+TEST_GEN_PROGS := dexcr_test hashchk_test
 
 TEST_FILES := settings
 top_srcdir = ../../../../..
@@ -6,4 +6,4 @@ include ../../lib.mk
 
 HASHCHK_TEST_CFLAGS = -no-pie $(call cc-option,-mno-rop-protect)
 
-$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
+$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c ./cap.c
diff --git a/tools/testing/selftests/powerpc/dexcr/cap.c b/tools/testing/selftests/powerpc/dexcr/cap.c
new file mode 100644
index 000000000000..3c9b1f27345d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/cap.c
@@ -0,0 +1,72 @@
+#include <linux/capability.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include "cap.h"
+#include "utils.h"
+
+struct kernel_capabilities {
+	struct __user_cap_header_struct header;
+
+	struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
+};
+
+static void get_caps(struct kernel_capabilities *caps)
+{
+	FAIL_IF_EXIT_MSG(syscall(SYS_capget, &caps->header, &caps->data),
+			 "cannot get capabilities");
+}
+
+static void set_caps(struct kernel_capabilities *caps)
+{
+	FAIL_IF_EXIT_MSG(syscall(SYS_capset, &caps->header, &caps->data),
+			 "cannot set capabilities");
+}
+
+static void init_caps(struct kernel_capabilities *caps, pid_t pid)
+{
+	memset(caps, 0, sizeof(*caps));
+
+	caps->header.version = _LINUX_CAPABILITY_VERSION_3;
+	caps->header.pid = pid;
+
+	get_caps(caps);
+}
+
+static bool has_cap(struct kernel_capabilities *caps, size_t cap)
+{
+	size_t data_index = cap / 32;
+	size_t offset = cap % 32;
+
+	FAIL_IF_EXIT_MSG(data_index >= ARRAY_SIZE(caps->data), "cap out of range");
+
+	return caps->data[data_index].effective & (1 << offset);
+}
+
+static void drop_cap(struct kernel_capabilities *caps, size_t cap)
+{
+	size_t data_index = cap / 32;
+	size_t offset = cap % 32;
+
+	FAIL_IF_EXIT_MSG(data_index >= ARRAY_SIZE(caps->data), "cap out of range");
+
+	caps->data[data_index].effective &= ~(1 << offset);
+}
+
+bool check_cap_sysadmin(void)
+{
+	struct kernel_capabilities caps;
+
+	init_caps(&caps, 0);
+
+	return has_cap(&caps, CAP_SYS_ADMIN);
+}
+
+void drop_cap_sysadmin(void)
+{
+	struct kernel_capabilities caps;
+
+	init_caps(&caps, 0);
+	drop_cap(&caps, CAP_SYS_ADMIN);
+	set_caps(&caps);
+}
diff --git a/tools/testing/selftests/powerpc/dexcr/cap.h b/tools/testing/selftests/powerpc/dexcr/cap.h
new file mode 100644
index 000000000000..41f41dda9862
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/cap.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Simple capabilities getter/setter
+ *
+ * This header file contains helper functions and macros
+ * required to get and set capabilities(7). Introduced so
+ * we aren't the first to rely on libcap.
+ */
+#ifndef _SELFTESTS_POWERPC_DEXCR_CAP_H
+#define _SELFTESTS_POWERPC_DEXCR_CAP_H
+
+#include <stdbool.h>
+
+bool check_cap_sysadmin(void);
+
+void drop_cap_sysadmin(void);
+
+#endif  /* _SELFTESTS_POWERPC_DEXCR_CAP_H */
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h
index fb8007bf19f8..b90633ae49e9 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.h
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h
@@ -21,6 +21,8 @@
 #define DEXCR_PRO_SRAPD		DEXCR_PRO_MASK(4)
 #define DEXCR_PRO_NPHIE		DEXCR_PRO_MASK(5)
 
+#define SYSCTL_DEXCR_SBHE	"/proc/sys/kernel/speculative_branch_hint_enable"
+
 enum DexcrSource {
 	UDEXCR,		/* Userspace DEXCR value */
 	ENFORCED,	/* Enforced by hypervisor */
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr_test.c b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
new file mode 100644
index 000000000000..5446cb350c84
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
@@ -0,0 +1,241 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "cap.h"
+#include "dexcr.h"
+#include "utils.h"
+
+/*
+ * Test that an editable aspect
+ * - Current prctl state reported by the getter
+ * - Can be toggled on and off when process has CAP_SYS_ADMIN
+ * - Can't be edited if CAP_SYS_ADMIN not present
+ * - Can't be modified after force set
+ */
+static int dexcr_prctl_editable_aspect_test(unsigned long which)
+{
+	pid_t pid;
+
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(which), "aspect not supported");
+
+	FAIL_IF_MSG(!(pr_aspect_get(which) & PR_PPC_DEXCR_PRCTL), "aspect not editable");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(which, UDEXCR),
+		    "resetting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_SET_ASPECT), "prctl failed");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "setting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(which, UDEXCR),
+		    "clearing aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	pid = fork();
+	if (pid == 0) {
+		drop_cap_sysadmin();
+		FAIL_IF_EXIT_MSG(pr_aspect_edit(which, PR_PPC_DEXCR_SET_ASPECT),
+				 "prctl success when nonprivileged");
+		FAIL_IF_EXIT_MSG(pr_aspect_check(which, UDEXCR),
+				 "edited aspect when nonprivileged");
+		_exit(0);
+	}
+	await_child_success(pid);
+
+	FAIL_IF_MSG(!pr_aspect_edit(which, PR_PPC_DEXCR_FORCE_SET_ASPECT), "prctl force set failed");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "force setting aspect did not take effect");
+
+	FAIL_IF_MSG(pr_aspect_get(which) != (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+		    "prctl getter not reporting aspect state");
+
+	FAIL_IF_MSG(pr_aspect_edit(which, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl success when forced");
+	FAIL_IF_MSG(!pr_aspect_check(which, UDEXCR),
+		    "edited aspect when forced");
+
+	return 0;
+}
+
+static int dexcr_prctl_sbhe_test(void)
+{
+	sysctl_set_sbhe(-1);
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_SBHE);
+}
+
+static int dexcr_prctl_ibrtpd_test(void)
+{
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_IBRTPD);
+}
+
+static int dexcr_prctl_srapd_test(void)
+{
+	return dexcr_prctl_editable_aspect_test(PR_PPC_DEXCR_SRAPD);
+}
+
+static int dexcr_sysctl_sbhe_test(void)
+{
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(PR_PPC_DEXCR_SBHE), "aspect not supported");
+
+	sysctl_set_sbhe(0);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 0, "failed to clear sysctl SBHE");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to clear");
+
+	sysctl_set_sbhe(1);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 1, "failed to set sysctl SBHE");
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to set");
+
+	sysctl_set_sbhe(-1);
+	FAIL_IF_MSG(sysctl_get_sbhe() != -1, "failed to default sysctl SBHE");
+	FAIL_IF_MSG(!pr_aspect_edit(PR_PPC_DEXCR_SBHE, PR_PPC_DEXCR_CLEAR_ASPECT), "prctl failed");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to default to prctl clear setting");
+
+	FAIL_IF_MSG(!pr_aspect_edit(PR_PPC_DEXCR_SBHE, PR_PPC_DEXCR_SET_ASPECT), "prctl failed");
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to default to prctl set setting");
+
+	sysctl_set_sbhe(0);
+	FAIL_IF_MSG(sysctl_get_sbhe() != 0, "failed to clear sysctl SBHE");
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_SBHE, UDEXCR),
+		    "SBHE failed to override prctl setting");
+
+	return 0;
+}
+
+static int dexcr_test_inherit_execve(char expected_dexcr)
+{
+	switch (expected_dexcr) {
+	case '0':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "clearing IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "clearing IBRTPD across exec not applied");
+		break;
+	case '1':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "setting IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "setting IBRTPD across exec not applied");
+		break;
+	case '2':
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "force setting IBRTPD across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "force setting IBRTPD across exec not applied");
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Check that a child process inherits the DEXCR over fork and execve
+ */
+static int dexcr_inherit_test(void)
+{
+	pid_t pid;
+
+	SKIP_IF_MSG(!check_cap_sysadmin(), "must have capability CAP_SYS_ADMIN");
+	SKIP_IF_MSG(!pr_aspect_supported(PR_PPC_DEXCR_IBRTPD), "IBRTPD not supported");
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_CLEAR_ASPECT);
+	FAIL_IF_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to clear");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "0", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_CLEAR_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "clearing IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "clearing IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_SET_ASPECT);
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to set");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "1", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "setting IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "setting IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	pr_aspect_edit(PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_FORCE_SET_ASPECT);
+	FAIL_IF_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+		    "IBRTPD failed to force set");
+
+	pid = fork();
+	if (pid == 0) {
+		char *args[] = { "dexcr_test_inherit_execve", "2", NULL };
+
+		FAIL_IF_EXIT_MSG(pr_aspect_get(PR_PPC_DEXCR_IBRTPD) !=
+				 (PR_PPC_DEXCR_FORCE_SET_ASPECT | PR_PPC_DEXCR_PRCTL),
+				 "force setting IBRTPD not inherited");
+
+		FAIL_IF_EXIT_MSG(!pr_aspect_check(PR_PPC_DEXCR_IBRTPD, UDEXCR),
+				 "force setting IBRTPD not applied");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int err = 0;
+
+	if (argc >= 2 && strcmp(argv[0], "dexcr_test_inherit_execve") == 0)
+		return dexcr_test_inherit_execve(argv[1][0]);
+
+	err |= test_harness(dexcr_prctl_sbhe_test, "dexcr_prctl_sbhe");
+	err |= test_harness(dexcr_prctl_ibrtpd_test, "dexcr_prctl_ibrtpd");
+	err |= test_harness(dexcr_prctl_srapd_test, "dexcr_prctl_srapd");
+	err |= test_harness(dexcr_sysctl_sbhe_test, "dexcr_sysctl_sbhe");
+	err |= test_harness(dexcr_inherit_test, "dexcr_inherit");
+
+	return err;
+}
-- 
2.38.1


  parent reply	other threads:[~2022-11-28  2:46 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-28  2:44 [RFC PATCH 00/13] Add DEXCR support Benjamin Gray
2022-11-28  2:44 ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 01/13] powerpc/book3s: Add missing <linux/sched.h> include Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  4:28   ` Nicholas Piggin
2023-03-07  4:28     ` Nicholas Piggin
2022-11-28  2:44 ` [RFC PATCH 02/13] powerpc: Add initial Dynamic Execution Control Register (DEXCR) support Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  4:45   ` Nicholas Piggin
2023-03-07  4:45     ` Nicholas Piggin
2023-03-09 23:46     ` Benjamin Gray
2023-03-09 23:46       ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 03/13] powerpc/dexcr: Handle hashchk exception Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2022-11-29 10:39   ` Nicholas Piggin
2022-11-29 10:39     ` Nicholas Piggin
2022-11-29 22:04     ` Benjamin Gray
2022-11-29 22:04       ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 04/13] powerpc/dexcr: Support userspace ROP protection Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  5:05   ` Nicholas Piggin
2023-03-07  5:05     ` Nicholas Piggin
2023-03-07  5:37     ` Benjamin Gray
2023-03-07  5:37       ` Benjamin Gray
2023-03-21  4:51       ` Nicholas Piggin
2023-03-21  4:51         ` Nicholas Piggin
2022-11-28  2:44 ` [RFC PATCH 05/13] prctl: Define PowerPC DEXCR interface Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  5:07   ` Nicholas Piggin
2023-03-07  5:07     ` Nicholas Piggin
2022-11-28  2:44 ` [RFC PATCH 06/13] powerpc/dexcr: Add prctl implementation Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  5:12   ` Nicholas Piggin
2023-03-07  5:12     ` Nicholas Piggin
2022-11-28  2:44 ` [RFC PATCH 07/13] powerpc/dexcr: Add sysctl entry for SBHE system override Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  5:30   ` Nicholas Piggin
2023-03-07  5:30     ` Nicholas Piggin
2023-03-07  5:58     ` Benjamin Gray
2023-03-07  5:58       ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 08/13] powerpc/dexcr: Add enforced userspace ROP protection config Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 09/13] selftests/powerpc: Add more utility macros Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 10/13] selftests/powerpc: Add hashst/hashchk test Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2022-11-28  2:44 ` Benjamin Gray [this message]
2022-11-28  2:44   ` [RFC PATCH 11/13] selftests/powerpc: Add DEXCR prctl, sysctl interface test Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 12/13] selftests/powerpc: Add DEXCR status utility lsdexcr Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2022-11-28  2:44 ` [RFC PATCH 13/13] Documentation: Document PowerPC kernel DEXCR interface Benjamin Gray
2022-11-28  2:44   ` Benjamin Gray
2023-03-07  5:40   ` Nicholas Piggin
2023-03-07  5:40     ` Nicholas Piggin
2023-03-07  5:52     ` Benjamin Gray
2023-03-07  5:52       ` Benjamin Gray
2022-11-28  4:05 ` [RFC PATCH 00/13] Add DEXCR support Russell Currey
2022-11-28  4:05   ` Russell Currey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221128024458.46121-12-bgray@linux.ibm.com \
    --to=bgray@linux.ibm.com \
    --cc=ajd@linux.ibm.com \
    --cc=cmr@bluescreens.de \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=ruscur@russell.cc \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.