mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 22:35:33 +00:00
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>
This commit is contained in:
committed by
Andrei Vagin
parent
327e14933d
commit
e2e8be37f2
@@ -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;
|
||||
|
||||
/*
|
||||
|
@@ -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))
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -18,6 +18,7 @@ enum faults {
|
||||
FI_PARTIAL_PAGES = 131,
|
||||
FI_HUGE_ANON_SHMEM_ID = 132,
|
||||
FI_CANNOT_MAP_VDSO = 133,
|
||||
FI_CORRUPT_EXTREGS = 134,
|
||||
FI_MAX,
|
||||
};
|
||||
|
||||
|
@@ -575,6 +575,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
|
||||
ictx->flags |= INFECT_COMPATIBLE;
|
||||
if (kdat.x86_has_ptrace_fpu_xsave_bug)
|
||||
ictx->flags |= INFECT_X86_PTRACE_MXCSR_BUG;
|
||||
if (fault_injected(FI_CORRUPT_EXTREGS))
|
||||
ictx->flags |= INFECT_CORRUPT_EXTREGS;
|
||||
|
||||
ictx->log_fd = log_get_fd();
|
||||
|
||||
|
Reference in New Issue
Block a user