Check that "read-only" fields are writable when the IA32_VMX_MISC MSR reports that software can use VMWRITE to write to any supported field in the VMCS. Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx> Signed-off-by: Liran Alon <liran.alon@xxxxxxxxxx> --- lib/x86/msr.h | 3 +++ x86/vmx.c | 62 ++++++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 663bad034c0d..abf0d93bc58d 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -405,6 +405,9 @@ #define MSR_IA32_VMX_TRUE_EXIT 0x0000048f #define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 +/* MSR_IA32_VMX_MISC bits */ +#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29) + #define MSR_IA32_TSCDEADLINE 0x000006e0 /* AMD-V MSRs */ diff --git a/x86/vmx.c b/x86/vmx.c index aa04ac68dab5..f80b155c4dae 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -125,7 +125,7 @@ static struct vmcs_field vmcs_fields[] = { { MASK(64), APIC_ACCS_ADDR }, { MASK(64), EPTP }, - { 0 /* read-only */, INFO_PHYS_ADDR }, + { MASK(64), INFO_PHYS_ADDR }, { MASK(64), VMCS_LINK_PTR }, { MASK(64), GUEST_DEBUGCTL }, @@ -155,14 +155,14 @@ static struct vmcs_field vmcs_fields[] = { { MASK(32), TPR_THRESHOLD }, { MASK(32), CPU_EXEC_CTRL1 }, - { 0 /* read-only */, VMX_INST_ERROR }, - { 0 /* read-only */, EXI_REASON }, - { 0 /* read-only */, EXI_INTR_INFO }, - { 0 /* read-only */, EXI_INTR_ERROR }, - { 0 /* read-only */, IDT_VECT_INFO }, - { 0 /* read-only */, IDT_VECT_ERROR }, - { 0 /* read-only */, EXI_INST_LEN }, - { 0 /* read-only */, EXI_INST_INFO }, + { MASK(32), VMX_INST_ERROR }, + { MASK(32), EXI_REASON }, + { MASK(32), EXI_INTR_INFO }, + { MASK(32), EXI_INTR_ERROR }, + { MASK(32), IDT_VECT_INFO }, + { MASK(32), IDT_VECT_ERROR }, + { MASK(32), EXI_INST_LEN }, + { MASK(32), EXI_INST_INFO }, { MASK(32), GUEST_LIMIT_ES }, { MASK(32), GUEST_LIMIT_CS }, @@ -199,12 +199,12 @@ static struct vmcs_field vmcs_fields[] = { { MASK_NATURAL, CR3_TARGET_2 }, { MASK_NATURAL, CR3_TARGET_3 }, - { 0 /* read-only */, EXI_QUALIFICATION }, - { 0 /* read-only */, IO_RCX }, - { 0 /* read-only */, IO_RSI }, - { 0 /* read-only */, IO_RDI }, - { 0 /* read-only */, IO_RIP }, - { 0 /* read-only */, GUEST_LINEAR_ADDRESS }, + { MASK_NATURAL, EXI_QUALIFICATION }, + { MASK_NATURAL, IO_RCX }, + { MASK_NATURAL, IO_RSI }, + { MASK_NATURAL, IO_RDI }, + { MASK_NATURAL, IO_RIP }, + { MASK_NATURAL, GUEST_LINEAR_ADDRESS }, { MASK_NATURAL, GUEST_CR0 }, { MASK_NATURAL, GUEST_CR3 }, @@ -241,6 +241,28 @@ static struct vmcs_field vmcs_fields[] = { { MASK_NATURAL, HOST_RIP }, }; +enum vmcs_field_type { + VMCS_FIELD_TYPE_CONTROL = 0, + VMCS_FIELD_TYPE_READ_ONLY_DATA = 1, + VMCS_FIELD_TYPE_GUEST = 2, + VMCS_FIELD_TYPE_HOST = 3, + VMCS_FIELD_TYPES, +}; + +static inline int vmcs_field_type(struct vmcs_field *f) +{ + return (f->encoding >> VMCS_FIELD_TYPE_SHIFT) & 0x3; +} + +static int vmcs_field_readonly(struct vmcs_field *f) +{ + u64 ia32_vmx_misc; + + ia32_vmx_misc = rdmsr(MSR_IA32_VMX_MISC); + return !(ia32_vmx_misc & MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS) && + (vmcs_field_type(f) == VMCS_FIELD_TYPE_READ_ONLY_DATA); +} + static inline u64 vmcs_field_value(struct vmcs_field *f, u8 cookie) { u64 value; @@ -264,6 +286,16 @@ static bool check_vmcs_field(struct vmcs_field *f, u8 cookie) u64 actual; int ret; + if (f->encoding == VMX_INST_ERROR) { + printf("Skipping volatile field %lx\n", f->encoding); + return true; + } + + if (vmcs_field_readonly(f)) { + printf("Skipping read-only field %lx\n", f->encoding); + return true; + } + ret = vmcs_read_checking(f->encoding, &actual); assert(!(ret & X86_EFLAGS_CF)); /* Skip VMCS fields that aren't recognized by the CPU */ -- 1.9.1