diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-06-01 08:09:19 -0400 |
---|---|---|
committer | Radim Krčmář <rkrcmar@redhat.com> | 2016-06-02 11:38:50 -0400 |
commit | 83676e923895adf2af392cfd36a05709950aaeef (patch) | |
tree | 5c462f932fa0d899a0b37c3187f76a8fd9b31ca1 | |
parent | b21629da120dd6145d14dbd6d028e1bba680a92b (diff) |
KVM: x86: avoid vmalloc(0) in the KVM_SET_CPUID
This causes an ugly dmesg splat. Beautified syzkaller testcase:
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/kvm.h>
long r[8];
int main()
{
struct kvm_cpuid2 c = { 0 };
r[2] = open("/dev/kvm", O_RDWR);
r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
r[4] = ioctl(r[3], KVM_CREATE_VCPU, 0x8);
r[7] = ioctl(r[4], KVM_SET_CPUID, &c);
return 0;
}
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
-rw-r--r-- | arch/x86/kvm/cpuid.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 769af907f824..7597b42a8a88 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c | |||
@@ -181,19 +181,22 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, | |||
181 | struct kvm_cpuid_entry __user *entries) | 181 | struct kvm_cpuid_entry __user *entries) |
182 | { | 182 | { |
183 | int r, i; | 183 | int r, i; |
184 | struct kvm_cpuid_entry *cpuid_entries; | 184 | struct kvm_cpuid_entry *cpuid_entries = NULL; |
185 | 185 | ||
186 | r = -E2BIG; | 186 | r = -E2BIG; |
187 | if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) | 187 | if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) |
188 | goto out; | 188 | goto out; |
189 | r = -ENOMEM; | 189 | r = -ENOMEM; |
190 | cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * cpuid->nent); | 190 | if (cpuid->nent) { |
191 | if (!cpuid_entries) | 191 | cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * |
192 | goto out; | 192 | cpuid->nent); |
193 | r = -EFAULT; | 193 | if (!cpuid_entries) |
194 | if (copy_from_user(cpuid_entries, entries, | 194 | goto out; |
195 | cpuid->nent * sizeof(struct kvm_cpuid_entry))) | 195 | r = -EFAULT; |
196 | goto out_free; | 196 | if (copy_from_user(cpuid_entries, entries, |
197 | cpuid->nent * sizeof(struct kvm_cpuid_entry))) | ||
198 | goto out; | ||
199 | } | ||
197 | for (i = 0; i < cpuid->nent; i++) { | 200 | for (i = 0; i < cpuid->nent; i++) { |
198 | vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function; | 201 | vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function; |
199 | vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax; | 202 | vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax; |
@@ -212,9 +215,8 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, | |||
212 | kvm_x86_ops->cpuid_update(vcpu); | 215 | kvm_x86_ops->cpuid_update(vcpu); |
213 | r = kvm_update_cpuid(vcpu); | 216 | r = kvm_update_cpuid(vcpu); |
214 | 217 | ||
215 | out_free: | ||
216 | vfree(cpuid_entries); | ||
217 | out: | 218 | out: |
219 | vfree(cpuid_entries); | ||
218 | return r; | 220 | return r; |
219 | } | 221 | } |
220 | 222 | ||