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

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
Loading
Loading
Loading
Loading
+14 −16
Original line number Diff line number Diff line
@@ -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.
	 */
	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.
	 * 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.
	 */
	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]);
		}
		/*
+7 −0
Original line number Diff line number Diff line
@@ -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) */
+105 −3
Original line number Diff line number Diff line
@@ -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();