[PATCH] x86/svm: Always sync guest CR2 on VMExit

Andrew Cooper posted 1 patch 3 days, 11 hours ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/20260501213826.1291860-1-andrew.cooper3@citrix.com
xen/arch/x86/hvm/svm/svm.c | 1 +
1 file changed, 1 insertion(+)
[PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Andrew Cooper 3 days, 11 hours ago
Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
and one is in the VMCB.

Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
loads and saves the guest CR2 across VMRUN/VMExit.

For HAP guests (where #PF is not intercepted, and therefore we don't typically
inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
migration is cooperative and not done from the #PF handler, this also goes
unoticed by guests.

It also means that an emulated MOV-from-CR2 reads a stale value.

Reported-by: Stefano Stabellini <sstabellini@kernel.org>
Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <jbeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Teddy Astie <teddy.astie@vates.tech>
CC: Stefano Stabellini <sstabellini@kernel.org>

It also also works around the QEMU bug that triggered the investigion, where
the CR2 intercepts trigger despite Xen requesting CR2 not to be intercepted.
---
 xen/arch/x86/hvm/svm/svm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index ced616684732..f49d2ebbfdd5 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2505,6 +2505,7 @@ void asmlinkage svm_vmexit_handler(void)
     hvm_sanitize_regs_fields(
         regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l));
 
+    v->arch.hvm.guest_cr[2] = vmcb_get_cr2(vmcb);
     if ( paging_mode_hap(v->domain) )
         v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb);
 

base-commit: 61f957d48c78df6c5254b6f54d6170d3bd3d717e
-- 
2.39.5


Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Teddy Astie 20 hours ago
Le 01/05/2026 à 23:43, Andrew Cooper a écrit :
> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
> and one is in the VMCB.
> 
> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
> loads and saves the guest CR2 across VMRUN/VMExit.
> 
> For HAP guests (where #PF is not intercepted, and therefore we don't typically
> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
> migration is cooperative and not done from the #PF handler, this also goes
> unoticed by guests.
> 
> It also means that an emulated MOV-from-CR2 reads a stale value.
> 
> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Roger Pau Monné <roger.pau@citrix.com>
> CC: Teddy Astie <teddy.astie@vates.tech>
> CC: Stefano Stabellini <sstabellini@kernel.org>
> 
> It also also works around the QEMU bug that triggered the investigion, where
> the CR2 intercepts trigger despite Xen requesting CR2 not to be intercepted.
> ---
>   xen/arch/x86/hvm/svm/svm.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index ced616684732..f49d2ebbfdd5 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -2505,6 +2505,7 @@ void asmlinkage svm_vmexit_handler(void)
>       hvm_sanitize_regs_fields(
>           regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l));
>   
> +    v->arch.hvm.guest_cr[2] = vmcb_get_cr2(vmcb);
>       if ( paging_mode_hap(v->domain) )
>           v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb);
>   
> 
> base-commit: 61f957d48c78df6c5254b6f54d6170d3bd3d717e

Reviewed-by: Teddy Astie <teddy.astie@vates.tech>


