2
0
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:
Dmitry Safonov
2021-02-25 19:57:10 +00:00
committed by Andrei Vagin
parent 327e14933d
commit e2e8be37f2
6 changed files with 87 additions and 3 deletions

View File

@@ -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;
/*

View File

@@ -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))

View File

@@ -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;

View File

@@ -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

View File

@@ -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,
};

View File

@@ -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();