Skip to content

Disallow MSR read/writes#991

Draft
ludfjig wants to merge 11 commits into
hyperlight-dev:mainfrom
ludfjig:reset2
Draft

Disallow MSR read/writes#991
ludfjig wants to merge 11 commits into
hyperlight-dev:mainfrom
ludfjig:reset2

Conversation

@ludfjig

@ludfjig ludfjig commented Oct 27, 2025

Copy link
Copy Markdown
Contributor

Disallows reading/writing MSRs in the guest. Can be bypassed with unsafe function on SandboxConfiguration. The goal is to prevent guest state to persist across snapshot-restores.

Will mark ready for review once KVM releases new version, which should include newly added KVM_X86_SET_MSR_FILTER vm ioctl that this PR depends on, see rust-vmm/kvm#359

@ludfjig ludfjig force-pushed the reset2 branch 7 times, most recently from aeca04d to 968f2f4 Compare October 31, 2025 00:29
@ludfjig ludfjig added the kind/enhancement For PRs adding features, improving functionality, docs, tests, etc. label Dec 2, 2025
@ludfjig ludfjig force-pushed the reset2 branch 3 times, most recently from e859ff9 to e793129 Compare December 8, 2025 18:42
@ludfjig ludfjig changed the title Reset more state when restoring snapshot Reset MSRs when restoring snapshot Dec 18, 2025
@ludfjig ludfjig changed the title Reset MSRs when restoring snapshot Disallow MSR read/writes Feb 10, 2026
@ludfjig ludfjig force-pushed the reset2 branch 5 times, most recently from 8f55249 to 3bb2294 Compare February 13, 2026 23:16
@ludfjig ludfjig force-pushed the reset2 branch 2 times, most recently from 032168d to c0383dd Compare February 18, 2026 19:27
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
ludfjig added 2 commits July 10, 2026 11:28
Design doc for resetting guest-written MSRs across MultiUseSandbox::restore() with a per-MSR opt-in allow list, plus a KVM Phase 1 implementation handoff brief.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Reset the guest-visible stateful MSRs on sandbox restore and gate the
per-MSR allow list behind validation, so guest MSR writes cannot leak
across restores. Adds host-index sweep, negative-leak, denied-MSR fault,
and partial-set poison tests, plus documentation of the reset-set
completeness argument and the dormant host_specific/TSC machinery.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Handoff for the mshv agent: the pass-through completeness gap, the Hyper-V/mshv source facts (SVM pass-through MSR set, intercept behavior) the agent cannot see, and the reset-or-mask plan per MSR class.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Widen the KVM-only MSR reset machinery to also cover the mshv backend, so
guest MSR writes do not leak across a snapshot restore on Hyper-V. Implement
capture_msrs/apply_msrs on MshvVm using batched get_msrs/set_msrs, detecting
failure from the returned error (set_msrs reports no count) and poisoning on
a partial apply.

mshv has no per-MSR deny filter, so a guest can write architectural
pass-through MSRs with no intercept, and completeness rests on reset. The
reset set covers every stateful pass-through MSR the crate can map and
restore: the core syscall, sysenter, and base MSRs, KERNEL_GS_BASE,
SPEC_CTRL, and the CET MSRs where CET is active. mshv has no host-probed
index list, so the reset set is resolved by probing each mappable index
with a get at init, including only those that read back. That resets CET on
hosts where it is exposed and skips it elsewhere without failing init. The
allow list is validated at VM creation so a non-resettable or unmappable
request is a hard error.

The pass-through classes with no mapping (PMU, AMX/XFD, FRED, arch LBR)
cannot be reset. Completeness holds because the minimal partition enables
none of them, so a guest access faults. A test asserts this on the host.

Add mshv tests: a pass-through MSR write is reset across restore, a guest
read of an unresettable class faults, a rejected set_msrs during restore
poisons the sandbox, an allowed MSR does not leak across restore, and
allowing a non-resettable or unmapped MSR fails sandbox creation.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
ludfjig added 6 commits July 10, 2026 18:34
Implement MSR reset for the Windows Hypervisor Platform backend, matching the KVM and mshv phases. WHP models MSRs as named registers (no index list), so capture_msrs/apply_msrs map indices to WHV_REGISTER_NAME values.

WHP has no usable per-MSR deny filter: the Hyper-V hypervisor refuses to intercept an MSR it implements (WHvSetupPartition rejects MsrActionList/UnimplementedMsrAction; the X64MsrExitBitmap UnhandledMsrs bit only traps already-faulting MSRs). Isolation therefore relies on reset, so the reset set must cover every guest-writable, retained MSR by construction.

An audit of every WHP-exposable MSR found real cross-restore leaks not covered by the core reset set: the MTRR family, TSC_ADJUST, and TSC_AUX. Add these to the shared MSR table so both WHP and mshv (both filterless) reset them; the change is a no-op on KVM (guest writes are denied by the filter) and per-backend host-support probes drop unsupported indices. Raw TSC is not reset (it free-runs); a direct WRMSR(TSC) is rolled back via TSC_ADJUST.

Also gate the guest ReadMSR/WriteMSR functions to x86_64 and remove redundant target_arch gates from the already-arch-gated hyperlight_vm/x86_64.rs.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Record the WHP MSR-reset implementation, the source-proven finding that Hyper-V cannot intercept an implemented MSR, and the cross-restore leak audit. Flags the remaining Linux validation of the shared MSR-table change on KVM and mshv.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
The WHP MSR reset commit added MTRR and TSC_ADJUST/TSC_AUX to the shared
reset table and widened the MSR access-control VM exits to all of x86_64.
On an mshv-only Linux build those exits are never constructed, since only
KVM and WHP produce them, which fails the build under deny-warnings. Gate
VmExit::MsrRead/MsrWrite, the RunVmError violation variants, the run-loop
arms, and the error mapping to the backends that construct them (KVM and
Windows).

Add an mshv leak sweep over the MTRR and TSC MSRs the shared table added.
mshv has no per-MSR deny filter, so each is guest-unreachable, masked, or
retained. A retained MSR must roll back on restore. The test asserts no
value leaks across a restore whichever path the host takes.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
The reset set on WHP and mshv (both filterless) must cover every guest-writable, retained MSR by construction, so add tests that push toward that guarantee instead of spot-checking a handful.

test_whp_unresettable_msr_classes_do_not_retain asserts the classes the completeness argument depends on (PMU, AMX, FRED, LBR, masked DEBUGCTL) never retain a guest write. test_whp_no_msr_leaks_across_restore_broad_sweep and its mshv3-gated counterpart sweep ~60 architectural MSRs and require that no guest-written value survives a restore, whatever the host does (fault, mask, or retain-and-reset). The mshv sweep still needs to be run on a real mshv host.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
The no-leak invariant is identical on all backends, but three test families were triplicated per backend (test_{kvm,mshv,whp}_*) with near-identical bodies. Since the CI matrix runs each backend on its own runner, an agnostic test gated only by target_arch (or, for the deny-filter-only sweep, by the filterless backends) and skipped at runtime via get_available_hypervisor().is_none() gives all backends identical coverage from one source.

Consolidate the allow-non-resettable-fails, allowed-msr-no-leak, and broad no-leak sweep families into single shared tests and drop the per-backend copies. Genuinely backend-specific tests (KVM deny-filter poison, KVM host-index-list sweep, mshv unmapped/partial-set, WHP named-register reset) stay as they are. Validated on WHP; KVM and mshv confirm via their CI runners.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
restore() clears the poisoned flag and works on a poisoned sandbox, so a faulting or filter-denied MSR access is recovered by restoring the pre-access snapshot instead of building a fresh VM. This is much cheaper (the sweep no longer recreates ~60 sandboxes) and removes the reason the sweep was gated off KVM.

Ungate the broad sweep to target_arch = x86_64 so it runs on every backend in the CI matrix. On KVM the deny filter intercepts every non-allowed MSR access, so the sweep self-skips there (KVM's coverage is the host-index-list sweep plus the deny tests); on the filterless backends (mshv, WHP) it is the meaningful completeness sweep. Apply the same restore-reuse to the WHP unresettable-classes test.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement For PRs adding features, improving functionality, docs, tests, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant