Skip to content

Commit 93b1b92

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

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-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: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,44 @@ 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+
/// // Safety: filter is valid
560+
/// unsafe { vm.set_msr_filter(&mut filter).unwrap() };
561+
/// ```
562+
#[cfg(target_arch = "x86_64")]
563+
pub unsafe fn set_msr_filter(&self, filter: &kvm_msr_filter) -> Result<()> {
564+
// SAFETY: Safe because we call this with a Vm fd and we trust the kernel, and the caller
565+
// has promised validity of the filter structure.
566+
let ret = unsafe { ioctl_with_ref(self, KVM_SET_MSR_FILTER(), filter) };
567+
if ret == 0 {
568+
Ok(())
569+
} else {
570+
Err(errno::Error::last())
571+
}
572+
}
573+
536574
/// Directly injects a MSI message as per the `KVM_SIGNAL_MSI` ioctl.
537575
///
538576
/// See the documentation for `KVM_SIGNAL_MSI`.
@@ -2900,4 +2938,44 @@ mod tests {
29002938
vm.has_device_attr(&dist_attr).unwrap();
29012939
vm.set_device_attr(&dist_attr).unwrap();
29022940
}
2941+
2942+
#[test]
2943+
#[cfg(target_arch = "x86_64")]
2944+
fn test_set_msr_filter() {
2945+
let kvm = Kvm::new().unwrap();
2946+
let vm = kvm.create_vm().unwrap();
2947+
2948+
if !kvm.check_extension(Cap::X86MsrFilter) {
2949+
return;
2950+
}
2951+
2952+
let empty_filter = kvm_msr_filter {
2953+
flags: KVM_MSR_FILTER_DEFAULT_ALLOW,
2954+
ranges: [kvm_msr_filter_range::default(); 16],
2955+
};
2956+
// Safety: empty_filter is valid
2957+
unsafe { vm.set_msr_filter(&empty_filter).unwrap() };
2958+
2959+
// From KVM API:
2960+
// 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.
2961+
let empty_deny_filter = kvm_msr_filter {
2962+
flags: KVM_MSR_FILTER_DEFAULT_DENY,
2963+
ranges: [kvm_msr_filter_range::default(); 16],
2964+
};
2965+
// Safety: empty_deny_filter is invalid
2966+
unsafe { vm.set_msr_filter(&empty_deny_filter).unwrap_err() };
2967+
2968+
// disable access to all except 1 MSR
2969+
let mut filter = kvm_msr_filter {
2970+
flags: KVM_MSR_FILTER_DEFAULT_DENY,
2971+
ranges: [kvm_msr_filter_range::default(); 16],
2972+
};
2973+
let mut bitmap = 0b1u8;
2974+
filter.ranges[0].base = 0x10; // IA32_TIME_STAMP_COUNTER
2975+
filter.ranges[0].flags = KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE;
2976+
filter.ranges[0].nmsrs = 1;
2977+
filter.ranges[0].bitmap = &mut bitmap;
2978+
// Safety: bitmap is valid 8 bits, and nmsrs is 1
2979+
unsafe { vm.set_msr_filter(&filter).unwrap() };
2980+
}
29032981
}

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)