Re: [PATCH v2] nSVM: Check injected event consistency

Teddy Astie <[email protected]>
Newsgroups org.xenproject.lists.xen-devel
Message-ID <1785247466.8631fc262581453bbf619ec5b2062170.19fa90a823a000e099@vates.tech>
Le 16/07/2026 à 17:41, Abdelkareem Abdelsaamad a écrit :
> On the AMD platforms, allowing a VMRUN instruction with a malformed VMCB has
> debugging complications, security and performance implications. The APM volume
> 2 15.20 [1] states two possibilities that result in a VMRUN exit with
> VMEXIT_INVALID due to injected events. These are either
> • Reserved values of TYPE have been specified.
> • TYPE = 3 (exception) has been specified with a vector that does not
>    correspond to an exception (this includes vector 2, which is an NMI, not
>    an exception).
> Extend the VMCB checks to check for such inconsistency.
> 
> The collection of the invalid exception vectors are picked from the upstream KVM
> commit ("7e79f71bca5c" KVM: nSVM: Add missing consistency check for EVENTINJ).
> 
> [1] https://docs.amd.com/v/u/en-US/24593_3.44_APM_Vol2
> 
> Signed-off-by: Abdelkareem Abdelsaamad <[email protected]>
> ---
> Changes in v2:
> - Remove the redundant SVM_EVENT_INJ_TYPE_MASK and SVM_EVENT_INJ_VEC_MASK
>    constants.
> - Correct the Injected Event Type consistency check to disallow the injection
>    of reserved type 1 events.
> ---
> Testing:
>   - Using a locally developed XTF nested virt setup, I manually tested VMRUN
>     instruction handling with a malformed VMCB:
>     1) Inject event with the type (7).
>        The hypervisor logs show the message
>        (XEN) [  645.155609] d2v0[nsvm_vmcb_prepare4vmrun]: eventinj: Invalid Injected
>              Event Type: (0x7)
>     2) Inject event with the exception value (3) and the vector value (2) for NMI.
>        The hypervisor logs show the message
>        (XEN) [  645.157277] d2v0[nsvm_vmcb_prepare4vmrun]: eventinj: Invalid Injected Event.
>               Exception type: (0x3), with a vector: (0x2) does not belong to an exception
> 
>   - CI tests:
> https://gitlab.com/xen-project/people/aabdelsa/xen/-/pipelines/2682300446
> ---
>   xen/arch/x86/hvm/svm/vmcb.c | 40 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 40 insertions(+)
> 
> diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
> index 975a1eaef8..c31d2a6f58 100644
> --- a/xen/arch/x86/hvm/svm/vmcb.c
> +++ b/xen/arch/x86/hvm/svm/vmcb.c
> @@ -320,6 +320,31 @@ void svm_vmcb_dump(const char *from, const struct vmcb_struct *vmcb)
>       svm_dump_sel("  TR", &vmcb->tr);
>   }
>   
> +static bool is_valid_svm_vmcb_injected_exception_vector(
> +    const struct vmcb_struct *vmcb, uint8_t vmcb_injected_vector)
> +{
> +    return ( (vmcb_injected_vector == X86_EXC_DE) ||
> +             (vmcb_injected_vector == X86_EXC_DB) ||
> +             (vmcb_injected_vector == X86_EXC_BP) ||
> +             (vmcb_injected_vector == X86_EXC_OF) ||
> +             (vmcb_injected_vector == X86_EXC_BR) ||

This particular exception is special. AMD APM states that this event is 
"impossible" if the guest is in 64-bit mode and will cause 
VMEXIT_INVALID in such case.

 > If the VMM attempts to inject an event that is impossible for the 
guest mode (e.g., a #BR exception when the guest is in 64-bit mode), the 
event injection will fail and no guest state instructions will be 
executed; VMRUN will immediately exit with an error code of VMEXIT_INVALID.

So this one likely want a additional check for hvm_guest_x86_mode() != 
X86_MODE_64BIT.

It looks like #OF has the same quirk (invalid in 64-bits mode).

Though I don't know if any other exception has a similar behavior though.

> +             (vmcb_injected_vector == X86_EXC_UD) ||
> +             (vmcb_injected_vector == X86_EXC_NM) ||
> +             (vmcb_injected_vector == X86_EXC_DF) ||
> +             (vmcb_injected_vector == X86_EXC_TS) ||
> +             (vmcb_injected_vector == X86_EXC_NP) ||
> +             (vmcb_injected_vector == X86_EXC_SS) ||
> +             (vmcb_injected_vector == X86_EXC_GP) ||
> +             (vmcb_injected_vector == X86_EXC_PF) ||
> +             (vmcb_injected_vector == X86_EXC_MF) ||
> +             (vmcb_injected_vector == X86_EXC_AC) ||
> +             (vmcb_injected_vector == X86_EXC_MC) ||
> +             (vmcb_injected_vector == X86_EXC_XM) ||
> +             (vmcb_injected_vector == X86_EXC_HV) ||
> +             (vmcb_injected_vector == X86_EXC_SX) ||
> +             (vmcb_get_sev_es(vmcb) && vmcb_injected_vector == X86_EXC_VC) );
> +}

I think using a switch here would help making things more readable, 
especially if we need to add additional comparisons in specific cases 
(SEV-ES for #VC, !64-bits for #BR and #OF, ...).

I have in mind something like

   switch (vmcb_injected_vector)
   {
   case X86_EXC_OF:
   case X86_EXC_BR:
       return hvm_guest_x86_mode(v) != X86_MODE_64BIT;

   (all other special cases, ...)

   case X86_EXC_UD:
   (all other simple cases ...)
       return true;

   default:
       return false;
   }

> +
>   bool svm_vmcb_isvalid(
>       const char *from, const struct vmcb_struct *vmcb, const struct vcpu *v,
>       bool verbose)
> @@ -330,6 +355,12 @@ bool svm_vmcb_isvalid(
>       unsigned long cr4 = vmcb_get_cr4(vmcb);
>       unsigned long valid;
>       uint64_t efer = vmcb_get_efer(vmcb);
> +    uint8_t vmcb_injected_type = vmcb->event_inj.type;
> +    uint8_t vmcb_injected_vector = vmcb->event_inj.vector;
> +    uint8_t vmcb_valid_event_inj_types_mask = (1 << X86_ET_EXT_INTR) |
> +                                              (1 << X86_ET_NMI) |
> +                                              (1 << X86_ET_HW_EXC) |
> +                                              (1 << X86_ET_SW_INT);
>   
>   #define PRINTF(fmt, args...) do { \
>       if ( !verbose ) return true; \
> @@ -392,6 +423,15 @@ bool svm_vmcb_isvalid(
>           PRINTF("eventinj: MBZ bits are set (%#"PRIx64")\n",
>                  vmcb->event_inj.raw);
>   
> +    if ( !((1 << vmcb_injected_type) & vmcb_valid_event_inj_types_mask) )
> +        PRINTF("eventinj: Invalid Injected Event Type: (%#"PRIx8")\n",
> +               vmcb_injected_type);
> +
> +    if ( (vmcb_injected_type == X86_ET_HW_EXC) &&
> +         !is_valid_svm_vmcb_injected_exception_vector(vmcb, vmcb_injected_vector) )
> +        PRINTF("eventinj: Invalid Injected Event. Exception type: (%#"PRIx8"),"
> +               " with a vector: (%#"PRIx8") does not belong to an exception\n",
> +               vmcb_injected_type, vmcb_injected_vector);
>   #undef PRINTF
>       return ret;
>   }

Teddy
OpenPGP_0x660FA9D102CBCFD0.asc (application/pgp-keys, 2.4 KB)
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
x9fhaZEsniw8/bYgC3igkk5YJiOa
=lUIA
-----END PGP PUBLIC KEY BLOCK-----
OpenPGP_signature.asc (application/pgp-signature, 665 B)
-----BEGIN PGP SIGNATURE-----

wsD5BAABCAAjFiEEGAIew9LzHY3pdrqtZg+p0QLLz9AFAmpotuQFAwAAAAAACgkQZg+p0QLLz9AC
KQv9FJ2Q7sxUL7m4nQYo7tErfaVWpbjIJTTA7IWbdbAoyHLeQxvVI3v/Rt1GMRzfrXW8FJRMkcQ0
CoCQB+J4JCO443hgPMcJW7clP7Kh9AU8zCIgtXtkn+n0+Swd+4mfnNcRWTbhjXbH5vHbzUjk2Xll
9Iao9zHc9j3ZSoFhYDhNvSQlLeTMgXmTKKr8eJa8EcVaO41X2sdiZriIc0tQuFwa6SBrAGzQ1eNx
JDfIkFn9nZ8Ra/hwiF+K9AYvTXEg4Bu8l1TfZi7HWjIGpK7NYwkHyKdBXb2MO0Llrhnnhn/+NVjA
WPvjSO9A1Wc2awNbrhEoXzAPVU7x9lnPnyb/MjqXuJsCk/n37QbuM9BrOfO+tA8RwjAa0/YwB3PK
esTXvXBc1D+8YvpeYYq78URznrwIfst2JGHvVGSODmfEgEvVLsP3tVdiNcOomK6Bvp/ImH1pz+I1
dpCd1976vs+5QQA6TZutMQI2YvSYwGmh2famAbnL3TcapgBhLNwad9HlSH/+
=wUoG
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.