diff options
author | Dmitry Safonov <dima@arista.com> | 2021-02-25 22:57:10 +0300 |
---|---|---|
committer | Andrei Vagin <avagin@gmail.com> | 2021-09-03 20:31:00 +0300 |
commit | e2e8be37f22b2fb4623af3bec844cf5a98e823c1 (patch) | |
tree | d3012c0a0dd829dc1a17229f7328e5cec4550f18 /compel | |
parent | 327e14933d6b2391d0e3d0790e6556216a7d9ebb (diff) |
x86/compel/fault-inject: Add a fault-injection for corrupting extended regset
With pseudo-random garbage, the seed is printed with pr_err().
get_task_regs() is called during seizing the task and also for each
thread.
At this moment only for x86.
Signed-off-by: Dmitry Safonov <dima@arista.com>
Diffstat (limited to 'compel')
-rw-r--r-- | compel/arch/x86/src/lib/cpu.c | 2 | ||||
-rw-r--r-- | compel/arch/x86/src/lib/include/uapi/asm/fpu.h | 4 | ||||
-rw-r--r-- | compel/arch/x86/src/lib/infect.c | 79 | ||||
-rw-r--r-- | compel/include/uapi/infect.h | 2 |
4 files changed, 84 insertions, 3 deletions
diff --git a/compel/arch/x86/src/lib/cpu.c b/compel/arch/x86/src/lib/cpu.c index 617512167..c96f01353 100644 --- a/compel/arch/x86/src/lib/cpu.c +++ b/compel/arch/x86/src/lib/cpu.c @@ -125,7 +125,7 @@ static int compel_fpuid(compel_cpuinfo_t *c) c->xfeatures_mask &= ~(1 << i); } - c->xfeatures_mask &= XCNTXT_MASK; + c->xfeatures_mask &= XFEATURE_MASK_USER; c->xfeatures_mask &= ~XFEATURE_MASK_SUPERVISOR; /* diff --git a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h index 4ff531fb9..8985ad7f6 100644 --- a/compel/arch/x86/src/lib/include/uapi/asm/fpu.h +++ b/compel/arch/x86/src/lib/include/uapi/asm/fpu.h @@ -76,7 +76,7 @@ enum xfeature { #define XFEATURE_MASK_SUPERVISOR (XFEATURE_MASK_PT | XFEATURE_HDC) /* All currently supported features */ -#define XCNTXT_MASK \ +#define XFEATURE_MASK_USER \ (XFEATURE_MASK_FP | XFEATURE_MASK_SSE | \ XFEATURE_MASK_YMM | XFEATURE_MASK_OPMASK | \ XFEATURE_MASK_ZMM_Hi256 | XFEATURE_MASK_Hi16_ZMM | \ @@ -232,7 +232,7 @@ struct pkru_state { * can vary quite a bit between CPUs. * * - * One page should be enough for the whole xsave state. + * One page should be enough for the whole xsave state ;-) */ #define EXTENDED_STATE_AREA_SIZE (4096 - sizeof(struct i387_fxsave_struct) - sizeof(struct xsave_hdr_struct)) diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index 9c4abb60c..401001942 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -4,6 +4,8 @@ #include <sys/mman.h> #include <sys/user.h> #include <errno.h> +#include <stdlib.h> +#include <time.h> #include <compel/asm/fpu.h> @@ -258,6 +260,80 @@ static int get_task_fpregs(pid_t pid, user_fpregs_struct_t *xsave) return 0; } +/* See arch/x86/kernel/fpu/xstate.c */ +static void validate_random_xstate(struct xsave_struct *xsave) +{ + struct xsave_hdr_struct *hdr = &xsave->xsave_hdr; + unsigned int i; + + /* No unknown or supervisor features may be set */ + hdr->xstate_bv &= XFEATURE_MASK_USER; + hdr->xstate_bv &= ~XFEATURE_MASK_SUPERVISOR; + + for (i = 0; i < XFEATURE_MAX; i++) { + if (!compel_fpu_has_feature(i)) + hdr->xstate_bv &= ~(1 << i); + } + + /* Userspace must use the uncompacted format */ + hdr->xcomp_bv = 0; + + /* + * If 'reserved' is shrunken to add a new field, make sure to validate + * that new field here! + */ + BUILD_BUG_ON(sizeof(hdr->reserved) != 48); + + /* No reserved bits may be set */ + memset(&hdr->reserved, 0, sizeof(hdr->reserved)); +} + +/* + * TODO: Put fault-injection under CONFIG_* and move + * extended regset corruption to generic code + */ +static int corrupt_extregs(pid_t pid) +{ + bool use_xsave = compel_cpu_has_feature(X86_FEATURE_OSXSAVE); + user_fpregs_struct_t ext_regs; + int *rand_to = (int *)&ext_regs; + unsigned int seed; + size_t i; + + seed = time(NULL); + for (i = 0; i < sizeof(ext_regs) / sizeof(int); i++) + *rand_to++ = rand_r(&seed); + + /* + * Error log-level as: + * - not intended to be used outside of testing, + * - zdtm.py will grep it auto-magically from logs + * (and the seed will be known from an automatical testing) + */ + pr_err("Corrupting %s for %d, seed %u\n", + use_xsave ? "xsave" : "fpuregs", pid, seed); + + if (!use_xsave) { + if (ptrace(PTRACE_SETFPREGS, pid, NULL, &ext_regs)) { + pr_perror("Can't set FPU registers for %d", pid); + return -1; + } + } else { + struct iovec iov; + + validate_random_xstate((void *)&ext_regs); + + iov.iov_base = &ext_regs; + iov.iov_len = sizeof(ext_regs); + + if (ptrace(PTRACE_SETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) { + pr_perror("Can't set xstate for %d", pid); + return -1; + } + } + return 0; +} + int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, void *arg, unsigned long flags) { @@ -309,6 +385,9 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, ret = get_task_xsave(pid, &xsave); } + if (!ret && unlikely(flags & INFECT_CORRUPT_EXTREGS)) + ret = corrupt_extregs(pid); + if (ret) goto err; diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index fa326eafe..6cf3daf46 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -136,6 +136,8 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_COMPATIBLE (1UL << 3) /* Workaround for ptrace bug on Skylake CPUs with kernels older than v4.14 */ #define INFECT_X86_PTRACE_MXCSR_BUG (1UL << 4) +/* After infecting - corrupt extended registers (fault-injection) */ +#define INFECT_CORRUPT_EXTREGS (1UL << 5) /* * There are several ways to describe a blob to compel |