Hypervisor crash due to missing exception recovery on XRSTOR

Processors do certain validity checks on the data passed to XRSTOR. While the hypervisor controls the placement of that memory block, it doesn’t restrict the contents in any way. Thus the hypervisor exposes itself to a fault occurring on XRSTOR. Other than for FXRSTOR, which behaves similarly, there was no exception recovery code attached to XRSTOR.

improper error handling (missing exception recovery)



x86/xsave: recover from faults on XRSTOR

Just like FXRSTOR, XRSTOR can raise #GP if bad content is being passed to it in the memory block (i.e. aspects not under the control of the hypervisor, other than e.g. proper alignment of the block).

Also correct the comment explaining why FXRSTOR needs exception recovery code to not wrongly state that this can only be a result of the control tools passing a bad image.

--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -93,10 +93,25 @@ void xrstor(struct vcpu *v, uint64_t mas
                        "fildl %0"          /* load to clear state */
                        : : "m" (ptr->fpu_sse) );
-    asm volatile (
-        ".byte " REX_PREFIX "0x0f,0xae,0x2f"
-        :
-        : "m" (*ptr), "a" (lmask), "d" (hmask), "D"(ptr) );
+    /*
+     * XRSTOR can fault if passed a corrupted data block. We handle this
+     * possibility, which may occur if the block was passed to us by control
+     * tools or through VCPUOP_initialise, by silently clearing the block.
+     */
+    asm volatile ( "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+                   ".section .fixup,\"ax\"\n"
+                   "2: mov %5,%%ecx       \n"
+                   "   xor %1,%1          \n"
+                   "   rep stosb          \n"
+                   "   lea %2,%0          \n"
+                   "   mov %3,%1          \n"
+                   "   jmp 1b             \n"
+                   ".previous             \n"
+                   _ASM_EXTABLE(1b, 2b)
+                   : "+&D" (ptr), "+&a" (lmask)
+                   : "m" (*ptr), "g" (lmask), "d" (hmask),
+                     "m" (xsave_cntxt_size)
+                   : "ecx" );


Malicious or buggy unprivileged user space can cause the entire host to crash.