linux/arch/x86/kvm
Wanpeng Li 546d87e5c9 KVM: x86: fix NULL deref in vcpu_scan_ioapic
Reported by syzkaller:

    BUG: unable to handle kernel NULL pointer dereference at 00000000000001b0
    IP: _raw_spin_lock+0xc/0x30
    PGD 3e28eb067
    PUD 3f0ac6067
    PMD 0
    Oops: 0002 [#1] SMP
    CPU: 0 PID: 2431 Comm: test Tainted: G           OE   4.10.0-rc1+ #3
    Call Trace:
     ? kvm_ioapic_scan_entry+0x3e/0x110 [kvm]
     kvm_arch_vcpu_ioctl_run+0x10a8/0x15f0 [kvm]
     ? pick_next_task_fair+0xe1/0x4e0
     ? kvm_arch_vcpu_load+0xea/0x260 [kvm]
     kvm_vcpu_ioctl+0x33a/0x600 [kvm]
     ? hrtimer_try_to_cancel+0x29/0x130
     ? do_nanosleep+0x97/0xf0
     do_vfs_ioctl+0xa1/0x5d0
     ? __hrtimer_init+0x90/0x90
     ? do_nanosleep+0x5b/0xf0
     SyS_ioctl+0x79/0x90
     do_syscall_64+0x6e/0x180
     entry_SYSCALL64_slow_path+0x25/0x25
    RIP: _raw_spin_lock+0xc/0x30 RSP: ffffa43688973cc0

The syzkaller folks reported a NULL pointer dereference due to
ENABLE_CAP succeeding even without an irqchip.  The Hyper-V
synthetic interrupt controller is activated, resulting in a
wrong request to rescan the ioapic and a NULL pointer dereference.

    #include <sys/ioctl.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <linux/kvm.h>
    #include <pthread.h>
    #include <stddef.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    #ifndef KVM_CAP_HYPERV_SYNIC
    #define KVM_CAP_HYPERV_SYNIC 123
    #endif

    void* thr(void* arg)
    {
	struct kvm_enable_cap cap;
	cap.flags = 0;
	cap.cap = KVM_CAP_HYPERV_SYNIC;
	ioctl((long)arg, KVM_ENABLE_CAP, &cap);
	return 0;
    }

    int main()
    {
	void *host_mem = mmap(0, 0x1000, PROT_READ|PROT_WRITE,
			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
	int kvmfd = open("/dev/kvm", 0);
	int vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
	struct kvm_userspace_memory_region memreg;
	memreg.slot = 0;
	memreg.flags = 0;
	memreg.guest_phys_addr = 0;
	memreg.memory_size = 0x1000;
	memreg.userspace_addr = (unsigned long)host_mem;
	host_mem[0] = 0xf4;
	ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
	int cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
	struct kvm_sregs sregs;
	ioctl(cpufd, KVM_GET_SREGS, &sregs);
	sregs.cr0 = 0;
	sregs.cr4 = 0;
	sregs.efer = 0;
	sregs.cs.selector = 0;
	sregs.cs.base = 0;
	ioctl(cpufd, KVM_SET_SREGS, &sregs);
	struct kvm_regs regs = { .rflags = 2 };
	ioctl(cpufd, KVM_SET_REGS, &regs);
	ioctl(vmfd, KVM_CREATE_IRQCHIP, 0);
	pthread_t th;
	pthread_create(&th, 0, thr, (void*)(long)cpufd);
	usleep(rand() % 10000);
	ioctl(cpufd, KVM_RUN, 0);
	pthread_join(th, 0);
	return 0;
    }

This patch fixes it by failing ENABLE_CAP if without an irqchip.

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Fixes: 5c919412fe (kvm/x86: Hyper-V synthetic interrupt controller)
Cc: stable@vger.kernel.org # 4.5+
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-01-12 14:52:52 +01:00
..
assigned-dev.c KVM: x86: use list_for_each_entry* 2016-02-23 15:40:54 +01:00
assigned-dev.h KVM: x86: move device assignment out of kvm_host.h 2014-11-24 16:53:50 +01:00
cpuid.c KVM: x86: Expose Intel AVX512IFMA/AVX512VBMI/SHA features to guest. 2016-12-15 15:02:44 +01:00
cpuid.h Revert "KVM: x86: add pcommit support" 2016-07-23 11:04:23 -07:00
debugfs.c kvm: x86: export TSC information to user-space 2016-09-16 16:57:48 +02:00
emulate.c KVM: x86: Introduce segmented_write_std 2017-01-12 14:34:58 +01:00
hyperv.c KVM: hyperv: fix locking of struct kvm_hv fields 2016-12-16 17:53:38 +01:00
hyperv.h KVM: x86: Hyper-V tsc page setup 2016-09-20 09:26:20 +02:00
i8254.c KVM: x86: Handle the kthread worker using the new API 2016-12-08 15:31:11 +01:00
i8254.h KVM: x86: Handle the kthread worker using the new API 2016-12-08 15:31:11 +01:00
i8259.c KVM: x86: clean/fix memory barriers in irqchip_in_kernel 2015-07-30 16:02:56 +02:00
ioapic.c KVM: x86: fix out-of-bounds accesses of rtc_eoi map 2016-11-24 18:37:19 +01:00
ioapic.h KVM: x86: fix out-of-bounds accesses of rtc_eoi map 2016-11-24 18:37:19 +01:00
iommu.c - ARM: GICv3 ITS emulation and various fixes. Removal of the old 2016-08-02 16:11:27 -04:00
irq_comm.c KVM: x86: check for pic and ioapic presence before use 2016-11-24 18:39:28 +01:00
irq.c x86/kvm: Audit and remove any unnecessary uses of module.h 2016-07-14 15:07:00 +02:00
irq.h KVM: Move kvm_setup_default/empty_irq_routing declaration in arch specific header 2016-07-22 18:52:00 +01:00
Kconfig KVM: remove kvm_vcpu_compatible 2016-06-16 00:05:00 +02:00
kvm_cache_regs.h KVM, pkeys: add pkeys support for permission_fault 2016-03-22 16:23:37 +01:00
lapic.c KVM: x86: flush pending lapic jump label updates on module unload 2017-01-12 14:33:17 +01:00
lapic.h KVM: x86: flush pending lapic jump label updates on module unload 2017-01-12 14:33:17 +01:00
Makefile kvm: add stubs for arch specific debugfs support 2016-09-16 16:57:47 +02:00
mmu_audit.c kvm: rename pfn_t to kvm_pfn_t 2016-01-15 17:56:32 -08:00
mmu.c kvm: svm: Add support for additional SVM NPF error codes 2016-11-24 18:32:26 +01:00
mmu.h kvm: mmu: remove is_present_gpte() 2016-07-14 09:02:47 +02:00
mmutrace.h tracing: Rename ftrace_event.h to trace_events.h 2015-05-13 14:05:12 -04:00
mtrr.c KVM: MTRR: fix kvm_mtrr_check_gfn_range_consistency page fault 2016-07-05 16:14:43 +02:00
page_track.c kvm/page_track: export symbols for external usage 2016-11-04 12:13:20 +01:00
paging_tmpl.h kvm: mmu: track read permission explicitly for shadow EPT page tables 2016-07-14 09:03:50 +02:00
pmu_amd.c perf/x86/amd: Make HW_CACHE_REFERENCES and HW_CACHE_MISSES measure L2 2016-09-16 16:19:49 +02:00
pmu_intel.c KVM: x86: Fix typos 2016-06-14 11:16:28 +02:00
pmu.c KVM: x86: consolidate different ways to test for in-kernel LAPIC 2016-02-09 16:57:45 +01:00
pmu.h KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch 2015-06-23 14:12:14 +02:00
svm.c KVM: x86: Add kvm_skip_emulated_instruction and use it. 2016-12-08 15:31:05 +01:00
trace.h KVM: x86: support using the vmx preemption timer for tsc deadline timer 2016-06-16 10:07:48 +02:00
tss.h
vmx.c KVM: VMX: remove duplicated declaration 2017-01-05 15:08:48 +01:00
x86.c KVM: x86: fix NULL deref in vcpu_scan_ioapic 2017-01-12 14:52:52 +01:00
x86.h KVM: x86: introduce get_kvmclock_ns 2016-09-20 09:26:15 +02:00