- 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmQgPFAACgkQEsHwGGHe VUrAfA//QyZE5JnH0Ber3upRlZ/dPSNKIaOX6DMLshGj7QDqs2utTnjc4pwaqGWD OWpPuAJvOo2+NsN4nfB12venasIzseXDBBhEw6a5kYx73QmFbZ4XswFBLl2Eh8we cFbqU4B8SQvFQaahZ4kRRHpsmNGEPYRvgh2lBjcKUJBUaCuu6KoqE9+I3t173Obc sPfkXmhintDjYIjKfllN78rsBq4uCCaOVu5u299ZFMdBakRtx0M7U3547+4hwoE3 txP+VK+TPs8e64XJtCTem1br8HXNt/W5pC4IoQPnH8V+FLhUp1iIz6FpVHnJ7VMD 9c8VL7e8BNXhKkQn8sSkSVUZV3xNP7n4MbKKbba3f6EWPZnI28WQ3w09LUte/1aa hHEHyjMVyJfUiAcfuE1gZflG1+TqT8GkQJ+hqG9+/iSCWftOMuhfsKCROCLGhltJ yYBoyR2ZC1ErSLIOvgYAEUIeZ9FkzreOU0Pit6P/5qaPu+EXw3uDzoZB0WQH40Z5 PQwz04/s3idPwbfCZDOyNc7QZwxbGu1ESkdiTtCJmbBLW0MkWiBCnf/qZsK7PdD1 Q2qmx86ewIo6QipJpGK9pqWuzwFYNEJJHn3P7T1CcYQnQb+61m+b6WeYozQCgyMF 0dII6JulW98/WzjVgH6zUA0a0dicO7FM9H6iEGqlIcvxv0PuM7M= =eZTj -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
986c63741d
@ -1118,21 +1118,20 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
|
||||
zerofrom = offsetof(struct xregs_state, extended_state_area);
|
||||
|
||||
/*
|
||||
* The ptrace buffer is in non-compacted XSAVE format. In
|
||||
* non-compacted format disabled features still occupy state space,
|
||||
* but there is no state to copy from in the compacted
|
||||
* init_fpstate. The gap tracking will zero these states.
|
||||
* This 'mask' indicates which states to copy from fpstate.
|
||||
* Those extended states that are not present in fpstate are
|
||||
* either disabled or initialized:
|
||||
*
|
||||
* In non-compacted format, disabled features still occupy
|
||||
* state space but there is no state to copy from in the
|
||||
* compacted init_fpstate. The gap tracking will zero these
|
||||
* states.
|
||||
*
|
||||
* The extended features have an all zeroes init state. Thus,
|
||||
* remove them from 'mask' to zero those features in the user
|
||||
* buffer instead of retrieving them from init_fpstate.
|
||||
*/
|
||||
mask = fpstate->user_xfeatures;
|
||||
|
||||
/*
|
||||
* Dynamic features are not present in init_fpstate. When they are
|
||||
* in an all zeros init state, remove those from 'mask' to zero
|
||||
* those features in the user buffer instead of retrieving them
|
||||
* from init_fpstate.
|
||||
*/
|
||||
if (fpu_state_size_dynamic())
|
||||
mask &= (header.xfeatures | xinit->header.xcomp_bv);
|
||||
mask = header.xfeatures;
|
||||
|
||||
for_each_extended_xfeature(i, mask) {
|
||||
/*
|
||||
@ -1151,9 +1150,8 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
|
||||
pkru.pkru = pkru_val;
|
||||
membuf_write(&to, &pkru, sizeof(pkru));
|
||||
} else {
|
||||
copy_feature(header.xfeatures & BIT_ULL(i), &to,
|
||||
membuf_write(&to,
|
||||
__raw_xsave_addr(xsave, i),
|
||||
__raw_xsave_addr(xinit, i),
|
||||
xstate_sizes[i]);
|
||||
}
|
||||
/*
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/kasan.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage);
|
||||
|
||||
@ -29,6 +30,12 @@ static __init void init_cea_offsets(void)
|
||||
unsigned int max_cea;
|
||||
unsigned int i, j;
|
||||
|
||||
if (!kaslr_enabled()) {
|
||||
for_each_possible_cpu(i)
|
||||
per_cpu(_cea_offset, i) = i;
|
||||
return;
|
||||
}
|
||||
|
||||
max_cea = (CPU_ENTRY_AREA_MAP_SIZE - PAGE_SIZE) / CPU_ENTRY_AREA_SIZE;
|
||||
|
||||
/* O(sodding terrible) */
|
||||
|
@ -14,8 +14,10 @@
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "../kselftest.h" /* For __cpuid_count() */
|
||||
|
||||
@ -583,6 +585,13 @@ static void test_dynamic_state(void)
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2)
|
||||
{
|
||||
return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
|
||||
&xbuf2->bytes[xtiledata.xbuf_offset],
|
||||
xtiledata.size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save current register state and compare it to @xbuf1.'
|
||||
*
|
||||
@ -599,9 +608,7 @@ static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
|
||||
fatal_error("failed to allocate XSAVE buffer\n");
|
||||
|
||||
xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
|
||||
ret = memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
|
||||
&xbuf2->bytes[xtiledata.xbuf_offset],
|
||||
xtiledata.size);
|
||||
ret = __compare_tiledata_state(xbuf1, xbuf2);
|
||||
|
||||
free(xbuf2);
|
||||
|
||||
@ -826,6 +833,99 @@ static void test_context_switch(void)
|
||||
free(finfo);
|
||||
}
|
||||
|
||||
/* Ptrace test */
|
||||
|
||||
/*
|
||||
* Make sure the ptracee has the expanded kernel buffer on the first
|
||||
* use. Then, initialize the state before performing the state
|
||||
* injection from the ptracer.
|
||||
*/
|
||||
static inline void ptracee_firstuse_tiledata(void)
|
||||
{
|
||||
load_rand_tiledata(stashed_xsave);
|
||||
init_xtiledata();
|
||||
}
|
||||
|
||||
/*
|
||||
* Ptracer injects the randomized tile data state. It also reads
|
||||
* before and after that, which will execute the kernel's state copy
|
||||
* functions. So, the tester is advised to double-check any emitted
|
||||
* kernel messages.
|
||||
*/
|
||||
static void ptracer_inject_tiledata(pid_t target)
|
||||
{
|
||||
struct xsave_buffer *xbuf;
|
||||
struct iovec iov;
|
||||
|
||||
xbuf = alloc_xbuf();
|
||||
if (!xbuf)
|
||||
fatal_error("unable to allocate XSAVE buffer");
|
||||
|
||||
printf("\tRead the init'ed tiledata via ptrace().\n");
|
||||
|
||||
iov.iov_base = xbuf;
|
||||
iov.iov_len = xbuf_size;
|
||||
|
||||
memset(stashed_xsave, 0, xbuf_size);
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
|
||||
fatal_error("PTRACE_GETREGSET");
|
||||
|
||||
if (!__compare_tiledata_state(stashed_xsave, xbuf))
|
||||
printf("[OK]\tThe init'ed tiledata was read from ptracee.\n");
|
||||
else
|
||||
printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n");
|
||||
|
||||
printf("\tInject tiledata via ptrace().\n");
|
||||
|
||||
load_rand_tiledata(xbuf);
|
||||
|
||||
memcpy(&stashed_xsave->bytes[xtiledata.xbuf_offset],
|
||||
&xbuf->bytes[xtiledata.xbuf_offset],
|
||||
xtiledata.size);
|
||||
|
||||
if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
|
||||
fatal_error("PTRACE_SETREGSET");
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
|
||||
fatal_error("PTRACE_GETREGSET");
|
||||
|
||||
if (!__compare_tiledata_state(stashed_xsave, xbuf))
|
||||
printf("[OK]\tTiledata was correctly written to ptracee.\n");
|
||||
else
|
||||
printf("[FAIL]\tTiledata was not correctly written to ptracee.\n");
|
||||
}
|
||||
|
||||
static void test_ptrace(void)
|
||||
{
|
||||
pid_t child;
|
||||
int status;
|
||||
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
err(1, "fork");
|
||||
} else if (!child) {
|
||||
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL))
|
||||
err(1, "PTRACE_TRACEME");
|
||||
|
||||
ptracee_firstuse_tiledata();
|
||||
|
||||
raise(SIGTRAP);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
do {
|
||||
wait(&status);
|
||||
} while (WSTOPSIG(status) != SIGTRAP);
|
||||
|
||||
ptracer_inject_tiledata(child);
|
||||
|
||||
ptrace(PTRACE_DETACH, child, NULL, NULL);
|
||||
wait(&status);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
||||
err(1, "ptrace test");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Check hardware availability at first */
|
||||
@ -846,6 +946,8 @@ int main(void)
|
||||
ctxtswtest_config.num_threads = 5;
|
||||
test_context_switch();
|
||||
|
||||
test_ptrace();
|
||||
|
||||
clearhandler(SIGILL);
|
||||
free_stashed_xsave();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user