|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: Re: [PATCH] x86/nsvm: Fix L2 VINTR intercept merging when only Xen intercepts L1
On 11/5/6 16:16 PM, Ross Lagerwall wrote: >On 11/3/26 4:59 PM, Abdelkareem Abdelsaamad wrote: >> When nesting SVM, if the L1 hypervisor has not requested a virtual interrupt >> (VINTR) intercept for L2, Xen should not force one. L2 execution should >> remain >> isolated from the L1 VINTR state, and there should be no expectation that L2 >> execution results in an L1 VINTR becoming deliverable. >> >> Currently, if Xen intercepts the VINTR for its own L1 management, this >> intercept incorrectly forces an intercept during L2 execution even when L1 >> intended for L2 to run without it. This breaks the expected transparency of >> L1 >> configuration and introduces unnecessary VMEXITs. >> >> Furthermore, handling this forced VMEXIT_VINTR can cause a pending L1 virtual >> interrupt to be incorrectly delivered to L2. This occurs because when the >> intercept is determined to be requested solely by the host >> (returning NESTEDHVM_VMEXIT_HOST), svm_vmexit_handler does not switch to the >> correct VMCB context before evaluating the interrupt injection. >> >> Fix this by ensuring the L2 VINTR intercept bit in the L2 execution VMCB >> solely >> reflects the L1's explicit configuration for its guest, independent of Xen's >> internal L1 intercept state. >> >> Signed-off-by: Abdelkareem Abdelsaamad <abdelkareem.abdelsaamad@xxxxxxxxxx> >> --- >> Testing: >> - Test setup using a custom XTF nested virtualization setup: >> 1. An L1 maskable interrupt is triggered while L1 has physical interrupts >> disabled (via the CLI), leaving the interrupt pending. >> 2. L2 is launched via VMRUN with an active, deliverable virtual interrupt >> configured in its VMCB (L2 EFLAGS.IF = 1, L2 vGIF is unmasked, >> V_IRQ_PENDING is set and L2 V_IRQ is injected on a distinct vector >> from >> the pending L1 interrupt). >> 3. Xen enables L1's VINTR_INTERCEPT to catch the next available VINTR >> window. L2's VINTR_INTERCEPT is kept cleared. >> >> Results: >> - Old Behaviour: If the pending L1 maskable interrupt vector has no >> handler mapped in the L2 IDT, L2 immediately crashes. Otherwise, >> the L1 maskable interrupt is incorrectly leaked and delivered into >> the L2 guest. >> - New Behaviour: The L1 maskable interrupt is securely withheld from L2 >> and correctly delivered back to the L1 context upon the next window. >> >> Note on Test scenario: >> I think the same window race can also result when having an injected L1 >> maskable interrupt handler that temporarily raise the TPR to block >> lower-priority interrupts, with the intention to be lowering the TPR >> asynchronously later, then executing the L2 VMRUN in between. >> >> - CI tests: >> https://gitlab.com/xen-project/people/aabdelsa/xen/-/pipelines/3023453459 >> --- >> xen/arch/x86/hvm/svm/nestedsvm.c | 3 +++ >> 1 file changed, 3 insertions(+) >> >> diff --git a/xen/arch/x86/hvm/svm/nestedsvm.c >> b/xen/arch/x86/hvm/svm/nestedsvm.c >> index 128008321d..21b50a59b0 100644 >> --- a/xen/arch/x86/hvm/svm/nestedsvm.c >> +++ b/xen/arch/x86/hvm/svm/nestedsvm.c >> @@ -403,6 +403,9 @@ static int nsvm_vmcb_prepare4vmrun(struct vcpu *v, >> struct cpu_user_regs *regs) >> n2vmcb->_general2_intercepts = >> n1vmcb->_general2_intercepts | ns_vmcb->_general2_intercepts; >> >> + if ( !(ns_vmcb->_general1_intercepts & GENERAL1_INTERCEPT_VINTR) ) >> + n2vmcb->_general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR; >> + > >If L0 wants to inject an interrupt but the VINTR intercept is not enabled, how >would it detect when it can inject the interrupt? In particular, if VMCB(1-2) >has V_INTR_MASKING=0 and L2 sets EFLAGS.IF=1, the interrupt should be >delivered but L0 won't notice. I do not follow on this. My reading of the APM about the V_INTR_MASKING is that it is intended to decouple the control of the physical and the virtual interrupt's EFLAGS.IF. Specifically, when it is set, the host's EFLAGS.IF at the time of VMRUN determines whether maskable physical interrupts are masked or not. The host and guest values of EFLAGS.IF remain distinct. I f the L0 wants to detect L1's interrupt window is open, it checks against L1's EFLAGS. In the scenario when the L1 configured the L2 with EFLAGS.IF as enabled (1) but the L1 itself has EFLAGS.IF cleared (0) and so it is in interrupt shadow, and the L1 then runs the L2. My understanding is that the L2 should not be intercepted as nothing changed for the L1's state (L1's EFLAGS.IF remains cleared). Only when the L0 wants to detect that the L2's interrupt window is open, it explicitely intercepts the VMCB02 in svm_intr_assist->svm_enable_intr_window? Or do you mean that during nested runs, L0 needs to intercept when the virtual interrupt window opens to know when physical interrupts become deliverable— since from L2's perspective, L1's virtual interrupts act as physical interrupts? If the answer is yes, What VMEXIT should be injected back to L1? Is this VMEXIT_INTR?
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |