Skip to content

Commit 1d9b975

Browse files
committed
vm-ioctls: Add KVM_X86_SET_MSR_FILTER vm ioctl
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 48d93d6 commit 1d9b975

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

kvm-ioctls/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Upcoming Release
44

55
- Plumb through KVM_CAP_DIRTY_LOG_RING as DirtyLogRing cap.
6+
- [[#359]](https://github.com/rust-vmm/kvm/pull/359) Add support for `KVM_SET_MSR_FILTER` vm ioctl on x86_64.
67

78
## v0.24.0
89

kvm-ioctls/src/cap.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ pub enum Cap {
159159
#[cfg(target_arch = "x86_64")]
160160
X86UserSpaceMsr = KVM_CAP_X86_USER_SPACE_MSR,
161161
#[cfg(target_arch = "x86_64")]
162+
X86MsrFilter = KVM_CAP_X86_MSR_FILTER,
163+
#[cfg(target_arch = "x86_64")]
162164
ExitHypercall = KVM_CAP_EXIT_HYPERCALL,
163165
#[cfg(target_arch = "x86_64")]
164166
MemoryFaultInfo = KVM_CAP_MEMORY_FAULT_INFO,

kvm-ioctls/src/ioctls/vm.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,43 @@ impl VmFd {
533533
}
534534
}
535535

536+
/// Sets the MSR filter as per the `KVM_X86_SET_MSR_FILTER` ioctl.
537+
///
538+
/// See the documentation for `KVM_X86_SET_MSR_FILTER` in the
539+
/// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt).
540+
///
541+
/// # Arguments
542+
///
543+
/// * `filter` - MSR filter configuration to be set.
544+
///
545+
/// # Safety
546+
///
547+
/// The caller must ensure that the given `kvm_msr_filter` is valid. Specifically any `bitmap` pointers in the `kvm_msr_filter_range`
548+
/// structures within `filter.ranges` must point to valid memory of sufficient size.
549+
/// # Example
550+
///
551+
/// ```rust
552+
/// # extern crate kvm_bindings;
553+
/// # extern crate kvm_ioctls;
554+
/// # use kvm_bindings::kvm_msr_filter;
555+
/// # use kvm_ioctls::Kvm;
556+
/// let kvm = Kvm::new().unwrap();
557+
/// let vm = kvm.create_vm().unwrap();
558+
/// let mut filter = kvm_msr_filter::default();
559+
/// vm.set_msr_filter(&mut filter).unwrap();
560+
/// ```
561+
#[cfg(target_arch = "x86_64")]
562+
pub unsafe fn set_msr_filter(&self, filter: &kvm_msr_filter) -> Result<()> {
563+
// SAFETY: Safe because we call this with a Vm fd and we trust the kernel, and the caller
564+
// has promised validity of the filter structure.
565+
let ret = unsafe { ioctl_with_ref(self, KVM_SET_MSR_FILTER(), filter) };
566+
if ret == 0 {
567+
Ok(())
568+
} else {
569+
Err(errno::Error::last())
570+
}
571+
}
572+
536573
/// Directly injects a MSI message as per the `KVM_SIGNAL_MSI` ioctl.
537574
///
538575
/// See the documentation for `KVM_SIGNAL_MSI`.
@@ -2900,4 +2937,44 @@ mod tests {
29002937
vm.has_device_attr(&dist_attr).unwrap();
29012938
vm.set_device_attr(&dist_attr).unwrap();
29022939
}
2940+
2941+
#[test]
2942+
#[cfg(target_arch = "x86_64")]
2943+
fn test_set_msr_filter() {
2944+
let kvm = Kvm::new().unwrap();
2945+
let vm = kvm.create_vm().unwrap();
2946+
2947+
if !kvm.check_extension(Cap::X86MsrFilter) {
2948+
return;
2949+
}
2950+
2951+
let empty_filter = kvm_msr_filter {
2952+
flags: KVM_MSR_FILTER_DEFAULT_ALLOW,
2953+
ranges: [kvm_msr_filter_range::default(); 16],
2954+
};
2955+
// Safety: empty_filter is valid
2956+
unsafe { vm.set_msr_filter(&empty_filter).unwrap() };
2957+
2958+
// From KVM API:
2959+
// Calling this ioctl with an empty set of ranges (all nmsrs == 0) disables MSR filtering. In that mode, KVM_MSR_FILTER_DEFAULT_DENY is invalid and causes an error.
2960+
let empty_deny_filter = kvm_msr_filter {
2961+
flags: KVM_MSR_FILTER_DEFAULT_DENY,
2962+
ranges: [kvm_msr_filter_range::default(); 16],
2963+
};
2964+
// Safety: empty_deny_filter is invalid
2965+
unsafe { vm.set_msr_filter(&empty_deny_filter).unwrap_err() };
2966+
2967+
// disable access to all except 1 MSR
2968+
let mut filter = kvm_msr_filter {
2969+
flags: KVM_MSR_FILTER_DEFAULT_DENY,
2970+
ranges: [kvm_msr_filter_range::default(); 16],
2971+
};
2972+
let mut bitmap = 0b1u8;
2973+
filter.ranges[0].base = 0x10; // IA32_TIME_STAMP_COUNTER
2974+
filter.ranges[0].flags = KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE;
2975+
filter.ranges[0].nmsrs = 1;
2976+
filter.ranges[0].bitmap = &mut bitmap;
2977+
// Safety: bitmap is valid 8 bits, and nmsrs is 1
2978+
unsafe { vm.set_msr_filter(&filter).unwrap() };
2979+
}
29032980
}

kvm-ioctls/src/kvm_ioctls.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ ioctl_ior_nr!(KVM_MEMORY_ENCRYPT_REG_REGION, KVMIO, 0xbb, kvm_enc_region);
123123
/* Available on SEV-enabled guests. */
124124
#[cfg(target_arch = "x86_64")]
125125
ioctl_ior_nr!(KVM_MEMORY_ENCRYPT_UNREG_REGION, KVMIO, 0xbc, kvm_enc_region);
126+
/* Available with KVM_CAP_X86_MSR_FILTER */
127+
#[cfg(target_arch = "x86_64")]
128+
ioctl_iow_nr!(KVM_SET_MSR_FILTER, KVMIO, 0xc6, kvm_msr_filter);
126129

127130
// Ioctls for VCPU fds.
128131

0 commit comments

Comments
 (0)