-
Notifications
You must be signed in to change notification settings - Fork 132
cvm guest vsm: protections applied to overlay pages shouldn't affect bitmaps #1557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
sluck-msft
merged 2 commits into
microsoft:main
from
sluck-msft:gvsm/fix-overlay-vtl-prot
Jun 20, 2025
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ use hvdef::HV_PAGE_SIZE; | |
use hvdef::HvError; | ||
use hvdef::HvMapGpaFlags; | ||
use hvdef::HypercallCode; | ||
use hvdef::Vtl; | ||
use hvdef::hypercall::AcceptMemoryType; | ||
use hvdef::hypercall::HostVisibilityType; | ||
use hvdef::hypercall::HvInputVtl; | ||
|
@@ -393,15 +394,16 @@ impl HardwareIsolatedMemoryProtector { | |
fn apply_protections_with_overlay_handling( | ||
&self, | ||
range: MemoryRange, | ||
vtl: GuestVtl, | ||
calling_vtl: Vtl, | ||
target_vtl: GuestVtl, | ||
protections: HvMapGpaFlags, | ||
inner: &mut MutexGuard<'_, HardwareIsolatedMemoryProtectorInner>, | ||
) -> Result<(), ApplyVtlProtectionsError> { | ||
let mut range_queue = VecDeque::new(); | ||
range_queue.push_back(range); | ||
|
||
'outer: while let Some(range) = range_queue.pop_front() { | ||
for overlay_page in inner.overlay_pages[vtl].iter_mut() { | ||
for overlay_page in inner.overlay_pages[target_vtl].iter_mut() { | ||
let overlay_addr = overlay_page.gpn * HV_PAGE_SIZE; | ||
if range.contains_addr(overlay_addr) { | ||
// If the overlay page is within the range, update the | ||
|
@@ -424,7 +426,7 @@ impl HardwareIsolatedMemoryProtector { | |
} | ||
// We can only reach here if the range does not contain any overlay | ||
// pages, so now we can apply the protections to the range. | ||
self.apply_protections(range, vtl, protections)? | ||
self.apply_protections(range, calling_vtl, target_vtl, protections)? | ||
} | ||
|
||
Ok(()) | ||
|
@@ -433,14 +435,16 @@ impl HardwareIsolatedMemoryProtector { | |
fn apply_protections( | ||
&self, | ||
range: MemoryRange, | ||
vtl: GuestVtl, | ||
calling_vtl: Vtl, | ||
target_vtl: GuestVtl, | ||
protections: HvMapGpaFlags, | ||
) -> Result<(), ApplyVtlProtectionsError> { | ||
if vtl == GuestVtl::Vtl0 { | ||
// Only VTL 0 vtl permissions are explicitly tracked | ||
if calling_vtl == Vtl::Vtl1 && target_vtl == GuestVtl::Vtl0 { | ||
// Only VTL 1 permissions imposed on VTL 0 are explicitly tracked | ||
self.vtl0.update_permission_bitmaps(range, protections); | ||
} | ||
self.acceptor.apply_protections(range, vtl, protections) | ||
self.acceptor | ||
.apply_protections(range, target_vtl, protections) | ||
} | ||
|
||
/// Get the permissions that the given VTL has to the given GPN. | ||
|
@@ -691,11 +695,20 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
// overlay pages won't be host visible, so just apply the default | ||
// protections directly without handling them. | ||
for &range in &ranges { | ||
self.apply_protections(range, GuestVtl::Vtl0, inner.default_vtl_permissions.vtl0) | ||
.expect("should be able to apply default protections"); | ||
self.apply_protections( | ||
range, | ||
if self.vtl1_protections_enabled() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels odd. I feel like this should be another caller_vtl being passed in, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thinking is this:
|
||
Vtl::Vtl1 | ||
} else { | ||
Vtl::Vtl2 | ||
}, | ||
GuestVtl::Vtl0, | ||
inner.default_vtl_permissions.vtl0, | ||
) | ||
.expect("should be able to apply default protections"); | ||
|
||
if let Some(vtl1_protections) = inner.default_vtl_permissions.vtl1 { | ||
self.apply_protections(range, GuestVtl::Vtl1, vtl1_protections) | ||
self.apply_protections(range, Vtl::Vtl2, GuestVtl::Vtl1, vtl1_protections) | ||
.expect( | ||
"everything should be in a state where we can apply VTL protections", | ||
); | ||
|
@@ -744,7 +757,8 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
|
||
fn change_default_vtl_protections( | ||
&self, | ||
vtl: GuestVtl, | ||
calling_vtl: Vtl, | ||
target_vtl: GuestVtl, | ||
vtl_protections: HvMapGpaFlags, | ||
tlb_access: &mut dyn TlbFlushLockAccess, | ||
) -> Result<(), HvError> { | ||
|
@@ -756,7 +770,9 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
// finishes last will control the outcome. | ||
let mut inner = self.inner.lock(); | ||
|
||
inner.default_vtl_permissions.set(vtl, vtl_protections); | ||
inner | ||
.default_vtl_permissions | ||
.set(target_vtl, vtl_protections); | ||
|
||
let mut ranges = Vec::new(); | ||
for ram_range in self.layout.ram().iter() { | ||
|
@@ -789,8 +805,14 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
} | ||
|
||
for range in ranges { | ||
self.apply_protections_with_overlay_handling(range, vtl, vtl_protections, &mut inner) | ||
.unwrap(); | ||
self.apply_protections_with_overlay_handling( | ||
range, | ||
calling_vtl, | ||
target_vtl, | ||
vtl_protections, | ||
&mut inner, | ||
) | ||
.unwrap(); | ||
} | ||
|
||
// Flush any threads accessing pages that had their VTL protections | ||
|
@@ -806,7 +828,8 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
|
||
fn change_vtl_protections( | ||
&self, | ||
vtl: GuestVtl, | ||
calling_vtl: Vtl, | ||
target_vtl: GuestVtl, | ||
gpns: &[u64], | ||
protections: HvMapGpaFlags, | ||
tlb_access: &mut dyn TlbFlushLockAccess, | ||
|
@@ -844,8 +867,14 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
.unwrap(); // Ok to unwrap, we've validated the gpns above. | ||
|
||
for range in ranges { | ||
self.apply_protections_with_overlay_handling(range, vtl, protections, &mut inner) | ||
.unwrap(); | ||
self.apply_protections_with_overlay_handling( | ||
range, | ||
calling_vtl, | ||
target_vtl, | ||
protections, | ||
&mut inner, | ||
) | ||
.unwrap(); | ||
} | ||
|
||
// Flush any threads accessing pages that had their VTL protections | ||
|
@@ -857,7 +886,7 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
// other CPUs to release all guest mappings before declaring that the VTL | ||
// protection change has completed. | ||
tlb_access.flush(GuestVtl::Vtl0); | ||
tlb_access.set_wait_for_tlb_locks(vtl); | ||
tlb_access.set_wait_for_tlb_locks(target_vtl); | ||
|
||
Ok(()) | ||
} | ||
|
@@ -892,8 +921,13 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
|
||
// Everything's validated, change the permissions. | ||
if let Some(new_perms) = new_perms { | ||
self.apply_protections(MemoryRange::from_4k_gpn_range(gpn..gpn + 1), vtl, new_perms) | ||
.map_err(|_| HvError::OperationDenied)?; | ||
self.apply_protections( | ||
MemoryRange::from_4k_gpn_range(gpn..gpn + 1), | ||
Vtl::Vtl2, | ||
vtl, | ||
new_perms, | ||
) | ||
.map_err(|_| HvError::OperationDenied)?; | ||
} | ||
|
||
// Nothing from this point on can fail, so we can safely register the overlay page. | ||
|
@@ -934,6 +968,7 @@ impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector { | |
// Restore its permissions. | ||
self.apply_protections( | ||
MemoryRange::from_4k_gpn_range(gpn..gpn + 1), | ||
Vtl::Vtl2, | ||
vtl, | ||
overlay_pages[index].previous_permissions, | ||
) | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we call update_permission_bitmaps in one other spot below, does it need a similar guard?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the one in change_host_visibility? I think we want to remove the permissions there because it's the encrypted mapping and needs to reflect the underlying partition-wide mapping, I can add a comment.