Commit 986c6374 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 6485ac65 62faca1c
...@@ -1118,21 +1118,20 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, ...@@ -1118,21 +1118,20 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
zerofrom = offsetof(struct xregs_state, extended_state_area); zerofrom = offsetof(struct xregs_state, extended_state_area);
/* /*
* The ptrace buffer is in non-compacted XSAVE format. In * This 'mask' indicates which states to copy from fpstate.
* non-compacted format disabled features still occupy state space, * Those extended states that are not present in fpstate are
* but there is no state to copy from in the compacted * either disabled or initialized:
* init_fpstate. The gap tracking will zero these states. *
*/ * In non-compacted format, disabled features still occupy
mask = fpstate->user_xfeatures; * state space but there is no state to copy from in the
* compacted init_fpstate. The gap tracking will zero these
/* * states.
* Dynamic features are not present in init_fpstate. When they are *
* in an all zeros init state, remove those from 'mask' to zero * The extended features have an all zeroes init state. Thus,
* those features in the user buffer instead of retrieving them * remove them from 'mask' to zero those features in the user
* from init_fpstate. * buffer instead of retrieving them from init_fpstate.
*/ */
if (fpu_state_size_dynamic()) mask = header.xfeatures;
mask &= (header.xfeatures | xinit->header.xcomp_bv);
for_each_extended_xfeature(i, mask) { for_each_extended_xfeature(i, mask) {
/* /*
...@@ -1151,9 +1150,8 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate, ...@@ -1151,9 +1150,8 @@ void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
pkru.pkru = pkru_val; pkru.pkru = pkru_val;
membuf_write(&to, &pkru, sizeof(pkru)); membuf_write(&to, &pkru, sizeof(pkru));
} else { } else {
copy_feature(header.xfeatures & BIT_ULL(i), &to, membuf_write(&to,
__raw_xsave_addr(xsave, i), __raw_xsave_addr(xsave, i),
__raw_xsave_addr(xinit, i),
xstate_sizes[i]); xstate_sizes[i]);
} }
/* /*
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/kasan.h> #include <asm/kasan.h>
#include <asm/setup.h>
static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage); static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage);
...@@ -29,6 +30,12 @@ static __init void init_cea_offsets(void) ...@@ -29,6 +30,12 @@ static __init void init_cea_offsets(void)
unsigned int max_cea; unsigned int max_cea;
unsigned int i, j; 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; max_cea = (CPU_ENTRY_AREA_MAP_SIZE - PAGE_SIZE) / CPU_ENTRY_AREA_SIZE;
/* O(sodding terrible) */ /* O(sodding terrible) */
......
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
#include <sys/auxv.h> #include <sys/auxv.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/shm.h> #include <sys/shm.h>
#include <sys/ptrace.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/uio.h>
#include "../kselftest.h" /* For __cpuid_count() */ #include "../kselftest.h" /* For __cpuid_count() */
...@@ -583,6 +585,13 @@ static void test_dynamic_state(void) ...@@ -583,6 +585,13 @@ static void test_dynamic_state(void)
_exit(0); _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.' * Save current register state and compare it to @xbuf1.'
* *
...@@ -599,9 +608,7 @@ static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1) ...@@ -599,9 +608,7 @@ static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
fatal_error("failed to allocate XSAVE buffer\n"); fatal_error("failed to allocate XSAVE buffer\n");
xsave(xbuf2, XFEATURE_MASK_XTILEDATA); xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
ret = memcmp(&xbuf1->bytes[xtiledata.xbuf_offset], ret = __compare_tiledata_state(xbuf1, xbuf2);
&xbuf2->bytes[xtiledata.xbuf_offset],
xtiledata.size);
free(xbuf2); free(xbuf2);
...@@ -826,6 +833,99 @@ static void test_context_switch(void) ...@@ -826,6 +833,99 @@ static void test_context_switch(void)
free(finfo); 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) int main(void)
{ {
/* Check hardware availability at first */ /* Check hardware availability at first */
...@@ -846,6 +946,8 @@ int main(void) ...@@ -846,6 +946,8 @@ int main(void)
ctxtswtest_config.num_threads = 5; ctxtswtest_config.num_threads = 5;
test_context_switch(); test_context_switch();
test_ptrace();
clearhandler(SIGILL); clearhandler(SIGILL);
free_stashed_xsave(); free_stashed_xsave();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment