diff mbox series

[v1,4/4] selftests/x86: Refactor altstack setup code

Message ID 20230403044340.1312-5-chang.seok.bae@intel.com (mailing list archive)
State New
Headers show
Series selftests/x86: Improve signal test code | expand

Commit Message

Chang S. Bae April 3, 2023, 4:43 a.m. UTC
The sigaltstack setup code is almost the same across x86 tests. Most
of the test probably just needs a ready-to-use altstack instead of all
the setup code.

Refactor them to these helpers to simplify the test code:

- setup_sigaltstack()

  Allocate an altstack memory with a size more than the
  kernel-provided minimum. Then register the altstack via
  sigaltstack(2).

- cleanup_sigaltstack()

  Unregister the altstack and free up the memory.

Then, these two function calls are supposed to be enough for most
sigaltstack-needed test cases. But, when explicit sigaltstack() is
needed, another helper is available:

- init_sigaltstack()

  Do the same as setup_sigaltstack(), except for not invoking the
  sigaltstack syscall.

Finally, while here, ensure an altstack cleanup everywhere an altstack
is used.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
The patch is based on another series that fixes the sigaltstack test:
  https://lore.kernel.org/all/20230330233520.21937-2-chang.seok.bae@intel.com/

Considerably that fix should go first before this cleanup rework.
---
 tools/testing/selftests/x86/amx.c             | 42 ++++------
 tools/testing/selftests/x86/helpers.c         | 80 +++++++++++++++++++
 tools/testing/selftests/x86/helpers.h         |  4 +
 tools/testing/selftests/x86/mov_ss_trap.c     | 11 +--
 tools/testing/selftests/x86/sigaltstack.c     | 40 ++++------
 tools/testing/selftests/x86/sigreturn.c       | 10 +--
 .../selftests/x86/single_step_syscall.c       | 12 +--
 .../testing/selftests/x86/syscall_arg_fault.c | 11 +--
 8 files changed, 130 insertions(+), 80 deletions(-)
diff mbox series

Patch

diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c
index 1e8e60b1f7b9..70e1d64e9c57 100644
--- a/tools/testing/selftests/x86/amx.c
+++ b/tools/testing/selftests/x86/amx.c
@@ -362,29 +362,11 @@  static void validate_xcomp_perm(enum expected_result exp)
 #  define AT_MINSIGSTKSZ	51
 #endif
 
-static void *alloc_altstack(unsigned int size)
+static void setup_altstack(stack_t *stack, enum expected_result exp)
 {
-	void *altstack;
-
-	altstack = mmap(NULL, size, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
-
-	if (altstack == MAP_FAILED)
-		fatal_error("mmap() for altstack");
-
-	return altstack;
-}
-
-static void setup_altstack(void *addr, unsigned long size, enum expected_result exp)
-{
-	stack_t ss;
 	int rc;
 
-	memset(&ss, 0, sizeof(ss));
-	ss.ss_size = size;
-	ss.ss_sp = addr;
-
-	rc = sigaltstack(&ss, NULL);
+	rc = sigaltstack(stack, NULL);
 
 	if (exp == FAIL_EXPECTED) {
 		if (rc) {
@@ -401,7 +383,7 @@  static void test_dynamic_sigaltstack(void)
 {
 	unsigned int small_size, enough_size;
 	unsigned long minsigstksz;
-	void *altstack;
+	stack_t stack = { };
 
 	minsigstksz = getauxval(AT_MINSIGSTKSZ);
 	printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz);
@@ -416,9 +398,9 @@  static void test_dynamic_sigaltstack(void)
 		return;
 	}
 
-	enough_size = minsigstksz * 2;
-
-	altstack = alloc_altstack(enough_size);
+	if (init_sigaltstack(&stack) != 0)
+		fatal_error("sigaltstack allocation failed.");
+	enough_size = stack.ss_size;
 	printf("\tAllocate memory for altstack (%u bytes).\n", enough_size);
 
 	/*
@@ -427,7 +409,8 @@  static void test_dynamic_sigaltstack(void)
 	 */
 	small_size = minsigstksz - xtiledata.size;
 	printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size);
-	setup_altstack(altstack, small_size, SUCCESS_EXPECTED);
+	stack.ss_size = small_size;
+	setup_altstack(&stack, SUCCESS_EXPECTED);
 	validate_req_xcomp_perm(FAIL_EXPECTED);
 
 	/*
@@ -436,7 +419,8 @@  static void test_dynamic_sigaltstack(void)
 	 * and thus ARCH_REQ_XCOMP_PERM should succeed.
 	 */
 	printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size);
-	setup_altstack(altstack, enough_size, SUCCESS_EXPECTED);
+	stack.ss_size = enough_size;
+	setup_altstack(&stack, SUCCESS_EXPECTED);
 	validate_req_xcomp_perm(SUCCESS_EXPECTED);
 
 	/*
@@ -446,7 +430,11 @@  static void test_dynamic_sigaltstack(void)
 	 * once XTILEDATA permission is established.
 	 */
 	printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size);
