]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
KVM: lock slots_lock around device assignment
authorAlex Williamson <alex.williamson@redhat.com>
Wed, 18 Apr 2012 03:46:44 +0000 (21:46 -0600)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Tue, 19 Jun 2012 10:00:24 +0000 (03:00 -0700)
Bugdb: 13966
As pointed out by Jason Baron, when assigning a device to a guest
we first set the iommu domain pointer, which enables mapping
and unmapping of memory slots to the iommu.  This leaves a window
where this path is enabled, but we haven't synchronized the iommu
mappings to the existing memory slots.  Thus a slot being removed
at that point could send us down unexpected code paths removing
non-existent pinnings and iommu mappings.  Take the slots_lock
around creating the iommu domain and initial mappings as well as
around iommu teardown to avoid this race.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This fixes: CVE-2012-2121
Conflicts:

virt/kvm/iommu.c

virt/kvm/iommu.c

index d20006dfe9886abf673495178b5ab576e4182256..55ab345dd09aa274ea0a2a3187d250d85726bc18 100644 (file)
@@ -232,18 +232,18 @@ int kvm_iommu_map_guest(struct kvm *kvm)
                return -ENODEV;
        }
 
+
+       mutex_lock(&kvm->slots_lock);
        kvm->arch.iommu_domain = iommu_domain_alloc();
        if (!kvm->arch.iommu_domain)
-               return -ENOMEM;
+               goto out_unlock;
 
        r = kvm_iommu_map_memslots(kvm);
        if (r)
-               goto out_unmap;
-
-       return 0;
+               kvm_iommu_unmap_memslots(kvm);
 
-out_unmap:
-       kvm_iommu_unmap_memslots(kvm);
+out_unlock:
+       mutex_unlock(&kvm->slots_lock);
        return r;
 }
 
@@ -320,7 +320,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm)
        if (!domain)
                return 0;
 
+       mutex_lock(&kvm->slots_lock);
        kvm_iommu_unmap_memslots(kvm);
+       kvm->arch.iommu_domain = NULL;
+       mutex_unlock(&kvm->slots_lock);
+
        iommu_domain_free(domain);
        return 0;
 }