lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250226010731.2456-7-chang.seok.bae@intel.com>
Date: Tue, 25 Feb 2025 17:07:26 -0800
From: "Chang S. Bae" <chang.seok.bae@...el.com>
To: linux-kernel@...r.kernel.org,
	linux-kselftest@...r.kernel.org
Cc: x86@...nel.org,
	tglx@...utronix.de,
	mingo@...hat.com,
	bp@...en8.de,
	dave.hansen@...ux.intel.com,
	shuah@...nel.org,
	chang.seok.bae@...el.com
Subject: [PATCH 6/9] selftests/x86/xstate: Introduce signal ABI test

With the refactored test cases, another xstate exposure to userspace is
through signal delivery. While amx.c includes signal-related scenarios,
its primary focus is on xstate permission management, which is largely
specific to dynamic states.

The remaining gap is testing xstate preservation and restoration across
signal delivery. The kernel defines an ABI for presenting xstate in the
signal frame, closely resembling the hardware XSAVE format, where xstate
modification is also possible.

Introduce a new test case to verify xstate preservation across signal
delivery and return, that is ensuring ABI compatibility by:

- Loading xstate before raising a signal.
- Verifying correct exposure in the signal frame
- Modifying xstate in the signal frame before returning.
- Checking the state restoration upon signal return.

Integrate this test into the AMX test suite as an initial usage site.

Signed-off-by: Chang S. Bae <chang.seok.bae@...el.com>
---
Expected output:
$ amx_64
...
[RUN]   AMX Tile data: load xstate and raise SIGUSR1
[OK]    'magic1' is valid
[OK]    'xfeatures' in SW reserved area is valid
[OK]    'xfeatures' in XSAVE header is valid
[OK]    xstate delivery was successful
[OK]    'magic2' is valid
[RUN]   AMX Tile data: load new xstate from sighandler and check it after sigreturn
[OK]    xstate was restored correctly
---
 tools/testing/selftests/x86/amx.c    |   2 +
 tools/testing/selftests/x86/xstate.c | 108 +++++++++++++++++++++++++++
 tools/testing/selftests/x86/xstate.h |   1 +
 3 files changed, 111 insertions(+)

diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c
index 4bafbb72aa1b..9cb691d67ef4 100644
--- a/tools/testing/selftests/x86/amx.c
+++ b/tools/testing/selftests/x86/amx.c
@@ -510,6 +510,8 @@ int main(void)
 
 	test_ptrace(XFEATURE_XTILEDATA);
 
+	test_signal(XFEATURE_XTILEDATA);
+
 	clearhandler(SIGILL);
 	free_stashed_xsave();
 
diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c
index d318b35ba547..b5600f492632 100644
--- a/tools/testing/selftests/x86/xstate.c
+++ b/tools/testing/selftests/x86/xstate.c
@@ -21,6 +21,11 @@ static inline uint64_t xgetbv(uint32_t index)
 	return eax + ((uint64_t)edx << 32);
 }
 
+static inline uint64_t get_xstatebv(struct xsave_buffer *xbuf)
+{
+	return *(uint64_t *)(&xbuf->header);
+}
+
 static struct xstate_info xstate;
 
 struct futex_info {
@@ -325,3 +330,106 @@ void test_ptrace(uint32_t feature_num)
 	if (!WIFEXITED(status) || WEXITSTATUS(status))
 		ksft_exit_fail_msg("ptracee exit error\n");
 }
+
+/*
+ * Test signal delivery for the ABI compatibility.
+ * See the ABI format: arch/x86/include/uapi/asm/sigcontext.h
+ */
+
+/*
+ * Avoid using printf() in signal handlers as it is not
+ * async-signal-safe.
+ */
+#define SIGNAL_BUF_LEN 1000
+static char signal_message_buffer[SIGNAL_BUF_LEN];
+static void sig_print(char *msg)
+{
+	int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
+
+	strncat(signal_message_buffer, msg, left);
+}
+
+static struct xsave_buffer *stashed_xbuf;
+
+static void validate_sigfpstate(int sig, siginfo_t *si, void *ctx_void)
+{
+	ucontext_t *ctx = (ucontext_t *)ctx_void;
+	void *xbuf = ctx->uc_mcontext.fpregs;
+	struct _fpx_sw_bytes *sw_bytes;
+	uint32_t magic2;
+
+	/* Reset the signal message buffer: */
+	signal_message_buffer[0] = '\0';
+
+	sw_bytes = get_fpx_sw_bytes(xbuf);
+	if (sw_bytes->magic1 == FP_XSTATE_MAGIC1)
+		sig_print("[OK]\t'magic1' is valid\n");
+	else
+		sig_print("[FAIL]\t'magic1' is not valid\n");
+
+	if (get_fpx_sw_bytes_features(xbuf) & xstate.mask)
+		sig_print("[OK]\t'xfeatures' in SW reserved area is valid\n");
+	else
+		sig_print("[FAIL]\t'xfeatures' in SW reserved area is not valid\n");
+
+	if (get_xstatebv(xbuf) & xstate.mask)
+		sig_print("[OK]\t'xfeatures' in XSAVE header is valid\n");
+	else
+		sig_print("[FAIL]\t'xfeatures' in XSAVE hader is not valid\n");
+
+	if (validate_xstate_same(stashed_xbuf, xbuf))
+		sig_print("[OK]\txstate delivery was successful\n");
+	else
+		sig_print("[FAIL]\txstate delivery was not successful\n");
+
+	magic2 = *(uint32_t *)(xbuf + sw_bytes->xstate_size);
+	if (magic2 == FP_XSTATE_MAGIC2)
+		sig_print("[OK]\t'magic2' is valid\n");
+	else
+		sig_print("[FAIL]\t'magic2' is not valid\n");
+
+	set_rand_data(&xstate, xbuf);
+	copy_xstate(stashed_xbuf, xbuf);
+}
+
+void test_signal(uint32_t feature_num)
+{
+	bool valid_xstate;
+
+	xstate = get_xstate_info(feature_num);
+
+	/*
+	 * The signal handler will access this to verify xstate context
+	 * preservation.
+	 */
+
+	stashed_xbuf = alloc_xbuf();
+	if (!stashed_xbuf)
+		ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
+
+	printf("[RUN]\t%s: load xstate and raise SIGUSR1\n", xstate.name);
+
+	sethandler(SIGUSR1, validate_sigfpstate, 0);
+
+	load_rand_xstate(&xstate, stashed_xbuf);
+
+	raise(SIGUSR1);
+
+	/*
+	 * Immediately record the test result, deferring printf() to
+	 * prevent unintended state contamination by that.
+	 */
+	valid_xstate = validate_xregs_same(stashed_xbuf);
+	printf("%s", signal_message_buffer);
+
+	printf("[RUN]\t%s: load new xstate from sighandler and check it after sigreturn\n",
+	       xstate.name);
+
+	if (valid_xstate)
+		printf("[OK]\txstate was restored correctly\n");
+	else
+		printf("[FAIL]\txstate restoration failed\n");
+
+	clearhandler(SIGUSR1);
+	free(stashed_xbuf);
+}
diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h
index 2bf11d3a3ce9..4d0ffe9609f8 100644
--- a/tools/testing/selftests/x86/xstate.h
+++ b/tools/testing/selftests/x86/xstate.h
@@ -191,5 +191,6 @@ static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer
 
 void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations);
 void test_ptrace(uint32_t feature_num);
+void test_signal(uint32_t feature_num);
 
 #endif /* __SELFTESTS_X86_XSTATE_H */
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