Skip to content

Commit 62faca1

Browse files
ChangSeokBaehansendc
authored andcommitted
selftests/x86/amx: Add a ptrace test
Include a test case to validate the XTILEDATA injection to the target. Also, it ensures the kernel's ability to copy states between different XSAVE formats. Refactor the memcmp() code to be usable for the state validation. Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20230227210504.18520-3-chang.seok.bae%40intel.com
1 parent b158888 commit 62faca1

File tree

1 file changed

+105
-3
lines changed
  • tools/testing/selftests/x86

1 file changed

+105
-3
lines changed

tools/testing/selftests/x86/amx.c

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#include <sys/auxv.h>
1515
#include <sys/mman.h>
1616
#include <sys/shm.h>
17+
#include <sys/ptrace.h>
1718
#include <sys/syscall.h>
1819
#include <sys/wait.h>
20+
#include <sys/uio.h>
1921

2022
#include "../kselftest.h" /* For __cpuid_count() */
2123

@@ -583,6 +585,13 @@ static void test_dynamic_state(void)
583585
_exit(0);
584586
}
585587

588+
static inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2)
589+
{
590+
return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
591+
&xbuf2->bytes[xtiledata.xbuf_offset],
592+
xtiledata.size);
593+
}
594+
586595
/*
587596
* Save current register state and compare it to @xbuf1.'
588597
*
@@ -599,9 +608,7 @@ static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
599608
fatal_error("failed to allocate XSAVE buffer\n");
600609

601610
xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
602-
ret = memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
603-
&xbuf2->bytes[xtiledata.xbuf_offset],
604-
xtiledata.size);
611+
ret = __compare_tiledata_state(xbuf1, xbuf2);
605612

606613
free(xbuf2);
607614

@@ -826,6 +833,99 @@ static void test_context_switch(void)
826833
free(finfo);
827834
}
828835

836+
/* Ptrace test */
837+
838+
/*
839+
* Make sure the ptracee has the expanded kernel buffer on the first
840+
* use. Then, initialize the state before performing the state
841+
* injection from the ptracer.
842+
*/
843+
static inline void ptracee_firstuse_tiledata(void)
844+
{
845+
load_rand_tiledata(stashed_xsave);
846+
init_xtiledata();
847+
}
848+
849+
/*
850+
* Ptracer injects the randomized tile data state. It also reads
851+
* before and after that, which will execute the kernel's state copy
852+
* functions. So, the tester is advised to double-check any emitted
853+
* kernel messages.
854+
*/
855+
static void ptracer_inject_tiledata(pid_t target)
856+
{
857+
struct xsave_buffer *xbuf;
858+
struct iovec iov;
859+
860+
xbuf = alloc_xbuf();
861+
if (!xbuf)
862+
fatal_error("unable to allocate XSAVE buffer");
863+
864+
printf("\tRead the init'ed tiledata via ptrace().\n");
865+
866+
iov.iov_base = xbuf;
867+
iov.iov_len = xbuf_size;
868+
869+
memset(stashed_xsave, 0, xbuf_size);
870+
871+
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
872+
fatal_error("PTRACE_GETREGSET");
873+
874+
if (!__compare_tiledata_state(stashed_xsave, xbuf))
875+
printf("[OK]\tThe init'ed tiledata was read from ptracee.\n");
876+
else
877+
printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n");
878+
879+
printf("\tInject tiledata via ptrace().\n");
880+
881+
load_rand_tiledata(xbuf);
882+
883+
memcpy(&stashed_xsave->bytes[xtiledata.xbuf_offset],
884+
&xbuf->bytes[xtiledata.xbuf_offset],
885+
xtiledata.size);
886+
887+
if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
888+
fatal_error("PTRACE_SETREGSET");
889+
890+
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
891+
fatal_error("PTRACE_GETREGSET");
892+
893+
if (!__compare_tiledata_state(stashed_xsave, xbuf))
894+
printf("[OK]\tTiledata was correctly written to ptracee.\n");
895+
else
896+
printf("[FAIL]\tTiledata was not correctly written to ptracee.\n");
897+
}
898+
899+
static void test_ptrace(void)
900+
{
901+
pid_t child;
902+
int status;
903+
904+
child = fork();
905+
if (child < 0) {
906+
err(1, "fork");
907+
} else if (!child) {
908+
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL))
909+
err(1, "PTRACE_TRACEME");
910+
911+
ptracee_firstuse_tiledata();
912+
913+
raise(SIGTRAP);
914+
_exit(0);
915+
}
916+
917+
do {
918+
wait(&status);
919+
} while (WSTOPSIG(status) != SIGTRAP);
920+
921+
ptracer_inject_tiledata(child);
922+
923+
ptrace(PTRACE_DETACH, child, NULL, NULL);
924+
wait(&status);
925+
if (!WIFEXITED(status) || WEXITSTATUS(status))
926+
err(1, "ptrace test");
927+
}
928+
829929
int main(void)
830930
{
831931
/* Check hardware availability at first */
@@ -846,6 +946,8 @@ int main(void)
846946
ctxtswtest_config.num_threads = 5;
847947
test_context_switch();
848948

949+
test_ptrace();
950+
849951
clearhandler(SIGILL);
850952
free_stashed_xsave();
851953

0 commit comments

Comments
 (0)