Skip to content

Commit 986c637

Browse files
committed
Merge tag 'x86_urgent_for_v6.3_rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Borislav Petkov: - Add a AMX ptrace self test - Prevent a false-positive warning when retrieving the (invalid) address of dynamic FPU features in their init state which are not saved in init_fpstate at all - Randomize per-CPU entry areas only when KASLR is enabled * tag 'x86_urgent_for_v6.3_rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: selftests/x86/amx: Add a ptrace test x86/fpu/xstate: Prevent false-positive warning in __copy_xstate_uabi_buf() x86/mm: Do not shuffle CPU entry areas without KASLR
2 parents 6485ac6 + 62faca1 commit 986c637

File tree

3 files changed

+126
-19
lines changed

3 files changed

+126
-19
lines changed

arch/x86/kernel/fpu/xstate.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,21 +1118,20 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
11181118
zerofrom = offsetof(struct xregs_state, extended_state_area);
11191119

11201120
/*
1121-
* The ptrace buffer is in non-compacted XSAVE format. In
1122-
* non-compacted format disabled features still occupy state space,
1123-
* but there is no state to copy from in the compacted
1124-
* init_fpstate. The gap tracking will zero these states.
1125-
*/
1126-
mask = fpstate->user_xfeatures;
1127-
1128-
/*
1129-
* Dynamic features are not present in init_fpstate. When they are
1130-
* in an all zeros init state, remove those from 'mask' to zero
1131-
* those features in the user buffer instead of retrieving them
1132-
* from init_fpstate.
1121+
* This 'mask' indicates which states to copy from fpstate.
1122+
* Those extended states that are not present in fpstate are
1123+
* either disabled or initialized:
1124+
*
1125+
* In non-compacted format, disabled features still occupy
1126+
* state space but there is no state to copy from in the
1127+
* compacted init_fpstate. The gap tracking will zero these
1128+
* states.
1129+
*
1130+
* The extended features have an all zeroes init state. Thus,
1131+
* remove them from 'mask' to zero those features in the user
1132+
* buffer instead of retrieving them from init_fpstate.
11331133
*/
1134-
if (fpu_state_size_dynamic())
1135-
mask &= (header.xfeatures | xinit->header.xcomp_bv);
1134+
mask = header.xfeatures;
11361135

11371136
for_each_extended_xfeature(i, mask) {
11381137
/*
@@ -1151,9 +1150,8 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
11511150
pkru.pkru = pkru_val;
11521151
membuf_write(&to, &pkru, sizeof(pkru));
11531152
} else {
1154-
copy_feature(header.xfeatures & BIT_ULL(i), &to,
1153+
membuf_write(&to,
11551154
__raw_xsave_addr(xsave, i),
1156-
__raw_xsave_addr(xinit, i),
11571155
xstate_sizes[i]);
11581156
}
11591157
/*

arch/x86/mm/cpu_entry_area.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <asm/fixmap.h>
1111
#include <asm/desc.h>
1212
#include <asm/kasan.h>
13+
#include <asm/setup.h>
1314

1415
static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage);
1516

@@ -29,6 +30,12 @@ static __init void init_cea_offsets(void)
2930
unsigned int max_cea;
3031
unsigned int i, j;
3132

33+
if (!kaslr_enabled()) {
34+
for_each_possible_cpu(i)
35+
per_cpu(_cea_offset, i) = i;
36+
return;
37+
}
38+
3239
max_cea = (CPU_ENTRY_AREA_MAP_SIZE - PAGE_SIZE) / CPU_ENTRY_AREA_SIZE;
3340

3441
/* O(sodding terrible) */

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)