// https://syzkaller.appspot.com/bug?id=e169399c60ec130cb7ab1abfe6a0eea7b0262b62 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #define PAGE_SIZE 4096 #ifndef KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA #define KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA 0x6 #endif struct kvm_xen_hvm_attr_local { __u16 type; __u16 pad[3]; union { __u8 long_mode; __u8 vector; __u8 runstate_update_flag; union { __u64 gfn; __u64 hva; } shared_info; struct { __u32 send_port; __u32 type; __u32 flags; union { struct { __u32 port; __u32 vcpu; __u32 priority; } port; struct { __u32 port; __s32 fd; } eventfd; __u32 padding[4]; } deliver; } evtchn; __u32 xen_version; __u64 pad[8]; } u; }; #ifndef KVM_XEN_HVM_SET_ATTR #define KVM_XEN_HVM_SET_ATTR _IOW(KVMIO, 0xc9, struct kvm_xen_hvm_attr_local) #endif int kvm_fd, vm_fd; void *shared_info_addr1; void *shared_info_addr2; volatile int stop = 0; void *thread_kvm(void *arg) { struct kvm_xen_hvm_attr_local attr; memset(&attr, 0, sizeof(attr)); attr.type = KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA; int toggle = 0; while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { attr.u.shared_info.hva = (uint64_t)(uintptr_t)(toggle ? shared_info_addr2 : shared_info_addr1); ioctl(vm_fd, KVM_XEN_HVM_SET_ATTR, &attr); toggle = !toggle; } return NULL; } void *thread_madvise1(void *arg) { while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { madvise(shared_info_addr1, PAGE_SIZE, MADV_DONTNEED); *(volatile char *)shared_info_addr1 = 1; // Fault it back in } return NULL; } void *thread_madvise2(void *arg) { while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { madvise(shared_info_addr2, PAGE_SIZE, MADV_DONTNEED); *(volatile char *)shared_info_addr2 = 1; // Fault it back in } return NULL; } int main() { kvm_fd = open("/dev/kvm", O_RDWR); if (kvm_fd < 0) { printf("[-] Failed to open /dev/kvm: %s\n", strerror(errno)); exit(1); } printf("[+] Opened /dev/kvm\n"); vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0); if (vm_fd < 0) { printf("[-] Failed to create VM: %s\n", strerror(errno)); exit(1); } printf("[+] Created VM\n"); shared_info_addr1 = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (shared_info_addr1 == MAP_FAILED) { printf("[-] Failed to mmap 1: %s\n", strerror(errno)); exit(1); } printf("[+] mmap 1 successful\n"); shared_info_addr2 = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (shared_info_addr2 == MAP_FAILED) { printf("[-] Failed to mmap 2: %s\n", strerror(errno)); exit(1); } printf("[+] mmap 2 successful\n"); *(volatile char *)shared_info_addr1 = 1; *(volatile char *)shared_info_addr2 = 1; pthread_t t1, t2, t3; if (pthread_create(&t1, NULL, thread_kvm, NULL) != 0) { printf("[-] Failed to create thread_kvm: %s\n", strerror(errno)); exit(1); } if (pthread_create(&t2, NULL, thread_madvise1, NULL) != 0) { printf("[-] Failed to create thread_madvise1: %s\n", strerror(errno)); exit(1); } if (pthread_create(&t3, NULL, thread_madvise2, NULL) != 0) { printf("[-] Failed to create thread_madvise2: %s\n", strerror(errno)); exit(1); } printf("[+] Threads created, running race for 5 seconds...\n"); sleep(5); __atomic_store_n(&stop, 1, __ATOMIC_RELAXED); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); printf("[+] Race finished.\n"); return 0; }