History

KVM: Protect device ops->create and list_add with kvm->lock

KVM devices were manipulating list data structures without any form of synchronization, and some implementations of the create operations also suffered from a lack of synchronization. Now when we've split the xics create operation into create and init, we can hold the kvm->lock mutex while calling the create operation and when manipulating the devices list. The error path in the generic code gets slightly ugly because we have to take the mutex again and delete the device from the list, but holding the mutex during anon_inode_getfd or releasing/locking the mutex in the common non-error path seemed wrong.

Christoffer Dall committed 10 years ago

Commit a28ebea1 parent 023e9fd5 files · +27 −17Browse files

Unified · Split

5 files
  1. arch/arm/kvm/arm.c +5 −1
  2. arch/powerpc/kvm/book3s_xics.c +0 −2
  3. include/linux/kvm_host.h +6 −0
  4. virt/kvm/arm/vgic/vgic-init.c +4 −13
  5. virt/kvm/kvm_main.c +12 −1
arch/arm/kvm/arm.c+5−1
@@ -1009,9 +1009,13 @@ long kvm_arch_vm_ioctl(struct file *filp, · 1008 unmodified lines
1009 1009
1010 switch (ioctl) {1010 switch (ioctl) {
1011 case KVM_CREATE_IRQCHIP: {1011 case KVM_CREATE_IRQCHIP: {
1012 int ret;
1012 if (!vgic_present)1013 if (!vgic_present)
1013 return -ENXIO;1014 return -ENXIO;
1014 return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);1015 mutex_lock(&kvm->lock);
1016 ret = kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
1017 mutex_unlock(&kvm->lock);
1018 return ret;
1015 }1019 }
1016 case KVM_ARM_SET_DEVICE_ADDR: {1020 case KVM_ARM_SET_DEVICE_ADDR: {
1017 struct kvm_arm_device_addr dev_addr;1021 struct kvm_arm_device_addr dev_addr;
arch/powerpc/kvm/book3s_xics.c+0−2
@@ -1329,12 +1329,10 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type) · 1328 unmodified lines
1329 xics->kvm = kvm;1329 xics->kvm = kvm;
1330 1330
1331 /* Already there ? */1331 /* Already there ? */
1332 mutex_lock(&kvm->lock);
1333 if (kvm->arch.xics)1332 if (kvm->arch.xics)
1334 ret = -EEXIST;1333 ret = -EEXIST;
1335 else1334 else
1336 kvm->arch.xics = xics;1335 kvm->arch.xics = xics;
1337 mutex_unlock(&kvm->lock);
1338 1336
1339 if (ret) {1337 if (ret) {
1340 kfree(xics);1338 kfree(xics);
include/linux/kvm_host.h+6−0
@@ -1113,6 +1113,12 @@ struct kvm_device { · 1112 unmodified lines
1113/* create, destroy, and name are mandatory */1113/* create, destroy, and name are mandatory */
1114struct kvm_device_ops {1114struct kvm_device_ops {
1115 const char *name;1115 const char *name;
1116
1117 /*
1118 * create is called holding kvm->lock and any operations not suitable
1119 * to do while holding the lock should be deferred to init (see
1120 * below).
1121 */
1116 int (*create)(struct kvm_device *dev, u32 type);1122 int (*create)(struct kvm_device *dev, u32 type);
1117 1123
1118 /*1124 /*
virt/kvm/arm/vgic/vgic-init.c+4−13
@@ -73,12 +73,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) · 72 unmodified lines
73 int i, vcpu_lock_idx = -1, ret;73 int i, vcpu_lock_idx = -1, ret;
74 struct kvm_vcpu *vcpu;74 struct kvm_vcpu *vcpu;
75 75
76 mutex_lock(&kvm->lock);76 if (irqchip_in_kernel(kvm))
77 77 return -EEXIST;
78 if (irqchip_in_kernel(kvm)) {
79 ret = -EEXIST;
80 goto out;
81 }
82 78
83 /*79 /*
84 * This function is also called by the KVM_CREATE_IRQCHIP handler,80 * This function is also called by the KVM_CREATE_IRQCHIP handler,
@@ -87,10 +83,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) · 2 unmodified lines
87 * the proper checks already.83 * the proper checks already.
88 */84 */
89 if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&85 if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
90 !kvm_vgic_global_state.can_emulate_gicv2) {86 !kvm_vgic_global_state.can_emulate_gicv2)
91 ret = -ENODEV;87 return -ENODEV;
92 goto out;
93 }
94 88
95 /*89 /*
96 * Any time a vcpu is run, vcpu_load is called which tries to grab the90 * Any time a vcpu is run, vcpu_load is called which tries to grab the
@@ -138,9 +132,6 @@ out_unlock: · 41 unmodified lines
138 vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);132 vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
139 mutex_unlock(&vcpu->mutex);133 mutex_unlock(&vcpu->mutex);
140 }134 }
141
142out:
143 mutex_unlock(&kvm->lock);
144 return ret;135 return ret;
145}136}
146 137
virt/kvm/kvm_main.c+12−1
@@ -696,6 +696,11 @@ static void kvm_destroy_devices(struct kvm *kvm) · 695 unmodified lines
696{696{
697 struct kvm_device *dev, *tmp;697 struct kvm_device *dev, *tmp;
698 698
699 /*
700 * We do not need to take the kvm->lock here, because nobody else
701 * has a reference to the struct kvm at this point and therefore
702 * cannot access the devices list anyhow.
703 */
699 list_for_each_entry_safe(dev, tmp, &kvm->devices, vm_node) {704 list_for_each_entry_safe(dev, tmp, &kvm->devices, vm_node) {
700 list_del(&dev->vm_node);705 list_del(&dev->vm_node);
701 dev->ops->destroy(dev);706 dev->ops->destroy(dev);
@@ -2832,11 +2837,15 @@ static int kvm_ioctl_create_device(struct kvm *kvm, · 2130 unmodified lines
2832 dev->ops = ops;2837 dev->ops = ops;
2833 dev->kvm = kvm;2838 dev->kvm = kvm;
2834 2839
2840 mutex_lock(&kvm->lock);
2835 ret = ops->create(dev, cd->type);2841 ret = ops->create(dev, cd->type);
2836 if (ret < 0) {2842 if (ret < 0) {
2843 mutex_unlock(&kvm->lock);
2837 kfree(dev);2844 kfree(dev);
2838 return ret;2845 return ret;
2839 }2846 }
2847 list_add(&dev->vm_node, &kvm->devices);
2848 mutex_unlock(&kvm->lock);
2840 2849
2841 if (ops->init)2850 if (ops->init)
2842 ops->init(dev);2851 ops->init(dev);
@@ -2844,10 +2853,12 @@ static int kvm_ioctl_create_device(struct kvm *kvm, · 1 unmodified line
2844 ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);2853 ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
2845 if (ret < 0) {2854 if (ret < 0) {
2846 ops->destroy(dev);2855 ops->destroy(dev);
2856 mutex_lock(&kvm->lock);
2857 list_del(&dev->vm_node);
2858 mutex_unlock(&kvm->lock);
2847 return ret;2859 return ret;
2848 }2860 }
2849 2861
2850 list_add(&dev->vm_node, &kvm->devices);
2851 kvm_get_kvm(kvm);2862 kvm_get_kvm(kvm);
2852 cd->fd = ret;2863 cd->fd = ret;
2853 return 0;2864 return 0;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t