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