| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/01 05:53 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"KVM_HYPERV",
"KVM_XEN"
],
"FocusSymbols": [
"kvm_hv_flush_tlb",
"kvm_xen_hcall_vcpu_op",
"kvm_xen_vcpu_set_attr",
"kvm_hv_vcpu_flush_tlb",
"kvm_hv_activate_synic"
],
"Reasoning": "The patch modifies KVM Hyper-V and Xen emulation logic, specifically fixing race conditions and initialization issues related to vCPU structures, TLB flushing, and timers. These are functional changes to reachable core kernel logic that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/01 05:53 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 46107f019722a27ee193f5c82515aa5545cbaa9f\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Jul 1 05:53:34 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c\nindex 1ee0d23f894974..9d38cb644668da 100644\n--- a/arch/x86/kvm/hyperv.c\n+++ b/arch/x86/kvm/hyperv.c\n@@ -206,14 +206,20 @@ static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx)\n \n static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx)\n {\n-\tstruct kvm_vcpu *vcpu;\n \tstruct kvm_vcpu_hv_synic *synic;\n+\tstruct kvm_vcpu_hv *hv_vcpu;\n+\tstruct kvm_vcpu *vcpu;\n \n \tvcpu = get_vcpu_by_vpidx(kvm, vpidx);\n-\tif (!vcpu || !to_hv_vcpu(vcpu))\n+\tif (!vcpu)\n \t\treturn NULL;\n-\tsynic = to_hv_synic(vcpu);\n-\treturn (synic-\u003eactive) ? synic : NULL;\n+\n+\thv_vcpu = to_hv_vcpu_safe(vcpu);\n+\tif (!hv_vcpu)\n+\t\treturn NULL;\n+\n+\tsynic = \u0026hv_vcpu-\u003esynic;\n+\treturn READ_ONCE(synic-\u003eactive) ? synic : NULL;\n }\n \n static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)\n@@ -593,8 +599,7 @@ static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,\n {\n \tstruct kvm_vcpu *vcpu = hv_stimer_to_vcpu(stimer);\n \n-\tset_bit(stimer-\u003eindex,\n-\t\tto_hv_vcpu(vcpu)-\u003estimer_pending_bitmap);\n+\tset_bit(stimer-\u003eindex, vcpu-\u003earch.hyperv-\u003estimer_pending_bitmap);\n \tkvm_make_request(KVM_REQ_HV_STIMER, vcpu);\n \tif (vcpu_kick)\n \t\tkvm_vcpu_kick(vcpu);\n@@ -608,8 +613,7 @@ static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)\n \t\t\t\t stimer-\u003eindex);\n \n \thrtimer_cancel(\u0026stimer-\u003etimer);\n-\tclear_bit(stimer-\u003eindex,\n-\t\t to_hv_vcpu(vcpu)-\u003estimer_pending_bitmap);\n+\tclear_bit(stimer-\u003eindex, vcpu-\u003earch.hyperv-\u003estimer_pending_bitmap);\n \tstimer-\u003emsg_pending = false;\n \tstimer-\u003eexp_time = 0;\n }\n@@ -972,7 +976,6 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)\n \tif (!hv_vcpu)\n \t\treturn -ENOMEM;\n \n-\tvcpu-\u003earch.hyperv = hv_vcpu;\n \thv_vcpu-\u003evcpu = vcpu;\n \n \tsynic_init(\u0026hv_vcpu-\u003esynic);\n@@ -988,6 +991,14 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)\n \t\tspin_lock_init(\u0026hv_vcpu-\u003etlb_flush_fifo[i].write_lock);\n \t}\n \n+\t/*\n+\t * Ensure the structure is fully initialized before it's visible to\n+\t * other tasks, as much of the state can be legally accessed without\n+\t * holding vcpu-\u003emutex.\n+\t *\n+\t * Pairs with the smp_load_acquire() in to_hv_vcpu_safe().\n+\t */\n+\tsmp_store_release(\u0026vcpu-\u003earch.hyperv, hv_vcpu);\n \treturn 0;\n }\n \n@@ -1002,7 +1013,7 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)\n \n \tsynic = to_hv_synic(vcpu);\n \n-\tsynic-\u003eactive = true;\n+\tWRITE_ONCE(synic-\u003eactive, true);\n \tsynic-\u003edont_zero_synic_pages = dont_zero_synic_pages;\n \tsynic-\u003econtrol = HV_SYNIC_CONTROL_ENABLE;\n \treturn 0;\n@@ -1935,14 +1946,14 @@ static int kvm_hv_get_tlb_flush_entries(struct kvm *kvm, struct kvm_hv_hcall *hc\n \treturn kvm_hv_get_hc_data(kvm, hc, hc-\u003erep_cnt, hc-\u003erep_cnt, entries);\n }\n \n-static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,\n-\t\t\t\t struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo,\n-\t\t\t\t u64 *entries, int count)\n+static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu, u64 *entries, int count,\n+\t\t\t\t bool is_guest_mode)\n {\n-\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);\n+\tstruct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;\n \tu64 flush_all_entry = KVM_HV_TLB_FLUSHALL_ENTRY;\n \n-\tif (!hv_vcpu)\n+\ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode);\n+\tif (!tlb_flush_fifo)\n \t\treturn;\n \n \tspin_lock(\u0026tlb_flush_fifo-\u003ewrite_lock);\n@@ -1970,15 +1981,16 @@ static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,\n int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;\n-\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);\n \tu64 entries[KVM_HV_TLB_FLUSH_FIFO_SIZE];\n \tint i, j, count;\n \tgva_t gva;\n \n-\tif (!tdp_enabled || !hv_vcpu)\n+\tif (!tdp_enabled)\n \t\treturn -EINVAL;\n \n \ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));\n+\tif (!tlb_flush_fifo)\n+\t\treturn -EINVAL;\n \n \tcount = kfifo_out(\u0026tlb_flush_fifo-\u003eentries, entries, KVM_HV_TLB_FLUSH_FIFO_SIZE);\n \n@@ -2017,7 +2029,6 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\n \tstruct kvm *kvm = vcpu-\u003ekvm;\n \tstruct hv_tlb_flush_ex flush_ex;\n \tstruct hv_tlb_flush flush;\n-\tstruct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;\n \t/*\n \t * Normally, there can be no more than 'KVM_HV_TLB_FLUSH_FIFO_SIZE'\n \t * entries on the TLB flush fifo. The last entry, however, needs to be\n@@ -2144,11 +2155,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\n \t * analyze it here, flush TLB regardless of the specified address space.\n \t */\n \tif (all_cpus \u0026\u0026 !is_guest_mode(vcpu)) {\n-\t\tkvm_for_each_vcpu(i, v, kvm) {\n-\t\t\ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);\n-\t\t\thv_tlb_flush_enqueue(v, tlb_flush_fifo,\n-\t\t\t\t\t tlb_flush_entries, hc-\u003erep_cnt);\n-\t\t}\n+\t\tkvm_for_each_vcpu(i, v, kvm)\n+\t\t\thv_tlb_flush_enqueue(v, tlb_flush_entries, hc-\u003erep_cnt, false);\n \n \t\tkvm_make_all_cpus_request(kvm, KVM_REQ_HV_TLB_FLUSH);\n \t} else if (!is_guest_mode(vcpu)) {\n@@ -2158,9 +2166,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\n \t\t\tv = kvm_get_vcpu(kvm, i);\n \t\t\tif (!v)\n \t\t\t\tcontinue;\n-\t\t\ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);\n-\t\t\thv_tlb_flush_enqueue(v, tlb_flush_fifo,\n-\t\t\t\t\t tlb_flush_entries, hc-\u003erep_cnt);\n+\t\t\thv_tlb_flush_enqueue(v, tlb_flush_entries, hc-\u003erep_cnt, false);\n \t\t}\n \n \t\tkvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);\n@@ -2170,7 +2176,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\n \t\tbitmap_zero(vcpu_mask, KVM_MAX_VCPUS);\n \n \t\tkvm_for_each_vcpu(i, v, kvm) {\n-\t\t\thv_v = to_hv_vcpu(v);\n+\t\t\thv_v = to_hv_vcpu_safe(v);\n \n \t\t\t/*\n \t\t\t * The following check races with nested vCPUs entering/exiting\n@@ -2191,9 +2197,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\n \t\t\t\tcontinue;\n \n \t\t\t__set_bit(i, vcpu_mask);\n-\t\t\ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, true);\n-\t\t\thv_tlb_flush_enqueue(v, tlb_flush_fifo,\n-\t\t\t\t\t tlb_flush_entries, hc-\u003erep_cnt);\n+\t\t\thv_tlb_flush_enqueue(v, tlb_flush_entries, hc-\u003erep_cnt, true);\n \t\t}\n \n \t\tkvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);\ndiff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h\nindex 1c8f7aaab063d0..37a0bcf03e2816 100644\n--- a/arch/x86/kvm/hyperv.h\n+++ b/arch/x86/kvm/hyperv.h\n@@ -62,8 +62,22 @@ static inline struct kvm_hv *to_kvm_hv(struct kvm *kvm)\n \treturn \u0026kvm-\u003earch.hyperv;\n }\n \n+static inline struct kvm_vcpu_hv *to_hv_vcpu_safe(struct kvm_vcpu *vcpu)\n+{\n+\t/*\n+\t * Ensure the HyperV structure is fully initialized when accessing it\n+\t * without holding vcpu-\u003emutex (or some other guarantee that KVM can't\n+\t * concurrently instantiate the structure).\n+\t *\n+\t * Pairs with the smp_store_release() in kvm_hv_vcpu_init().\n+\t */\n+\treturn smp_load_acquire(\u0026vcpu-\u003earch.hyperv);\n+}\n+\n static inline struct kvm_vcpu_hv *to_hv_vcpu(struct kvm_vcpu *vcpu)\n {\n+\tkvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);\n+\n \treturn vcpu-\u003earch.hyperv;\n }\n \n@@ -88,7 +102,7 @@ static inline struct kvm_hv_syndbg *to_hv_syndbg(struct kvm_vcpu *vcpu)\n \n static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu)\n {\n-\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);\n+\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);\n \n \treturn hv_vcpu ? hv_vcpu-\u003evp_index : vcpu-\u003evcpu_idx;\n }\n@@ -142,7 +156,7 @@ static inline struct kvm_vcpu *hv_stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stim\n \n static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)\n {\n-\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);\n+\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);\n \n \tif (!hv_vcpu)\n \t\treturn false;\n@@ -198,10 +212,13 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,\n static inline struct kvm_vcpu_hv_tlb_flush_fifo *kvm_hv_get_tlb_flush_fifo(struct kvm_vcpu *vcpu,\n \t\t\t\t\t\t\t\t\t bool is_guest_mode)\n {\n-\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);\n+\tstruct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);\n \tint i = is_guest_mode ? HV_L2_TLB_FLUSH_FIFO :\n \t\t\t\tHV_L1_TLB_FLUSH_FIFO;\n \n+\tif (!hv_vcpu)\n+\t\treturn NULL;\n+\n \treturn \u0026hv_vcpu-\u003etlb_flush_fifo[i];\n }\n \n@@ -209,10 +226,12 @@ static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;\n \n-\tif (!to_hv_vcpu(vcpu) || !kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))\n+\tif (!kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))\n \t\treturn;\n \n \ttlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));\n+\tif (!tlb_flush_fifo)\n+\t\treturn;\n \n \tkfifo_reset_out(\u0026tlb_flush_fifo-\u003eentries);\n }\ndiff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h\nindex 6d6cd5904ddf66..c6de848bd9ced5 100644\n--- a/arch/x86/kvm/vmx/nested.h\n+++ b/arch/x86/kvm/vmx/nested.h\n@@ -57,16 +57,14 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,\n \n static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)\n {\n-\tlockdep_assert_once(lockdep_is_held(\u0026vcpu-\u003emutex) ||\n-\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003eusers_count));\n+\tkvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);\n \n \treturn to_vmx(vcpu)-\u003enested.cached_vmcs12;\n }\n \n static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)\n {\n-\tlockdep_assert_once(lockdep_is_held(\u0026vcpu-\u003emutex) ||\n-\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003eusers_count));\n+\tkvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);\n \n \treturn to_vmx(vcpu)-\u003enested.cached_shadow_vmcs12;\n }\ndiff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c\nindex 694b31c1fcc9af..eef378d0bb4557 100644\n--- a/arch/x86/kvm/xen.c\n+++ b/arch/x86/kvm/xen.c\n@@ -22,6 +22,7 @@\n #include \u003cxen/interface/version.h\u003e\n #include \u003cxen/interface/event_channel.h\u003e\n #include \u003cxen/interface/sched.h\u003e\n+#include \u003cxen/xen-ops.h\u003e\n \n #include \u003casm/xen/cpuid.h\u003e\n #include \u003casm/pvclock.h\u003e\n@@ -1103,6 +1104,8 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)\n \t\tbreak;\n \n \tcase KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID:\n+\t\tBUILD_BUG_ON(XEN_VCPU_ID_INVALID \u003c KVM_MAX_VCPUS);\n+\n \t\tif (data-\u003eu.vcpu_id \u003e= KVM_MAX_VCPUS)\n \t\t\tr = -EINVAL;\n \t\telse {\n@@ -1607,16 +1610,28 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,\n \tstruct vcpu_set_singleshot_timer oneshot;\n \tstruct x86_exception e;\n \n+\tif (cmd != VCPUOP_set_singleshot_timer \u0026\u0026\n+\t cmd != VCPUOP_stop_singleshot_timer)\n+\t\treturn false;\n+\n \tif (!kvm_xen_timer_enabled(vcpu))\n \t\treturn false;\n \n-\tswitch (cmd) {\n-\tcase VCPUOP_set_singleshot_timer:\n-\t\tif (vcpu-\u003earch.xen.vcpu_id != vcpu_id) {\n-\t\t\t*r = -EINVAL;\n-\t\t\treturn true;\n-\t\t}\n+\tif (vcpu-\u003earch.xen.vcpu_id == XEN_VCPU_ID_INVALID)\n+\t\treturn false;\n+\n+\t/*\n+\t * Reject the hypercall if the guest is trying to start/stop the timer\n+\t * for a different vCPU. Xen per-vCPU hypercalls take a target vCPU as\n+\t * a common parameter, as all per-vCPU hypercalls *except* single-shot\n+\t * timer updates can be cross-vCPU.\n+\t */\n+\tif (vcpu-\u003earch.xen.vcpu_id != vcpu_id) {\n+\t\t*r = -EINVAL;\n+\t\treturn true;\n+\t}\n \n+\tif (cmd == VCPUOP_set_singleshot_timer) {\n \t\t/*\n \t\t * The only difference for 32-bit compat is the 4 bytes of\n \t\t * padding after the interesting part of the structure. So\n@@ -1640,20 +1655,12 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,\n \t\t}\n \n \t\tkvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, false);\n-\t\t*r = 0;\n-\t\treturn true;\n-\n-\tcase VCPUOP_stop_singleshot_timer:\n-\t\tif (vcpu-\u003earch.xen.vcpu_id != vcpu_id) {\n-\t\t\t*r = -EINVAL;\n-\t\t\treturn true;\n-\t\t}\n+\t} else {\n \t\tkvm_xen_stop_timer(vcpu);\n-\t\t*r = 0;\n-\t\treturn true;\n \t}\n \n-\treturn false;\n+\t*r = 0;\n+\treturn true;\n }\n \n static bool kvm_xen_hcall_set_timer_op(struct kvm_vcpu *vcpu, uint64_t timeout,\n@@ -2299,7 +2306,7 @@ static bool kvm_xen_hcall_evtchn_send(struct kvm_vcpu *vcpu, u64 param, u64 *r)\n \n void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu)\n {\n-\tvcpu-\u003earch.xen.vcpu_id = vcpu-\u003evcpu_idx;\n+\tvcpu-\u003earch.xen.vcpu_id = XEN_VCPU_ID_INVALID;\n \tvcpu-\u003earch.xen.poll_evtchn = 0;\n \n \ttimer_setup(\u0026vcpu-\u003earch.xen.poll_timer, cancel_evtchn_poll, 0);\ndiff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h\nindex ab8cfaec82d31e..0bdfa36993527e 100644\n--- a/include/linux/kvm_host.h\n+++ b/include/linux/kvm_host.h\n@@ -989,6 +989,13 @@ static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx)\n \t\t\t\t\t lockdep_is_held(\u0026kvm-\u003eslots_lock));\n }\n \n+static inline void kvm_lockdep_assert_vcpu_is_locked_or_unreachable(struct kvm_vcpu *vcpu)\n+{\n+\tlockdep_assert_once(lockdep_is_held(\u0026vcpu-\u003emutex) ||\n+\t\t\t vcpu-\u003evcpu_idx \u003c 0 ||\n+\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003eusers_count));\n+}\n+\n static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)\n {\n \tint num_vcpus = atomic_read(\u0026kvm-\u003eonline_vcpus);\ndiff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c\nindex e44c20c049610d..05275d318bfbc7 100644\n--- a/virt/kvm/kvm_main.c\n+++ b/virt/kvm/kvm_main.c\n@@ -4188,6 +4188,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)\n \t\tgoto vcpu_decrement;\n \t}\n \n+\tvcpu-\u003evcpu_idx = -1;\n+\n \tBUILD_BUG_ON(sizeof(struct kvm_run) \u003e PAGE_SIZE);\n \tpage = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);\n \tif (!page) {\n@@ -4216,6 +4218,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)\n \t\tgoto unlock_vcpu_destroy;\n \t}\n \n+\t/*\n+\t * Set the vCPU's index *before* the vCPU is reachable by other tasks.\n+\t * Unwind the index back to -1 on failure so that KVM can use the index\n+\t * to detect that the vCPU is unreachable, e.g. for lockdep asserts.\n+\t */\n \tvcpu-\u003evcpu_idx = atomic_read(\u0026kvm-\u003eonline_vcpus);\n \tr = xa_insert(\u0026kvm-\u003evcpu_array, vcpu-\u003evcpu_idx, vcpu, GFP_KERNEL_ACCOUNT);\n \tWARN_ON_ONCE(r == -EBUSY);\n@@ -4254,6 +4261,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)\n \tkvm_put_kvm_no_destroy(kvm);\n \txa_erase(\u0026kvm-\u003evcpu_array, vcpu-\u003evcpu_idx);\n unlock_vcpu_destroy:\n+\tvcpu-\u003evcpu_idx = -1;\n \tmutex_unlock(\u0026kvm-\u003elock);\n \tkvm_dirty_ring_free(\u0026vcpu-\u003edirty_ring);\n arch_vcpu_destroy:\n"
} |
| 2/1 | 2026/07/01 05:53 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"KVM_HYPERV",
"KVM_XEN"
],
"FocusSymbols": [
"kvm_hv_flush_tlb",
"kvm_xen_hcall_vcpu_op",
"kvm_xen_vcpu_set_attr",
"kvm_hv_vcpu_flush_tlb",
"kvm_hv_activate_synic"
],
"Reasoning": "The patch modifies KVM Hyper-V and Xen emulation logic, specifically fixing race conditions and initialization issues related to vCPU structures, TLB flushing, and timers. These are functional changes to reachable core kernel logic that should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 46107f019722a27ee193f5c82515aa5545cbaa9f
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Jul 1 05:53:34 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 1ee0d23f894974..9d38cb644668da 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -206,14 +206,20 @@ static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx)
static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx)
{
- struct kvm_vcpu *vcpu;
struct kvm_vcpu_hv_synic *synic;
+ struct kvm_vcpu_hv *hv_vcpu;
+ struct kvm_vcpu *vcpu;
vcpu = get_vcpu_by_vpidx(kvm, vpidx);
- if (!vcpu || !to_hv_vcpu(vcpu))
+ if (!vcpu)
return NULL;
- synic = to_hv_synic(vcpu);
- return (synic->active) ? synic : NULL;
+
+ hv_vcpu = to_hv_vcpu_safe(vcpu);
+ if (!hv_vcpu)
+ return NULL;
+
+ synic = &hv_vcpu->synic;
+ return READ_ONCE(synic->active) ? synic : NULL;
}
static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
@@ -593,8 +599,7 @@ static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,
{
struct kvm_vcpu *vcpu = hv_stimer_to_vcpu(stimer);
- set_bit(stimer->index,
- to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ set_bit(stimer->index, vcpu->arch.hyperv->stimer_pending_bitmap);
kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
if (vcpu_kick)
kvm_vcpu_kick(vcpu);
@@ -608,8 +613,7 @@ static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)
stimer->index);
hrtimer_cancel(&stimer->timer);
- clear_bit(stimer->index,
- to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ clear_bit(stimer->index, vcpu->arch.hyperv->stimer_pending_bitmap);
stimer->msg_pending = false;
stimer->exp_time = 0;
}
@@ -972,7 +976,6 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
if (!hv_vcpu)
return -ENOMEM;
- vcpu->arch.hyperv = hv_vcpu;
hv_vcpu->vcpu = vcpu;
synic_init(&hv_vcpu->synic);
@@ -988,6 +991,14 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
spin_lock_init(&hv_vcpu->tlb_flush_fifo[i].write_lock);
}
+ /*
+ * Ensure the structure is fully initialized before it's visible to
+ * other tasks, as much of the state can be legally accessed without
+ * holding vcpu->mutex.
+ *
+ * Pairs with the smp_load_acquire() in to_hv_vcpu_safe().
+ */
+ smp_store_release(&vcpu->arch.hyperv, hv_vcpu);
return 0;
}
@@ -1002,7 +1013,7 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
synic = to_hv_synic(vcpu);
- synic->active = true;
+ WRITE_ONCE(synic->active, true);
synic->dont_zero_synic_pages = dont_zero_synic_pages;
synic->control = HV_SYNIC_CONTROL_ENABLE;
return 0;
@@ -1935,14 +1946,14 @@ static int kvm_hv_get_tlb_flush_entries(struct kvm *kvm, struct kvm_hv_hcall *hc
return kvm_hv_get_hc_data(kvm, hc, hc->rep_cnt, hc->rep_cnt, entries);
}
-static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,
- struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo,
- u64 *entries, int count)
+static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu, u64 *entries, int count,
+ bool is_guest_mode)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
u64 flush_all_entry = KVM_HV_TLB_FLUSHALL_ENTRY;
- if (!hv_vcpu)
+ tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode);
+ if (!tlb_flush_fifo)
return;
spin_lock(&tlb_flush_fifo->write_lock);
@@ -1970,15 +1981,16 @@ static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
u64 entries[KVM_HV_TLB_FLUSH_FIFO_SIZE];
int i, j, count;
gva_t gva;
- if (!tdp_enabled || !hv_vcpu)
+ if (!tdp_enabled)
return -EINVAL;
tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));
+ if (!tlb_flush_fifo)
+ return -EINVAL;
count = kfifo_out(&tlb_flush_fifo->entries, entries, KVM_HV_TLB_FLUSH_FIFO_SIZE);
@@ -2017,7 +2029,6 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
struct kvm *kvm = vcpu->kvm;
struct hv_tlb_flush_ex flush_ex;
struct hv_tlb_flush flush;
- struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
/*
* Normally, there can be no more than 'KVM_HV_TLB_FLUSH_FIFO_SIZE'
* entries on the TLB flush fifo. The last entry, however, needs to be
@@ -2144,11 +2155,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
* analyze it here, flush TLB regardless of the specified address space.
*/
if (all_cpus && !is_guest_mode(vcpu)) {
- kvm_for_each_vcpu(i, v, kvm) {
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
- }
+ kvm_for_each_vcpu(i, v, kvm)
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, false);
kvm_make_all_cpus_request(kvm, KVM_REQ_HV_TLB_FLUSH);
} else if (!is_guest_mode(vcpu)) {
@@ -2158,9 +2166,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
v = kvm_get_vcpu(kvm, i);
if (!v)
continue;
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, false);
}
kvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);
@@ -2170,7 +2176,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);
kvm_for_each_vcpu(i, v, kvm) {
- hv_v = to_hv_vcpu(v);
+ hv_v = to_hv_vcpu_safe(v);
/*
* The following check races with nested vCPUs entering/exiting
@@ -2191,9 +2197,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
continue;
__set_bit(i, vcpu_mask);
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, true);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, true);
}
kvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index 1c8f7aaab063d0..37a0bcf03e2816 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -62,8 +62,22 @@ static inline struct kvm_hv *to_kvm_hv(struct kvm *kvm)
return &kvm->arch.hyperv;
}
+static inline struct kvm_vcpu_hv *to_hv_vcpu_safe(struct kvm_vcpu *vcpu)
+{
+ /*
+ * Ensure the HyperV structure is fully initialized when accessing it
+ * without holding vcpu->mutex (or some other guarantee that KVM can't
+ * concurrently instantiate the structure).
+ *
+ * Pairs with the smp_store_release() in kvm_hv_vcpu_init().
+ */
+ return smp_load_acquire(&vcpu->arch.hyperv);
+}
+
static inline struct kvm_vcpu_hv *to_hv_vcpu(struct kvm_vcpu *vcpu)
{
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
+
return vcpu->arch.hyperv;
}
@@ -88,7 +102,7 @@ static inline struct kvm_hv_syndbg *to_hv_syndbg(struct kvm_vcpu *vcpu)
static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
return hv_vcpu ? hv_vcpu->vp_index : vcpu->vcpu_idx;
}
@@ -142,7 +156,7 @@ static inline struct kvm_vcpu *hv_stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stim
static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
if (!hv_vcpu)
return false;
@@ -198,10 +212,13 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
static inline struct kvm_vcpu_hv_tlb_flush_fifo *kvm_hv_get_tlb_flush_fifo(struct kvm_vcpu *vcpu,
bool is_guest_mode)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
int i = is_guest_mode ? HV_L2_TLB_FLUSH_FIFO :
HV_L1_TLB_FLUSH_FIFO;
+ if (!hv_vcpu)
+ return NULL;
+
return &hv_vcpu->tlb_flush_fifo[i];
}
@@ -209,10 +226,12 @@ static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
- if (!to_hv_vcpu(vcpu) || !kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
+ if (!kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
return;
tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));
+ if (!tlb_flush_fifo)
+ return;
kfifo_reset_out(&tlb_flush_fifo->entries);
}
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index 6d6cd5904ddf66..c6de848bd9ced5 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -57,16 +57,14 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
{
- lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
return to_vmx(vcpu)->nested.cached_vmcs12;
}
static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
{
- lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
}
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 694b31c1fcc9af..eef378d0bb4557 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -22,6 +22,7 @@
#include <xen/interface/version.h>
#include <xen/interface/event_channel.h>
#include <xen/interface/sched.h>
+#include <xen/xen-ops.h>
#include <asm/xen/cpuid.h>
#include <asm/pvclock.h>
@@ -1103,6 +1104,8 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
break;
case KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID:
+ BUILD_BUG_ON(XEN_VCPU_ID_INVALID < KVM_MAX_VCPUS);
+
if (data->u.vcpu_id >= KVM_MAX_VCPUS)
r = -EINVAL;
else {
@@ -1607,16 +1610,28 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,
struct vcpu_set_singleshot_timer oneshot;
struct x86_exception e;
+ if (cmd != VCPUOP_set_singleshot_timer &&
+ cmd != VCPUOP_stop_singleshot_timer)
+ return false;
+
if (!kvm_xen_timer_enabled(vcpu))
return false;
- switch (cmd) {
- case VCPUOP_set_singleshot_timer:
- if (vcpu->arch.xen.vcpu_id != vcpu_id) {
- *r = -EINVAL;
- return true;
- }
+ if (vcpu->arch.xen.vcpu_id == XEN_VCPU_ID_INVALID)
+ return false;
+
+ /*
+ * Reject the hypercall if the guest is trying to start/stop the timer
+ * for a different vCPU. Xen per-vCPU hypercalls take a target vCPU as
+ * a common parameter, as all per-vCPU hypercalls *except* single-shot
+ * timer updates can be cross-vCPU.
+ */
+ if (vcpu->arch.xen.vcpu_id != vcpu_id) {
+ *r = -EINVAL;
+ return true;
+ }
+ if (cmd == VCPUOP_set_singleshot_timer) {
/*
* The only difference for 32-bit compat is the 4 bytes of
* padding after the interesting part of the structure. So
@@ -1640,20 +1655,12 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,
}
kvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, false);
- *r = 0;
- return true;
-
- case VCPUOP_stop_singleshot_timer:
- if (vcpu->arch.xen.vcpu_id != vcpu_id) {
- *r = -EINVAL;
- return true;
- }
+ } else {
kvm_xen_stop_timer(vcpu);
- *r = 0;
- return true;
}
- return false;
+ *r = 0;
+ return true;
}
static bool kvm_xen_hcall_set_timer_op(struct kvm_vcpu *vcpu, uint64_t timeout,
@@ -2299,7 +2306,7 @@ static bool kvm_xen_hcall_evtchn_send(struct kvm_vcpu *vcpu, u64 param, u64 *r)
void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu)
{
- vcpu->arch.xen.vcpu_id = vcpu->vcpu_idx;
+ vcpu->arch.xen.vcpu_id = XEN_VCPU_ID_INVALID;
vcpu->arch.xen.poll_evtchn = 0;
timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ab8cfaec82d31e..0bdfa36993527e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -989,6 +989,13 @@ static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx)
lockdep_is_held(&kvm->slots_lock));
}
+static inline void kvm_lockdep_assert_vcpu_is_locked_or_unreachable(struct kvm_vcpu *vcpu)
+{
+ lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
+ vcpu->vcpu_idx < 0 ||
+ !refcount_read(&vcpu->kvm->users_count));
+}
+
static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
{
int num_vcpus = atomic_read(&kvm->online_vcpus);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index e44c20c049610d..05275d318bfbc7 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4188,6 +4188,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto vcpu_decrement;
}
+ vcpu->vcpu_idx = -1;
+
BUILD_BUG_ON(sizeof(struct kvm_run) > PAGE_SIZE);
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page) {
@@ -4216,6 +4218,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto unlock_vcpu_destroy;
}
+ /*
+ * Set the vCPU's index *before* the vCPU is reachable by other tasks.
+ * Unwind the index back to -1 on failure so that KVM can use the index
+ * to detect that the vCPU is unreachable, e.g. for lockdep asserts.
+ */
vcpu->vcpu_idx = atomic_read(&kvm->online_vcpus);
r = xa_insert(&kvm->vcpu_array, vcpu->vcpu_idx, vcpu, GFP_KERNEL_ACCOUNT);
WARN_ON_ONCE(r == -EBUSY);
@@ -4254,6 +4261,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
kvm_put_kvm_no_destroy(kvm);
xa_erase(&kvm->vcpu_array, vcpu->vcpu_idx);
unlock_vcpu_destroy:
+ vcpu->vcpu_idx = -1;
mutex_unlock(&kvm->lock);
kvm_dirty_ring_free(&vcpu->dirty_ring);
arch_vcpu_destroy:
|
| 3/2 | 2026/07/01 05:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8179 output: 34 thoughts: 777 Thoughts: **Analyzing KVM Patch for Fuzzing Potential** Okay, so I've got this patch that's touching KVM code, specifically related to the emulation of Hyper-V and Xen on x86, which is always interesting. My initial assessment is that these are functional changes, impacting core kernel logic within KVM. This immediately flags it as a "WorthFuzzing=true" situation. I need to dig deeper. The changes are distributed across several files: `hyperv.c`, `hyperv.h`, `nested.h`, `xen.c`, `kvm_host.h`, and `kvm_main.c`. It looks like we're hitting both Hyper-V and Xen-specific functionality, which is a good sign for fuzzing different emulation paths. The specific functions that are modified are: `synic_get`, `stimer_mark_pending`, `stimer_cleanup`, `kvm_hv_vcpu_init`, `kvm_hv_activate_synic`, `hv_tlb_flush_enqueue`, `kvm_hv_vcpu_flush_tlb`, `kvm_hv_flush_tlb`, `kvm_xen_vcpu_set_attr`, `kvm_xen_hcall_vcpu_op`, `kvm_xen_init_vcpu`, and `kvm_vm_ioctl_create_vcpu`. Now, for fuzzing, I want to prioritize specific targets. Based on my experience, I want to avoid anything that's too generic like `kvm_vm_ioctl_create_vcpu` if it's not a hot-path, but I should probably confirm that. I'm focusing on hypercall and ioctl handlers. `kvm_hv_flush_tlb`, `kvm_xen_hcall_vcpu_op`, and `kvm_xen_vcpu_set_attr` are all excellent targets. `kvm_hv_vcpu_flush_tlb` and `kvm_hv_activate_synic` are likely also interesting. The others need more context to assess. Next, I need to check the Kconfig options to ensure the relevant features are enabled. Obviously, `KVM` itself is required, but I need to determine if any of these changes are gated behind specific configurations for Hyper-V or Xen support. I'll grep for options like `KVM_XEN` or `KVM_HYPERV` in the Kconfig files and see what I find. This will help tailor fuzzing configurations to trigger the modified code. |
| 4/2 | 2026/07/01 05:53 | tool | grepper |
0mArgs:{
"Expression": "config KVM",
"PathPrefix": "arch/x86/kvm/Kconfig"
}Results: {
"Output": "arch/x86/kvm/Kconfig=18=if VIRTUALIZATION\narch/x86/kvm/Kconfig-19-\narch/x86/kvm/Kconfig:20:config KVM_X86\narch/x86/kvm/Kconfig-21-\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n--\narch/x86/kvm/Kconfig-51-\narch/x86/kvm/Kconfig:52:config KVM\narch/x86/kvm/Kconfig-53-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/x86/kvm/Kconfig-68-\narch/x86/kvm/Kconfig:69:config KVM_WERROR\narch/x86/kvm/Kconfig-70-\tbool \"Compile KVM with -Werror\"\n--\narch/x86/kvm/Kconfig-82-\narch/x86/kvm/Kconfig:83:config KVM_SW_PROTECTED_VM\narch/x86/kvm/Kconfig-84-\tbool \"Enable support for KVM software-protected VMs\"\n--\narch/x86/kvm/Kconfig-95-\narch/x86/kvm/Kconfig:96:config KVM_INTEL\narch/x86/kvm/Kconfig-97-\ttristate \"KVM for Intel (and compatible) processors support\"\n--\narch/x86/kvm/Kconfig-106-\narch/x86/kvm/Kconfig:107:config KVM_INTEL_PROVE_VE\narch/x86/kvm/Kconfig-108- bool \"Check that guests do not receive #VE exceptions\"\n--\narch/x86/kvm/Kconfig=122=config X86_SGX_KVM\n--\narch/x86/kvm/Kconfig-133-\narch/x86/kvm/Kconfig:134:config KVM_INTEL_TDX\narch/x86/kvm/Kconfig-135-\tbool \"Intel Trust Domain Extensions (TDX) support\"\n--\narch/x86/kvm/Kconfig-145-\narch/x86/kvm/Kconfig:146:config KVM_AMD\narch/x86/kvm/Kconfig-147-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-155-\narch/x86/kvm/Kconfig:156:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-157-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n--\narch/x86/kvm/Kconfig-171-\narch/x86/kvm/Kconfig:172:config KVM_IOAPIC\narch/x86/kvm/Kconfig-173-\tbool \"I/O APIC, PIC, and PIT emulation\"\n--\narch/x86/kvm/Kconfig-181-\narch/x86/kvm/Kconfig:182:config KVM_SMM\narch/x86/kvm/Kconfig-183-\tbool \"System Management Mode emulation\"\n--\narch/x86/kvm/Kconfig-192-\narch/x86/kvm/Kconfig:193:config KVM_HYPERV\narch/x86/kvm/Kconfig-194-\tbool \"Support for Microsoft Hyper-V emulation\"\n--\narch/x86/kvm/Kconfig-206-\narch/x86/kvm/Kconfig:207:config KVM_XEN\narch/x86/kvm/Kconfig-208-\tbool \"Support for Xen hypercall interface\"\n--\narch/x86/kvm/Kconfig-215-\narch/x86/kvm/Kconfig:216:config KVM_PROVE_MMU\narch/x86/kvm/Kconfig-217-\tbool \"Prove KVM MMU correctness\"\n--\narch/x86/kvm/Kconfig-228-\narch/x86/kvm/Kconfig:229:config KVM_EXTERNAL_WRITE_TRACKING\narch/x86/kvm/Kconfig-230-\tbool\narch/x86/kvm/Kconfig-231-\narch/x86/kvm/Kconfig:232:config KVM_MAX_NR_VCPUS\narch/x86/kvm/Kconfig-233-\tint \"Maximum number of vCPUs per KVM guest\"\n"
} |
| 5/2 | 2026/07/01 05:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10766 output: 36 thoughts: 32 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Kernel Configuration Context** Alright, so the focus is on hypervisor support within the kernel. Immediately, the names `KVM_HYPERV` and `KVM_XEN` jump out. These are the configurations relating to Hyper-V and Xen support respectively, and it's logical to assume that they are key to enabling virtualization functionality on this platform. I’m thinking we need to quickly determine whether these modules are *essential* to this setup. That is to say, I'm already formulating the next question. Do we need them, or are there alternatives at play? What are the implications of the current config. |
| 6/2 | 2026/07/01 05:53 | tool | grepper |
0mArgs:{
"Expression": "KVM_HYPERV",
"PathPrefix": "arch/x86/kvm/Makefile"
}Results: {
"Output": "arch/x86/kvm/Makefile=12=kvm-$(CONFIG_KVM_IOAPIC) += i8259.o i8254.o ioapic.o\narch/x86/kvm/Makefile:13:kvm-$(CONFIG_KVM_HYPERV) += hyperv.o\narch/x86/kvm/Makefile-14-kvm-$(CONFIG_KVM_XEN)\t+= xen.o\n--\narch/x86/kvm/Makefile=20=kvm-intel-$(CONFIG_X86_SGX_KVM)\t+= vmx/sgx.o\narch/x86/kvm/Makefile:21:kvm-intel-$(CONFIG_KVM_HYPERV)\t+= vmx/hyperv.o vmx/hyperv_evmcs.o\narch/x86/kvm/Makefile-22-kvm-intel-$(CONFIG_KVM_INTEL_TDX)\t+= vmx/tdx.o\n--\narch/x86/kvm/Makefile=26=kvm-amd-$(CONFIG_KVM_AMD_SEV)\t+= svm/sev.o\narch/x86/kvm/Makefile:27:kvm-amd-$(CONFIG_KVM_HYPERV)\t+= svm/hyperv.o\narch/x86/kvm/Makefile-28-\n"
} |
| 7/2 | 2026/07/01 05:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11336 output: 42 thoughts: 302 Thoughts: **Fuzzing Target Identification** Okay, so I see that compiling `hyperv.o` and `xen.o` definitely requires `KVM_HYPERV` and `KVM_XEN`. I should double-check to make sure there aren't any other configs I need to be aware of, but based on the patch, those seem to be the critical ones. It's modifying `arch/x86/kvm/hyperv.c` and `arch/x86/kvm/xen.c`, so that confirms it. Now, let's get down to brass tacks: what should I focus my fuzzing efforts on? From the context, I've got a list: `kvm_hv_flush_tlb`, `kvm_xen_hcall_vcpu_op`, `kvm_xen_vcpu_set_attr`, `kvm_hv_vcpu_flush_tlb`, `kvm_hv_activate_synic`, and `kvm_hv_vcpu_init`. Wait, this is interesting. I'm seeing that `kvm_hv_flush_tlb` and `kvm_xen_hcall_vcpu_op` are hypercall handlers. Excellent targets, as expected. And `kvm_xen_vcpu_set_attr` is an ioctl handler! Even better. These are prime candidates to throw some fuzzing data at. I should probably give `kvm_hv_vcpu_flush_tlb` another look too. Right, I'm going to double-check those two hypercall handlers, `kvm_hv_flush_tlb` and `kvm_xen_hcall_vcpu_op`, to make sure they're what I think they are. These are going to be key. |
| 8/2 | 2026/07/01 05:53 | tool | grepper |
0mArgs:{
"Expression": "kvm_hv_flush_tlb",
"PathPrefix": "arch/x86/kvm/hyperv.c"
}Results: {
"Output": "arch/x86/kvm/hyperv.c=1981=int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/hyperv.c-2023-\narch/x86/kvm/hyperv.c:2024:static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)\narch/x86/kvm/hyperv.c-2025-{\n--\narch/x86/kvm/hyperv.c-2079-\narch/x86/kvm/hyperv.c:2080:\t\ttrace_kvm_hv_flush_tlb(flush.processor_mask,\narch/x86/kvm/hyperv.c-2081-\t\t\t\t flush.address_space, flush.flags,\n--\narch/x86/kvm/hyperv.c-2109-\narch/x86/kvm/hyperv.c:2110:\t\ttrace_kvm_hv_flush_tlb_ex(flush_ex.hv_vp_set.valid_bank_mask,\narch/x86/kvm/hyperv.c-2111-\t\t\t\t\t flush_ex.hv_vp_set.format,\n--\narch/x86/kvm/hyperv.c-2185-\t\t\t * running on the same L1 vCPU from the moment of the request until\narch/x86/kvm/hyperv.c:2186:\t\t\t * kvm_hv_flush_tlb() returns. TLB is fully flushed in all other\narch/x86/kvm/hyperv.c-2187-\t\t\t * cases, e.g. when the target L2 vCPU migrates to a different L1\n--\narch/x86/kvm/hyperv.c=2538=int kvm_hv_hypercall(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/hyperv.c-2631-\t\t}\narch/x86/kvm/hyperv.c:2632:\t\tret = kvm_hv_flush_tlb(vcpu, \u0026hc);\narch/x86/kvm/hyperv.c-2633-\t\tbreak;\n--\narch/x86/kvm/hyperv.c-2644-\t\t}\narch/x86/kvm/hyperv.c:2645:\t\tret = kvm_hv_flush_tlb(vcpu, \u0026hc);\narch/x86/kvm/hyperv.c-2646-\t\tbreak;\n"
} |
| 9/2 | 2026/07/01 05:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12767 output: 44 thoughts: 44 Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as an expert in the field: **Tracing the TLB Flush Call** Alright, so the clue leads me to believe that `kvm_hv_flush_tlb` is indeed invoked within the `kvm_hv_hypercall` function. That makes sense, given the context. The next logical step is to see how this hypercall is being handled. I need to understand the path of execution to determine when and why the TLB flush is happening. I'll need to dive into the implementation of `kvm_xen_hcall_vcpu_op`. That's where I anticipate the hypercall dispatching logic resides, and that should shed light on the conditions that trigger the TLB flush within the hypervisor. This will give me a better understanding of how the virtual machine is behaving. |
| 10/2 | 2026/07/01 05:53 | tool | grepper |
0mArgs:{
"Expression": "kvm_xen_hcall_vcpu_op",
"PathPrefix": "arch/x86/kvm/xen.c"
}Results: {
"Output": "arch/x86/kvm/xen.c=1602=struct compat_vcpu_set_singleshot_timer {\n--\narch/x86/kvm/xen.c-1606-\narch/x86/kvm/xen.c:1607:static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,\narch/x86/kvm/xen.c-1608-\t\t\t\t int vcpu_id, u64 param, u64 *r)\n--\narch/x86/kvm/xen.c=1681=int kvm_xen_hypercall(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/xen.c-1743-\tcase __HYPERVISOR_vcpu_op:\narch/x86/kvm/xen.c:1744:\t\thandled = kvm_xen_hcall_vcpu_op(vcpu, longmode, params[0], params[1],\narch/x86/kvm/xen.c-1745-\t\t\t\t\t\tparams[2], \u0026r);\n"
} |
| 11/2 | 2026/07/01 05:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13345 output: 43 thoughts: 46 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Investigating the KVM/Xen Hypercall Interaction** Right, so `kvm_xen_hcall_vcpu_op` *is* definitely invoked from `kvm_xen_hypercall`. I need to confirm the exact nature of this interaction. That makes sense, given the context. Now, I'm thinking I should look closely at `kvm_xen_vcpu_set_attr`. I need to figure out how attributes are set within this whole hypercall scheme, and understand if that function will elucidate the exact data paths I'm after. This could be where the rubber meets the road, so to speak, in understanding how KVM interacts with the Xen hypervisor at the vCPU level. |
| 12/2 | 2026/07/01 05:54 | tool | grepper |
0mArgs:{
"Expression": "kvm_xen_vcpu_set_attr",
"PathPrefix": "arch/x86/kvm/xen.c"
}Results: {
"Output": "arch/x86/kvm/xen.c=852=int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)\n--\narch/x86/kvm/xen.c-906-\narch/x86/kvm/xen.c:907:int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)\narch/x86/kvm/xen.c-908-{\n"
} |
| 13/2 | 2026/07/01 05:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13764 output: 163 thoughts: 220 Thoughts: **Analyzing the KVM Patch for Fuzzing Opportunities** Okay, so I'm looking at this patch and it's modifying KVM's emulation logic, specifically the Hyper-V and Xen aspects. Right, I see that `kvm_xen_vcpu_set_attr` is an ioctl handler – that's definitely a good starting point for fuzzing. I'll need to remember that. My first thought is that these changes are functional; they're fixing races and initialization problems in the vCPU structures, TLB flushing, and timer mechanisms. These are all critical core kernel areas that are reachable, so fuzzing is certainly warranted here. Let's quickly confirm those config options. I need to make sure I get the prerequisites correct. It looks like `KVM_HYPERV` and `KVM_XEN` are the only configs I need to enable to trigger this code. Okay, good to know. I should also make a note of the key symbols I need to target in my fuzzing setup: `kvm_hv_flush_tlb`, `kvm_xen_hcall_vcpu_op`, `kvm_xen_vcpu_set_attr`, `kvm_hv_vcpu_flush_tlb`, and `kvm_hv_activate_synic`. Those are the entry points. Alright, time to get this set-results process moving. |
| 14/2 | 2026/07/01 05:54 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM_HYPERV",
"KVM_XEN"
],
"FocusSymbols": [
"kvm_hv_flush_tlb",
"kvm_xen_hcall_vcpu_op",
"kvm_xen_vcpu_set_attr",
"kvm_hv_vcpu_flush_tlb",
"kvm_hv_activate_synic"
],
"Reasoning": "The patch modifies KVM Hyper-V and Xen emulation logic, specifically fixing race conditions and initialization issues related to vCPU structures, TLB flushing, and timers. These are functional changes to reachable core kernel logic that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM_HYPERV",
"KVM_XEN"
],
"FocusSymbols": [
"kvm_hv_flush_tlb",
"kvm_xen_hcall_vcpu_op",
"kvm_xen_vcpu_set_attr",
"kvm_hv_vcpu_flush_tlb",
"kvm_hv_activate_synic"
],
"Reasoning": "The patch modifies KVM Hyper-V and Xen emulation logic, specifically fixing race conditions and initialization issues related to vCPU structures, TLB flushing, and timers. These are functional changes to reachable core kernel logic that should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|