-	setup_altstack(altstack, small_size, FAIL_EXPECTED);
+	stack.ss_size = small_size;
+	setup_altstack(&stack, FAIL_EXPECTED);
+
+	stack.ss_size = enough_size;
+	cleanup_sigaltstack(&stack);
 }
 
 static void test_dynamic_state(void)
diff --git a/tools/testing/selftests/x86/helpers.c b/tools/testing/selftests/x86/helpers.c
index a6ecc42d359f..1f5b1e5a3d66 100644
--- a/tools/testing/selftests/x86/helpers.c
+++ b/tools/testing/selftests/x86/helpers.c
@@ -3,6 +3,15 @@ 
 #include <string.h>
 #include <err.h>
 
+#include <sys/auxv.h>
+#include <sys/mman.h>
+
+#include "helpers.h"
+
+#ifndef AT_MINSIGSTKSZ
+#  define AT_MINSIGSTKSZ	51
+#endif
+
 #include "helpers.h"
 
 void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
@@ -28,3 +37,74 @@  void clearhandler(int sig)
 	if (sigaction(sig, &sa, 0))
 		err(1, "sigaction");
 }
+
+#define ALTSTKSZ	8096
+
+static unsigned long get_sigaltstacksz(void)
+{
+	return getauxval(AT_MINSIGSTKSZ) + ALTSTKSZ;
+}
+
+/**
+ * init_sigalstack -- allocate an altstack without registration
+ * @stack:	stack_t pointer
+ * Returns:	0 if successful; otherwise, nonzero
+ *
+ * Unless testing with different sizes, setup_sigaltstack() should be
+ * enough to provide a ready-to-use stack
+ */
+int init_sigaltstack(stack_t *stack)
+{
+	if (!stack)
+		return -1;
+
+	if (stack->ss_size > 0 && stack->ss_sp > 0)
+		return 0;
+
+	stack->ss_size = get_sigaltstacksz();
+
+	stack->ss_sp = mmap(NULL, stack->ss_size, PROT_READ | PROT_WRITE,
+			    MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+	if (stack->ss_sp == MAP_FAILED)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * setup_sigaltstack -- allocate and register an altstack
+ * @stack:	stack_t pointer
+ * Returns:	0 if successful; otherwise, nonzero
+ */
+int setup_sigaltstack(stack_t *stack)
+{
+	int rc;
+
+	rc = init_sigaltstack(stack);
+	if (rc)
+		return -1;
+
+	return sigaltstack(stack, NULL);
+}
+
+/**
+ * cleanup_sigaltstack -- unregister and free an altstack
+ * @stack:	stack_t pointer
+ * Returns:	None
+ */
+void cleanup_sigaltstack(stack_t *stack)
+{
+	size_t size;
+	void *sp;
+
+	if (!stack)
+		return;
+
+	size = stack->ss_size;
+	sp = stack->ss_sp;
+
+	stack->ss_flags = SS_DISABLE;
+	sigaltstack(stack, NULL);
+
+	munmap(sp, size);
+}
diff --git a/tools/testing/selftests/x86/helpers.h b/tools/testing/selftests/x86/helpers.h
index 35ff4df35397..a47ba1a2d929 100644
--- a/tools/testing/selftests/x86/helpers.h
+++ b/tools/testing/selftests/x86/helpers.h
@@ -5,6 +5,10 @@ 
 #include <signal.h>
 #include <asm/processor-flags.h>
 
+int init_sigaltstack(stack_t *stack);
+int setup_sigaltstack(stack_t *stack);
+void cleanup_sigaltstack(stack_t *stack);
+
 void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
 		int flags);
 
diff --git a/tools/testing/selftests/x86/mov_ss_trap.c b/tools/testing/selftests/x86/mov_ss_trap.c
index cfec7a3e30b7..c9ffc8b3a214 100644
--- a/tools/testing/selftests/x86/mov_ss_trap.c
+++ b/tools/testing/selftests/x86/mov_ss_trap.c
@@ -133,13 +133,8 @@  int main()
 	stack_t stack = { };
 	unsigned long nr;
 
-	stack.ss_size = SIGSTKSZ;
-	stack.ss_sp = malloc(sizeof(char) * SIGSTKSZ);
-	if (!stack.ss_sp)
-		err(1, "malloc()");
-
-	if (sigaltstack(&stack, NULL) != 0)
-		err(1, "sigaltstack()");
+	if (setup_sigaltstack(&stack) != 0)
+		err(1, "sigaltstack");
 
 	asm volatile ("mov %%ss, %[ss]" : [ss] "=m" (ss));
 	printf("\tSS = 0x%hx, &SS = 0x%p\n", ss, &ss);
@@ -271,7 +266,7 @@  int main()
 			);
 	}
 
