hv: nested: Keep privilege bits sync in shadow EPT entry

Guest may not use INVEPT instruction after enabling any of bits 2:0 from
0 to 1 of a present EPT entry, then the shadow EPT entry has no chance
to sync guest EPT entry. According to the SDM,
"""
Software may use the INVEPT instruction after modifying a present EPT
paging-structure entry (see Section 28.2.2) to change any of the
privilege bits 2:0 from 0 to 1.1 Failure to do so may cause an EPT
violation that would not otherwise occur. Because an EPT violation
invalidates any mappings that would be used by the access that caused
the EPT violation (see Section 28.3.3.1), an EPT violation will not
recur if the original access is performed again, even if the INVEPT
instruction is not executed.
"""

Sync the afterthought of privilege bits from guest EPT entry to shadow
EPT entry to cover above case.

Tracked-On: #5923
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Shuo A Liu 2021-06-28 11:56:28 +08:00 committed by wenlingz
parent a431cff94e
commit 9c1caad25a

View File

@ -438,6 +438,23 @@ bool handle_l2_ept_violation(struct acrn_vcpu *vcpu)
}
}
/*
* SDM 28.3.3.4 Guidelines for Use of the INVEPT Instruction:
* Software may use the INVEPT instruction after modifying a present EPT
* paging-structure entry (see Section 28.2.2) to change any of the
* privilege bits 2:0 from 0 to 1. Failure to do so may cause an EPT
* violation that would not otherwise occur. Because an EPT violation
* invalidates any mappings that would be used by the access that caused
* the EPT violation (see Section 28.3.3.1), an EPT violation will not
* recur if the original access is performed again, even if the INVEPT
* instruction is not executed.
*
* If access bits of guest EPT entry is added after shadow EPT entry setup,
* guest VM may not call INVEPT. Sync it here directly.
*/
shadow_ept_entry = (shadow_ept_entry & ~EPT_RWX) | (guest_ept_entry & EPT_RWX);
p_shadow_ept_page[offset] = shadow_ept_entry;
/* Shadow EPT entry exists */
if (is_leaf_ept_entry(guest_ept_entry, pt_level)) {
/* Shadow EPT is set up, let L2 VM re-execute the instruction. */