diff --git a/sys/platform/pc64/x86_64/npx.c b/sys/platform/pc64/x86_64/npx.c --- a/sys/platform/pc64/x86_64/npx.c +++ b/sys/platform/pc64/x86_64/npx.c @@ -423,6 +423,33 @@ td->td_proc->p_comm, td->td_savefpu->sv_xmm.sv_env.en_mxcsr); } + /* + * Sanitize the XSAVE header that lives at byte offset 512 of + * the save area. The bytes were just bcopy()'d from user + * memory and are otherwise passed verbatim to XRSTOR, which + * raises #GP if XCOMP_BV has bit 63 set (compacted format) + * together with any bit not present in XCR0, or if XSTATE_BV + * has bits outside XCR0. A #GP inside npxdna()/npxdna_quick() + * runs at gd_intr_nesting_level > 0 and panics the kernel. + * Force the standard (non-compacted) XSAVE form by clearing + * XCOMP_BV, and restrict XSTATE_BV to features actually + * enabled in XCR0. + */ + if (cpu_xsave) { + struct xstate_hdr *hdr = + &td->td_savefpu->sv_ymm64.sv_xstate.sx_hd; + if ((hdr->xstate_bv & ~npx_xcr0_mask) || + hdr->xstate_xcomp_bv != 0) { + krateprintf(&badfprate, + "pid %d (%s) signal return from user: " + "illegal XSAVE header bv=%016llx xcomp=%016llx\n", + td->td_proc->p_pid, td->td_proc->p_comm, + (unsigned long long)hdr->xstate_bv, + (unsigned long long)hdr->xstate_xcomp_bv); + hdr->xstate_bv &= npx_xcr0_mask; + hdr->xstate_xcomp_bv = 0; + } + } td->td_flags |= TDF_USINGFP; break; }