diff --git a/compel/arch/x86/src/lib/infect.c b/compel/arch/x86/src/lib/infect.c index d95299b3b..85c93ad8a 100644 --- a/compel/arch/x86/src/lib/infect.c +++ b/compel/arch/x86/src/lib/infect.c @@ -251,7 +251,7 @@ static int get_task_fpregs(pid_t pid, user_fpregs_struct_t *xsave) } int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, - void *arg, __maybe_unused unsigned long flags) + void *arg, unsigned long flags) { user_fpregs_struct_t xsave = { }, *xs = NULL; int ret = -1; @@ -286,14 +286,24 @@ int get_task_regs(pid_t pid, user_regs_struct_t *regs, save_regs_t save, pr_info("Dumping GP/FPU registers for %d\n", pid); - if (compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { - if (get_task_xsave(pid, &xsave)) - goto err; + if (!compel_cpu_has_feature(X86_FEATURE_OSXSAVE)) { + ret = get_task_fpregs(pid, &xsave); + } else if (unlikely(flags & INFECT_X86_PTRACE_MXCSR_BUG)) { + /* + * get_task_fpregs() will fill FP state, + * get_task_xsave() will overwrite rightly sse/mmx/etc + */ + pr_warn("Skylake xsave fpu bug workaround used\n"); + ret = get_task_fpregs(pid, &xsave); + if (!ret) + ret = get_task_xsave(pid, &xsave); } else { - if (get_task_fpregs(pid, &xsave)) - goto err; + ret = get_task_xsave(pid, &xsave); } + if (ret) + goto err; + xs = &xsave; out: ret = save(arg, regs, xs); diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index d9bf069b2..e0ff233e7 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -127,6 +127,8 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *); #define INFECT_FAIL_CONNECT 0x2 /* make parasite connect() fail */ #define INFECT_NO_BREAKPOINTS 0x4 /* no breakpoints in pie tracking */ #define INFECT_COMPATIBLE 0x8 /* can run parasite inside compat tasks */ +/* Workaround for ptrace bug on Skylake CPUs with kernels older than v4.14 */ +#define INFECT_X86_PTRACE_MXCSR_BUG 0x10 /* * There are several ways to describe a blob to compel diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index 1fd9142e5..267d3fa07 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -511,6 +511,8 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ictx->flags |= INFECT_NO_BREAKPOINTS; if (kdat.compat_cr) ictx->flags |= INFECT_COMPATIBLE; + if (kdat.x86_has_ptrace_fpu_xsave_bug) + ictx->flags |= INFECT_X86_PTRACE_MXCSR_BUG; ictx->log_fd = log_get_fd();