@@ -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}
0 commit comments