-	free(stack.ss_sp);
+	cleanup_sigaltstack(&stack);
 	printf("[OK]\tI aten't dead\n");
 	return 0;
 }
diff --git a/tools/testing/selftests/x86/sigaltstack.c b/tools/testing/selftests/x86/sigaltstack.c
index 7c2bd27908d5..6f753406ca91 100644
--- a/tools/testing/selftests/x86/sigaltstack.c
+++ b/tools/testing/selftests/x86/sigaltstack.c
@@ -28,17 +28,6 @@  static bool sigalrm_expected;
 
 static unsigned long at_minstack_size;
 
-static int setup_altstack(void *start, unsigned long size)
-{
-	stack_t ss;
-
-	memset(&ss, 0, sizeof(ss));
-	ss.ss_size = size;
-	ss.ss_sp = start;
-
-	return sigaltstack(&ss, NULL);
-}
-
 static jmp_buf jmpbuf;
 
 static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
@@ -63,14 +52,14 @@  static void sigalrm(int sig, siginfo_t *info, void *ctx_void)
 	}
 }
 
-static void test_sigaltstack(void *altstack, unsigned long size)
+static void test_sigaltstack(stack_t *stack)
 {
-	if (setup_altstack(altstack, size)) {
+	if (sigaltstack(stack, NULL)) {
 		/*
 		 * The kernel may return ENOMEM when the altstack size
 		 * is insufficient. Skip the test in this case.
 		 */
-		if (errno == ENOMEM && size < at_minstack_size) {
+		if (errno == ENOMEM && stack->ss_size < at_minstack_size) {
 			printf("[SKIP]\tThe running kernel disallows an insufficient size.\n");
 			return;
 		}
@@ -78,7 +67,7 @@  static void test_sigaltstack(void *altstack, unsigned long size)
 		err(1, "sigaltstack()");
 	}
 
-	sigalrm_expected = (size > at_minstack_size) ? true : false;
+	sigalrm_expected = (stack->ss_size > at_minstack_size) ? true : false;
 
 	sethandler(SIGSEGV, sigsegv, 0);
 	sethandler(SIGALRM, sigalrm, SA_ONSTACK);
@@ -97,19 +86,24 @@  static void test_sigaltstack(void *altstack, unsigned long size)
 
 int main(void)
 {
-	void *altstack;
+	unsigned long enough_size;
+	stack_t stack = { };
 
 	at_minstack_size = getauxval(AT_MINSIGSTKSZ);
 
-	altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
-	if (altstack == MAP_FAILED)
-		err(1, "mmap()");
+	if (init_sigaltstack(&stack) != 0)
+		err(1, "sigaltstack allocation failed.");
+	enough_size = stack.ss_size;
+
+	if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size) {
+		stack.ss_size = ENFORCED_MINSIGSTKSZ + 1;
+		test_sigaltstack(&stack);
+	}
 
-	if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size)
-		test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1);
+	stack.ss_size = enough_size;
+	test_sigaltstack(&stack);
 
-	test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ);
+	cleanup_sigaltstack(&stack);
 
 	return nerrs == 0 ? 0 : 1;
 }
diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
index b2282ca57e23..f9e06a13ad82 100644
--- a/tools/testing/selftests/x86/sigreturn.c
+++ b/tools/testing/selftests/x86/sigreturn.c
@@ -741,17 +741,13 @@  int main()
 {
 	int total_nerrs = 0;
 	unsigned short my_cs, my_ss;
+	stack_t stack = { };
 
 	asm volatile ("mov %%cs,%0" : "=r" (my_cs));
 	asm volatile ("mov %%ss,%0" : "=r" (my_ss));
 	setup_ldt();
 
-	stack_t stack = {
-		/* Our sigaltstack scratch space. */
-		.ss_sp = malloc(sizeof(char) * SIGSTKSZ),
-		.ss_size = SIGSTKSZ,
-	};
-	if (sigaltstack(&stack, NULL) != 0)
+	if (setup_sigaltstack(&stack) != 0)
 		err(1, "sigaltstack");
 
 	sethandler(SIGUSR1, sigusr1, 0);
@@ -849,6 +845,6 @@  int main()
 	total_nerrs += test_nonstrict_ss();
 #endif
 
-	free(stack.ss_sp);
+	cleanup_sigaltstack(&stack);
 	return total_nerrs ? 1 : 0;
 }
diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c
index 4c9b8fd7a41a..4e3224e52e30 100644
--- a/tools/testing/selftests/x86/single_step_syscall.c
+++ b/tools/testing/selftests/x86/single_step_syscall.c
@@ -126,13 +126,8 @@  int main()
 	int tmp;
 #endif
 
-	stack.ss_size = SIGSTKSZ;
-	stack.ss_sp = malloc(sizeof(char) * SIGSTKSZ);
-	if (!stack.ss_sp)
-		err(1, "malloc()");
-
-	if (sigaltstack(&stack, NULL) != 0)
-		err(1, "sigaltstack()");
+	if (setup_sigaltstack(&stack) != 0)
+		err(1, "sigaltstack");
 
 	sethandler(SIGTRAP, sigtrap, 0);
 
@@ -193,6 +188,7 @@  int main()
 	 */
 	if (sigsetjmp(jmpbuf, 1) == 0) {
 		unsigned long nr = SYS_getpid;
+
 		printf("[RUN]\tSet TF and check SYSENTER\n");
 		sethandler(SIGSEGV, print_and_longjmp,
 			   SA_RESETHAND | SA_ONSTACK);
@@ -217,6 +213,6 @@  int main()
 	/* Now make sure that another fast syscall doesn't set TF again. */
 	fast_syscall_no_tf();
 
-	free(stack.ss_sp);
+	cleanup_sigaltstack(&stack);
 	return 0;
 }
diff --git a/tools/testing/selftests/x86/syscall_arg_fault.c b/tools/testing/selftests/x86/syscall_arg_fault.c
index 1149ac24921a..1b22ef548582 100644
--- a/tools/testing/selftests/x86/syscall_arg_fault.c
+++ b/tools/testing/selftests/x86/syscall_arg_fault.c
@@ -87,12 +87,9 @@  static void sigill(int sig, siginfo_t *info, void *ctx_void)
 
 int main()
 {
-	stack_t stack = {
-		/* Our sigaltstack scratch space. */
-		.ss_sp = malloc(sizeof(char) * SIGSTKSZ),
-		.ss_size = SIGSTKSZ,
-	};
-	if (sigaltstack(&stack, NULL) != 0)
+	stack_t stack = { };
+
+	if (setup_sigaltstack(&stack) != 0)
 		err(1, "sigaltstack");
 
 	sethandler(SIGSEGV, sigsegv_or_sigbus, SA_ONSTACK);
@@ -218,6 +215,6 @@  int main()
 	set_eflags(get_eflags() & ~X86_EFLAGS_TF);
 #endif
 
-	free(stack.ss_sp);
+	cleanup_sigaltstack(&stack);
 	return 0;
 }