Skip to content

Commit

Permalink
protocols/core: Clear page after PVALIDATE of the page
Browse files Browse the repository at this point in the history
A malicious hypervisor can attempt to reveal data from the SVSM to lower
VMPL levels through RMP manipulation related to page validation. For
example:

  - Initially, VMPL0 has a page at GPA A which maps to SPA X
  - VMPL3 asks HV to change the state of GPA B to private
  - HV maliciously reclaims SPA X and changes the RMP entry (and NPT) to
    map it at GPA B
  - VMPL3 asks VMPL0 to validate a new page at GPA B
  - VMPL0 PVALIDATE/RMPADJUSTs GPA B, allowing VMPL3 to read the data that
    VMPL0 had previously stored at GPA A

To prevent the exposure of any data in that page, the SVSM must zero-out
the memory after the PVALIDATE but before the RMPADJUST that grants
permission to the lower VMPL levels.

Signed-off-by: Tom Lendacky <[email protected]>
  • Loading branch information
tlendacky committed Jun 19, 2023
1 parent 7f286b5 commit 0de111e
Showing 1 changed file with 28 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/protocols/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

use crate::protocols::error_codes::*;
use crate::util::util::memset;
use crate::vmsa_list::VMSA_LIST;
use crate::*;

Expand Down Expand Up @@ -103,6 +104,10 @@ impl PvalidateRequest {
funcs!(next, u16);
}

fn zero_memory_range(va: VirtAddr, len: usize) {
memset(va.as_mut_ptr(), 0, len);
}

unsafe fn address_valid(gfn: PhysFrame, page_size: u32) -> bool {
let mut gpa: PhysAddr = gfn.start_address();

Expand Down Expand Up @@ -402,6 +407,29 @@ unsafe fn handle_pvalidate(vmsa: *mut Vmsa, entry: *const PvalidateEntry) -> (bo
}

if action != 0 {
let gpa_end: PhysAddr = gpa + len;

/*
* Zero-out the memory before granting access to the lower VMPL levels
* to guard against a malicious hypervisor trying to disclose VMPL0
* data to lower VMPL levels.
*
* Since the ISA range from 0xC0000 - 0xFFFFF is used for BIOS ROMs and
* is read-only, do not attempt to zero out the range as it could
* generate an infinite #NPF loop.
*/
if gpa_end.as_u64() <= 0xc0000 || gpa.as_u64() >= 0x100000 {
zero_memory_range(map.va(), len as usize);
} else if page_size == 1 && gpa.as_u64() == 0 {
/*
* It is a 2MB page at GPA 0:
* - Clear the range from 0x0 - 0xBFFFF
* - Clear the range from 0x100000 - 0x200000
*/
zero_memory_range(map.va(), 0xc0000);
zero_memory_range(map.va() + 0x100000 as u64, 0x100000);
}

let ret: u32 = grant_vmpl_access(map.va(), page_size, VMPL::Vmpl1 as u8);
if ret != 0 {
(*vmsa).set_rax(SVSM_ERR_PROTOCOL_BASE + ret as u64);
Expand Down

0 comments on commit 0de111e

Please sign in to comment.