-- 
 | Vates 

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech
Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Stefano Stabellini 3 days, 11 hours ago
On Fri, 1 May 2026, Andrew Cooper wrote:
> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
> and one is in the VMCB.
> 
> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
> loads and saves the guest CR2 across VMRUN/VMExit.
> 
> For HAP guests (where #PF is not intercepted, and therefore we don't typically
> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
> migration is cooperative and not done from the #PF handler, this also goes
> unoticed by guests.
> 
> It also means that an emulated MOV-from-CR2 reads a stale value.
> 
> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Tested-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Roger Pau Monné <roger.pau@citrix.com>
> CC: Teddy Astie <teddy.astie@vates.tech>
> CC: Stefano Stabellini <sstabellini@kernel.org>
> 
> It also also works around the QEMU bug that triggered the investigion, where
> the CR2 intercepts trigger despite Xen requesting CR2 not to be intercepted.
> ---
>  xen/arch/x86/hvm/svm/svm.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index ced616684732..f49d2ebbfdd5 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -2505,6 +2505,7 @@ void asmlinkage svm_vmexit_handler(void)
>      hvm_sanitize_regs_fields(
>          regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l));
>  
> +    v->arch.hvm.guest_cr[2] = vmcb_get_cr2(vmcb);
>      if ( paging_mode_hap(v->domain) )
>          v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb);
>  
> 
> base-commit: 61f957d48c78df6c5254b6f54d6170d3bd3d717e
> -- 
> 2.39.5
> 
Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Andrew Cooper 3 days, 10 hours ago
On 01/05/2026 10:44 pm, Stefano Stabellini wrote:
> On Fri, 1 May 2026, Andrew Cooper wrote:
>> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
>> and one is in the VMCB.
>>
>> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
>> loads and saves the guest CR2 across VMRUN/VMExit.
>>
>> For HAP guests (where #PF is not intercepted, and therefore we don't typically
>> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
>> migration is cooperative and not done from the #PF handler, this also goes
>> unoticed by guests.
>>
>> It also means that an emulated MOV-from-CR2 reads a stale value.
>>
>> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
>> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> Tested-by: Stefano Stabellini <sstabellini@kernel.org>

Thanks, sadly I made the mistake of extending my XTF PoC for this.

There are also bugs on the emulated MOV-to-CR2 side, and they're far
harder to untangle.

This patch probably wants to go in in this form, accepting that there
are issues still to be addressed on the other side.

~Andrew
Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Jan Beulich 1 day, 3 hours ago
On 02.05.2026 00:21, Andrew Cooper wrote:
> On 01/05/2026 10:44 pm, Stefano Stabellini wrote:
>> On Fri, 1 May 2026, Andrew Cooper wrote:
>>> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
>>> and one is in the VMCB.
>>>
>>> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
>>> loads and saves the guest CR2 across VMRUN/VMExit.
>>>
>>> For HAP guests (where #PF is not intercepted, and therefore we don't typically
>>> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
>>> migration is cooperative and not done from the #PF handler, this also goes
>>> unoticed by guests.
>>>
>>> It also means that an emulated MOV-from-CR2 reads a stale value.
>>>
>>> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
>>> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> Tested-by: Stefano Stabellini <sstabellini@kernel.org>
> 
> Thanks, sadly I made the mistake of extending my XTF PoC for this.
> 
> There are also bugs on the emulated MOV-to-CR2 side, and they're far
> harder to untangle.

Any slightly closer details as to what?

> This patch probably wants to go in in this form, accepting that there
> are issues still to be addressed on the other side.

I agree:
Reviewed-by: Jan Beulich <jbeulich@suse.com>

Jan
Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Andrew Cooper 16 hours ago
On 04/05/2026 6:14 am, Jan Beulich wrote:
> On 02.05.2026 00:21, Andrew Cooper wrote:
>> On 01/05/2026 10:44 pm, Stefano Stabellini wrote:
>>> On Fri, 1 May 2026, Andrew Cooper wrote:
>>>> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
>>>> and one is in the VMCB.
>>>>
>>>> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
>>>> loads and saves the guest CR2 across VMRUN/VMExit.
>>>>
>>>> For HAP guests (where #PF is not intercepted, and therefore we don't typically
>>>> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
>>>> migration is cooperative and not done from the #PF handler, this also goes
>>>> unoticed by guests.
>>>>
>>>> It also means that an emulated MOV-from-CR2 reads a stale value.
>>>>
>>>> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
>>>> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>> Tested-by: Stefano Stabellini <sstabellini@kernel.org>
>> Thanks, sadly I made the mistake of extending my XTF PoC for this.
>>
>> There are also bugs on the emulated MOV-to-CR2 side, and they're far
>> harder to untangle.
> Any slightly closer details as to what?

hvmemul_write_cr() updates guest_cr[2] but doesn't sync it into the
VMCB.  This doesn't show up on Intel because CR2 is switched explicitly
in RAX across VMEntry/exit.

But, it's not the only problem path.

svm_vmexit_do_cr_access() is the fasthpath exit for CR intercepts when
decode assists are available.  hvm_mov_to_cr() and hvm_mov_from_cr() are
asymmetric in their handling of CR2.  mov_from will read from
guest_cr[2] but mov_to will domain crash.

However, case 2 ought to be unreachable in hvm_mov_from_cr() because of
how we program the intercepts, yet the QEMU bug which caused this to get
noticed will trigger an ASSERT() if I were to put one in.

So, do I fix up both to account for the fact we know QEMU is buggy with
intercepts?

>
>> This patch probably wants to go in in this form, accepting that there
>> are issues still to be addressed on the other side.
> I agree:
> Reviewed-by: Jan Beulich <jbeulich@suse.com>

Thanks.

~Andrew

Re: [PATCH] x86/svm: Always sync guest CR2 on VMExit
Posted by Jan Beulich 2 hours ago
On 04.05.2026 18:24, Andrew Cooper wrote:
> On 04/05/2026 6:14 am, Jan Beulich wrote:
>> On 02.05.2026 00:21, Andrew Cooper wrote:
>>> On 01/05/2026 10:44 pm, Stefano Stabellini wrote:
>>>> On Fri, 1 May 2026, Andrew Cooper wrote:
>>>>> Under SVM, there are two copies of guest CR2.  One is v->arch.hvm.guest_cr[2]
>>>>> and one is in the VMCB.
>>>>>
>>>>> Xen doesn't intercept CR2 accesses, so this mostly goes unnoticed; hardware
>>>>> loads and saves the guest CR2 across VMRUN/VMExit.
>>>>>
>>>>> For HAP guests (where #PF is not intercepted, and therefore we don't typically
>>>>> inject #PF either), this causes the guest CR2 value to be lost on migrate.  As
>>>>> migration is cooperative and not done from the #PF handler, this also goes
>>>>> unoticed by guests.
>>>>>
>>>>> It also means that an emulated MOV-from-CR2 reads a stale value.
>>>>>
>>>>> Reported-by: Stefano Stabellini <sstabellini@kernel.org>
>>>>> Fixes: d1bd157fbc9b ("Big merge the HVM full-virtualisation abstractions.")
>>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>>> Tested-by: Stefano Stabellini <sstabellini@kernel.org>
>>> Thanks, sadly I made the mistake of extending my XTF PoC for this.
>>>
>>> There are also bugs on the emulated MOV-to-CR2 side, and they're far
>>> harder to untangle.
>> Any slightly closer details as to what?
> 
> hvmemul_write_cr() updates guest_cr[2] but doesn't sync it into the
> VMCB.  This doesn't show up on Intel because CR2 is switched explicitly
> in RAX across VMEntry/exit.
> 
> But, it's not the only problem path.
> 
> svm_vmexit_do_cr_access() is the fasthpath exit for CR intercepts when
> decode assists are available.  hvm_mov_to_cr() and hvm_mov_from_cr() are
> asymmetric in their handling of CR2.  mov_from will read from
> guest_cr[2] but mov_to will domain crash.
> 
> However, case 2 ought to be unreachable in hvm_mov_from_cr() because of
> how we program the intercepts, yet the QEMU bug which caused this to get
> noticed will trigger an ASSERT() if I were to put one in.
> 
> So, do I fix up both to account for the fact we know QEMU is buggy with
> intercepts?

I think that's going to be (about) the best we can do.

Jan