| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/15 13:41 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "All changes in this patch series are strictly confined to the ARM64 KVM subsystem (arch/arm64/include/asm/kvm_host.h and arch/arm64/kvm/*). These files and code paths are exclusive to the ARM64 architecture and are not compiled or executable on the target architecture (amd64).",
"WorthFuzzing": false
} |
| 1/1 | 2026/10/15 13:41 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 7d8e22d0fb1808ab50f4de5b60472573258f12de\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Oct 15 13:41:52 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h\nindex cd9b9d2462f96..7b4f7b6d94b8d 100644\n--- a/arch/arm64/include/asm/kvm_host.h\n+++ b/arch/arm64/include/asm/kvm_host.h\n@@ -889,11 +889,10 @@ struct kvm_vcpu_arch {\n \t/*\n \t * Don't run the guest (internal implementation need).\n \t *\n-\t * Contrary to the flags above, this is set/cleared outside of\n-\t * a vcpu context, and thus cannot be mixed with the flags\n-\t * themselves (or the flag accesses need to be made atomic).\n+\t * Contrary to the flags above, this is updated outside of\n+\t * a vcpu context, and thus cannot be mixed with the flags.\n \t */\n-\tbool pause;\n+\tatomic_t pause;\n \n \t/*\n \t * We maintain more than a single set of debug registers to support\n@@ -1255,6 +1254,8 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,\n \n void kvm_arm_halt_guest(struct kvm *kvm);\n void kvm_arm_resume_guest(struct kvm *kvm);\n+void kvm_pause_vcpu(struct kvm_vcpu *vcpu);\n+void kvm_resume_vcpu(struct kvm_vcpu *vcpu);\n \n #define vcpu_has_run_once(vcpu)\t(!!READ_ONCE((vcpu)-\u003epid))\n \ndiff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c\nindex 0576c2022ef57..a2f1606822614 100644\n--- a/arch/arm64/kvm/arm.c\n+++ b/arch/arm64/kvm/arm.c\n@@ -565,6 +565,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n \tkvm_arm_pvtime_vcpu_init(\u0026vcpu-\u003earch);\n \n \tvcpu-\u003earch.hw_mmu = \u0026vcpu-\u003ekvm-\u003earch.mmu;\n+\tatomic_set(\u0026vcpu-\u003earch.pause, 0);\n \n \t/*\n \t * This vCPU may have been created after mpidr_data was initialized.\n@@ -839,6 +840,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,\n \treturn ret;\n }\n \n+static bool vcpu_can_run(struct kvm_vcpu *vcpu)\n+{\n+\treturn !kvm_arm_vcpu_stopped(vcpu) \u0026\u0026 !atomic_read(\u0026vcpu-\u003earch.pause);\n+}\n+\n /**\n * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled\n * @v:\t\tThe VCPU pointer\n@@ -854,8 +860,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)\n \t\t (kvm_timer_should_notify_user(v) ||\n \t\t kvm_pmu_should_notify_user(v)));\n \n-\treturn ((irq_lines || kvm_vgic_vcpu_pending_irq(v))\n-\t\t\u0026\u0026 !kvm_arm_vcpu_stopped(v) \u0026\u0026 !v-\u003earch.pause);\n+\treturn ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) \u0026\u0026 vcpu_can_run(v));\n }\n \n bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)\n@@ -1012,13 +1017,28 @@ bool kvm_arch_intc_initialized(struct kvm *kvm)\n \treturn vgic_initialized(kvm);\n }\n \n+void kvm_pause_vcpu(struct kvm_vcpu *vcpu)\n+{\n+\tDECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS) = { };\n+\n+\tatomic_inc(\u0026vcpu-\u003earch.pause);\n+\t__set_bit(vcpu-\u003evcpu_idx, vcpu_bitmap);\n+\tkvm_make_vcpus_request_mask(vcpu-\u003ekvm, KVM_REQ_SLEEP, vcpu_bitmap);\n+}\n+\n+void kvm_resume_vcpu(struct kvm_vcpu *vcpu)\n+{\n+\tif (atomic_dec_and_test(\u0026vcpu-\u003earch.pause))\n+\t\t__kvm_vcpu_wake_up(vcpu);\n+}\n+\n void kvm_arm_halt_guest(struct kvm *kvm)\n {\n \tunsigned long i;\n \tstruct kvm_vcpu *vcpu;\n \n \tkvm_for_each_vcpu(i, vcpu, kvm)\n-\t\tvcpu-\u003earch.pause = true;\n+\t\tatomic_inc(\u0026vcpu-\u003earch.pause);\n \tkvm_make_all_cpus_request(kvm, KVM_REQ_SLEEP);\n }\n \n@@ -1027,21 +1047,17 @@ void kvm_arm_resume_guest(struct kvm *kvm)\n \tunsigned long i;\n \tstruct kvm_vcpu *vcpu;\n \n-\tkvm_for_each_vcpu(i, vcpu, kvm) {\n-\t\tvcpu-\u003earch.pause = false;\n-\t\t__kvm_vcpu_wake_up(vcpu);\n-\t}\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tkvm_resume_vcpu(vcpu);\n }\n \n static void kvm_vcpu_sleep(struct kvm_vcpu *vcpu)\n {\n \tstruct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);\n \n-\trcuwait_wait_event(wait,\n-\t\t\t (!kvm_arm_vcpu_stopped(vcpu)) \u0026\u0026 (!vcpu-\u003earch.pause),\n-\t\t\t TASK_INTERRUPTIBLE);\n+\trcuwait_wait_event(wait, vcpu_can_run(vcpu), TASK_INTERRUPTIBLE);\n \n-\tif (kvm_arm_vcpu_stopped(vcpu) || vcpu-\u003earch.pause) {\n+\tif (!vcpu_can_run(vcpu)) {\n \t\t/* Awaken to handle a signal, request we sleep again later. */\n \t\tkvm_make_request(KVM_REQ_SLEEP, vcpu);\n \t}\n@@ -1314,38 +1330,40 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n \t\t */\n \t\tpreempt_disable();\n \n-\t\tkvm_nested_flush_hwstate(vcpu);\n-\n \t\tif (kvm_vcpu_has_pmu(vcpu))\n \t\t\tkvm_pmu_flush_hwstate(vcpu);\n \n-\t\tlocal_irq_disable();\n-\n-\t\tkvm_vgic_flush_hwstate(vcpu);\n+\t\tkvm_nested_flush_hwstate(vcpu);\n \n-\t\tkvm_pmu_update_vcpu_events(vcpu);\n+\t\tlocal_irq_disable();\n \n \t\t/*\n \t\t * Ensure we set mode to IN_GUEST_MODE after we disable\n \t\t * interrupts and before the final VCPU requests check.\n \t\t * See the comment in kvm_vcpu_exiting_guest_mode() and\n \t\t * Documentation/virt/kvm/vcpu-requests.rst\n+\t\t *\n+\t\t * Requests to self must be posted before this point, or\n+\t\t * won't be taken into account until the next exit. No state\n+\t\t * loading other than what happens at vcpu_load() time can\n+\t\t * be done before we have checked for pending requests.\n \t\t */\n \t\tsmp_store_mb(vcpu-\u003emode, IN_GUEST_MODE);\n \n \t\tif (ret \u003c= 0 || kvm_vcpu_exit_request(vcpu, \u0026ret)) {\n-\t\t\tvcpu-\u003emode = OUTSIDE_GUEST_MODE;\n-\t\t\tisb(); /* Ensure work in x_flush_hwstate is committed */\n-\t\t\tif (kvm_vcpu_has_pmu(vcpu))\n-\t\t\t\tkvm_pmu_sync_hwstate(vcpu);\n \t\t\tif (unlikely(!irqchip_in_kernel(vcpu-\u003ekvm)))\n \t\t\t\tkvm_timer_sync_user(vcpu);\n-\t\t\tkvm_vgic_sync_hwstate(vcpu);\n+\t\t\tsmp_store_release(\u0026vcpu-\u003emode, OUTSIDE_GUEST_MODE);\n \t\t\tlocal_irq_enable();\n \t\t\tpreempt_enable();\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* From here onwards, we are commited to entering the guest */\n+\t\tkvm_vgic_flush_hwstate(vcpu);\n+\n+\t\tkvm_pmu_update_vcpu_events(vcpu);\n+\n \t\tkvm_arch_vcpu_ctxflush_fp(vcpu);\n \n \t\t/**************************************************************\n@@ -1356,7 +1374,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n \n \t\tret = kvm_arm_vcpu_enter_exit(vcpu);\n \n-\t\tvcpu-\u003emode = OUTSIDE_GUEST_MODE;\n \t\tvcpu-\u003estat.exits++;\n \t\t/*\n \t\t * Back from guest\n@@ -1390,6 +1407,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n \n \t\tkvm_arch_vcpu_ctxsync_fp(vcpu);\n \n+\t\t/*\n+\t\t * All the state has been synchronised, let advertise\n+\t\t * we're outside of the guest.\n+\t\t */\n+\t\tsmp_store_release(\u0026vcpu-\u003emode, OUTSIDE_GUEST_MODE);\n+\n \t\t/*\n \t\t * We must ensure that any pending interrupts are taken before\n \t\t * we exit guest timing so that timer ticks are accounted as\ndiff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c\nindex b191365d97cc2..2fac0f2678122 100644\n--- a/arch/arm64/kvm/nested.c\n+++ b/arch/arm64/kvm/nested.c\n@@ -2046,6 +2046,9 @@ void check_nested_vcpu_requests(struct kvm_vcpu *vcpu)\n *\n * What follows is some slop to (1) react to exception routing / masking and (2)\n * preserve the pending SError state across translation regimes.\n+ *\n+ * Also generate the maintenance interrupt state, and finally check that if\n+ * we need to take an interrupt targetting the guest hypervisor.\n */\n void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)\n {\n@@ -2054,6 +2057,11 @@ void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)\n \n \tif (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING)))\n \t\tkvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu));\n+\n+\tvgic_v3_nested_update_mi(vcpu);\n+\n+\tif (vgic_state_is_nested(vcpu) \u0026\u0026 kvm_vgic_vcpu_pending_irq(vcpu))\n+\t\tkvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);\n }\n \n void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu)\ndiff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c\nindex c10a11373e106..a9949ab4e4133 100644\n--- a/arch/arm64/kvm/vgic/vgic-its.c\n+++ b/arch/arm64/kvm/vgic/vgic-its.c\n@@ -1382,6 +1382,15 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,\n \tif (vcpu1 == vcpu2)\n \t\treturn 0;\n \n+\t/*\n+\t * Bulk operations such as MOVALL are a pain, as they can clash\n+\t * badly locking-wise with other vcpus entering and exiting the\n+\t * guest, should they be affected by it. Stopping the guest is a\n+\t * safer bet to ensure uncontended access and ultimately forward\n+\t * progress. Yeah...\n+\t */\n+\tkvm_arm_halt_guest(kvm);\n+\n \txa_for_each(\u0026dist-\u003elpi_xa, intid, irq) {\n \t\tirq = vgic_get_irq(kvm, intid);\n \t\tif (!irq)\n@@ -1394,6 +1403,8 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,\n \n \tvgic_its_invalidate_cache(its);\n \n+\tkvm_arm_resume_guest(kvm);\n+\n \treturn 0;\n }\n \ndiff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c\nindex 5913a20d83019..f5bd29fbe3a90 100644\n--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c\n+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c\n@@ -303,9 +303,19 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,\n \t\tif (ctlr != GICR_CTLR_ENABLE_LPIS)\n \t\t\treturn;\n \n+\t\t/*\n+\t\t * Yes, disabling LPIs is painful, since it can be done from\n+\t\t * a *remote* vcpu! So let's not take any chance, and make\n+\t\t * sure that the target vCPU has written their LRs back to the\n+\t\t * irq structures, and release any reference they would have.\n+\t\t *\n+\t\t * If it hurts, don't do it.\n+\t\t */\n+\t\tkvm_pause_vcpu(vcpu);\n \t\tvgic_flush_pending_lpis(vcpu);\n \t\tvgic_its_invalidate_all_caches(vcpu-\u003ekvm);\n \t\tatomic_set_release(\u0026vgic_cpu-\u003ectlr, 0);\n+\t\tkvm_resume_vcpu(vcpu);\n \t} else {\n \t\tctlr = atomic_cmpxchg_acquire(\u0026vgic_cpu-\u003ectlr, 0,\n \t\t\t\t\t GICR_CTLR_ENABLE_LPIS);\ndiff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c\nindex 5cf5a1ef86cdd..7061b4ab206c9 100644\n--- a/arch/arm64/kvm/vgic/vgic.c\n+++ b/arch/arm64/kvm/vgic/vgic.c\n@@ -1152,7 +1152,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)\n \t *\n \t * We do that by placing a request to ourselves which will\n \t * abort the entry procedure and inject the exception at the\n-\t * beginning of the run loop.\n+\t * beginning of the run loop (see kvm_nested_flush_hwstate()).\n \t *\n \t * - Otherwise, do exactly *NOTHING* apart from enabling the virtual\n \t * CPU interface. The guest state is already loaded, and we can\n@@ -1162,16 +1162,10 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)\n \t * maintenance interrupt state, as it may fire.\n \t */\n \tif (vgic_state_is_nested(vcpu)) {\n-\t\tif (kvm_vgic_vcpu_pending_irq(vcpu))\n-\t\t\tkvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);\n-\n \t\tvgic_v3_flush_nested(vcpu);\n \t\treturn;\n \t}\n \n-\tif (vcpu_has_nv(vcpu))\n-\t\tvgic_v3_nested_update_mi(vcpu);\n-\n \tDEBUG_SPINLOCK_BUG_ON(!irqs_disabled());\n \n \tvgic_flush_state(vcpu);\n"
} |
| 2/1 | 2026/10/15 13:41 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are strictly confined to the ARM64 KVM subsystem (arch/arm64/include/asm/kvm_host.h and arch/arm64/kvm/*). These files and code paths are exclusive to the ARM64 architecture and are not compiled or executable on the target architecture (amd64).",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any '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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 7d8e22d0fb1808ab50f4de5b60472573258f12de
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Oct 15 13:41:52 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index cd9b9d2462f96..7b4f7b6d94b8d 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -889,11 +889,10 @@ struct kvm_vcpu_arch {
/*
* Don't run the guest (internal implementation need).
*
- * Contrary to the flags above, this is set/cleared outside of
- * a vcpu context, and thus cannot be mixed with the flags
- * themselves (or the flag accesses need to be made atomic).
+ * Contrary to the flags above, this is updated outside of
+ * a vcpu context, and thus cannot be mixed with the flags.
*/
- bool pause;
+ atomic_t pause;
/*
* We maintain more than a single set of debug registers to support
@@ -1255,6 +1254,8 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);
+void kvm_pause_vcpu(struct kvm_vcpu *vcpu);
+void kvm_resume_vcpu(struct kvm_vcpu *vcpu);
#define vcpu_has_run_once(vcpu) (!!READ_ONCE((vcpu)->pid))
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0576c2022ef57..a2f1606822614 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -565,6 +565,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
kvm_arm_pvtime_vcpu_init(&vcpu->arch);
vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
+ atomic_set(&vcpu->arch.pause, 0);
/*
* This vCPU may have been created after mpidr_data was initialized.
@@ -839,6 +840,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return ret;
}
+static bool vcpu_can_run(struct kvm_vcpu *vcpu)
+{
+ return !kvm_arm_vcpu_stopped(vcpu) && !atomic_read(&vcpu->arch.pause);
+}
+
/**
* kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
* @v: The VCPU pointer
@@ -854,8 +860,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
(kvm_timer_should_notify_user(v) ||
kvm_pmu_should_notify_user(v)));
- return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
- && !kvm_arm_vcpu_stopped(v) && !v->arch.pause);
+ return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) && vcpu_can_run(v));
}
bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
@@ -1012,13 +1017,28 @@ bool kvm_arch_intc_initialized(struct kvm *kvm)
return vgic_initialized(kvm);
}
+void kvm_pause_vcpu(struct kvm_vcpu *vcpu)
+{
+ DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS) = { };
+
+ atomic_inc(&vcpu->arch.pause);
+ __set_bit(vcpu->vcpu_idx, vcpu_bitmap);
+ kvm_make_vcpus_request_mask(vcpu->kvm, KVM_REQ_SLEEP, vcpu_bitmap);
+}
+
+void kvm_resume_vcpu(struct kvm_vcpu *vcpu)
+{
+ if (atomic_dec_and_test(&vcpu->arch.pause))
+ __kvm_vcpu_wake_up(vcpu);
+}
+
void kvm_arm_halt_guest(struct kvm *kvm)
{
unsigned long i;
struct kvm_vcpu *vcpu;
kvm_for_each_vcpu(i, vcpu, kvm)
- vcpu->arch.pause = true;
+ atomic_inc(&vcpu->arch.pause);
kvm_make_all_cpus_request(kvm, KVM_REQ_SLEEP);
}
@@ -1027,21 +1047,17 @@ void kvm_arm_resume_guest(struct kvm *kvm)
unsigned long i;
struct kvm_vcpu *vcpu;
- kvm_for_each_vcpu(i, vcpu, kvm) {
- vcpu->arch.pause = false;
- __kvm_vcpu_wake_up(vcpu);
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_resume_vcpu(vcpu);
}
static void kvm_vcpu_sleep(struct kvm_vcpu *vcpu)
{
struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);
- rcuwait_wait_event(wait,
- (!kvm_arm_vcpu_stopped(vcpu)) && (!vcpu->arch.pause),
- TASK_INTERRUPTIBLE);
+ rcuwait_wait_event(wait, vcpu_can_run(vcpu), TASK_INTERRUPTIBLE);
- if (kvm_arm_vcpu_stopped(vcpu) || vcpu->arch.pause) {
+ if (!vcpu_can_run(vcpu)) {
/* Awaken to handle a signal, request we sleep again later. */
kvm_make_request(KVM_REQ_SLEEP, vcpu);
}
@@ -1314,38 +1330,40 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
*/
preempt_disable();
- kvm_nested_flush_hwstate(vcpu);
-
if (kvm_vcpu_has_pmu(vcpu))
kvm_pmu_flush_hwstate(vcpu);
- local_irq_disable();
-
- kvm_vgic_flush_hwstate(vcpu);
+ kvm_nested_flush_hwstate(vcpu);
- kvm_pmu_update_vcpu_events(vcpu);
+ local_irq_disable();
/*
* Ensure we set mode to IN_GUEST_MODE after we disable
* interrupts and before the final VCPU requests check.
* See the comment in kvm_vcpu_exiting_guest_mode() and
* Documentation/virt/kvm/vcpu-requests.rst
+ *
+ * Requests to self must be posted before this point, or
+ * won't be taken into account until the next exit. No state
+ * loading other than what happens at vcpu_load() time can
+ * be done before we have checked for pending requests.
*/
smp_store_mb(vcpu->mode, IN_GUEST_MODE);
if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) {
- vcpu->mode = OUTSIDE_GUEST_MODE;
- isb(); /* Ensure work in x_flush_hwstate is committed */
- if (kvm_vcpu_has_pmu(vcpu))
- kvm_pmu_sync_hwstate(vcpu);
if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
kvm_timer_sync_user(vcpu);
- kvm_vgic_sync_hwstate(vcpu);
+ smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE);
local_irq_enable();
preempt_enable();
continue;
}
+ /* From here onwards, we are commited to entering the guest */
+ kvm_vgic_flush_hwstate(vcpu);
+
+ kvm_pmu_update_vcpu_events(vcpu);
+
kvm_arch_vcpu_ctxflush_fp(vcpu);
/**************************************************************
@@ -1356,7 +1374,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
ret = kvm_arm_vcpu_enter_exit(vcpu);
- vcpu->mode = OUTSIDE_GUEST_MODE;
vcpu->stat.exits++;
/*
* Back from guest
@@ -1390,6 +1407,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
kvm_arch_vcpu_ctxsync_fp(vcpu);
+ /*
+ * All the state has been synchronised, let advertise
+ * we're outside of the guest.
+ */
+ smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE);
+
/*
* We must ensure that any pending interrupts are taken before
* we exit guest timing so that timer ticks are accounted as
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index b191365d97cc2..2fac0f2678122 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -2046,6 +2046,9 @@ void check_nested_vcpu_requests(struct kvm_vcpu *vcpu)
*
* What follows is some slop to (1) react to exception routing / masking and (2)
* preserve the pending SError state across translation regimes.
+ *
+ * Also generate the maintenance interrupt state, and finally check that if
+ * we need to take an interrupt targetting the guest hypervisor.
*/
void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)
{
@@ -2054,6 +2057,11 @@ void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)
if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING)))
kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu));
+
+ vgic_v3_nested_update_mi(vcpu);
+
+ if (vgic_state_is_nested(vcpu) && kvm_vgic_vcpu_pending_irq(vcpu))
+ kvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);
}
void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index c10a11373e106..a9949ab4e4133 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -1382,6 +1382,15 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
if (vcpu1 == vcpu2)
return 0;
+ /*
+ * Bulk operations such as MOVALL are a pain, as they can clash
+ * badly locking-wise with other vcpus entering and exiting the
+ * guest, should they be affected by it. Stopping the guest is a
+ * safer bet to ensure uncontended access and ultimately forward
+ * progress. Yeah...
+ */
+ kvm_arm_halt_guest(kvm);
+
xa_for_each(&dist->lpi_xa, intid, irq) {
irq = vgic_get_irq(kvm, intid);
if (!irq)
@@ -1394,6 +1403,8 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
vgic_its_invalidate_cache(its);
+ kvm_arm_resume_guest(kvm);
+
return 0;
}
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 5913a20d83019..f5bd29fbe3a90 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -303,9 +303,19 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
if (ctlr != GICR_CTLR_ENABLE_LPIS)
return;
+ /*
+ * Yes, disabling LPIs is painful, since it can be done from
+ * a *remote* vcpu! So let's not take any chance, and make
+ * sure that the target vCPU has written their LRs back to the
+ * irq structures, and release any reference they would have.
+ *
+ * If it hurts, don't do it.
+ */
+ kvm_pause_vcpu(vcpu);
vgic_flush_pending_lpis(vcpu);
vgic_its_invalidate_all_caches(vcpu->kvm);
atomic_set_release(&vgic_cpu->ctlr, 0);
+ kvm_resume_vcpu(vcpu);
} else {
ctlr = atomic_cmpxchg_acquire(&vgic_cpu->ctlr, 0,
GICR_CTLR_ENABLE_LPIS);
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 5cf5a1ef86cdd..7061b4ab206c9 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1152,7 +1152,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
*
* We do that by placing a request to ourselves which will
* abort the entry procedure and inject the exception at the
- * beginning of the run loop.
+ * beginning of the run loop (see kvm_nested_flush_hwstate()).
*
* - Otherwise, do exactly *NOTHING* apart from enabling the virtual
* CPU interface. The guest state is already loaded, and we can
@@ -1162,16 +1162,10 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
* maintenance interrupt state, as it may fire.
*/
if (vgic_state_is_nested(vcpu)) {
- if (kvm_vgic_vcpu_pending_irq(vcpu))
- kvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);
-
vgic_v3_flush_nested(vcpu);
return;
}
- if (vcpu_has_nv(vcpu))
- vgic_v3_nested_update_mi(vcpu);
-
DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
vgic_flush_state(vcpu);
|
| 3/2 | 2026/10/15 13:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 7252 output: 41 thoughts: 540 Thoughts: **Initial Assessment: WorthFuzzing = False (Likely)** Okay, here we go. We've got a patch series for syzkaller, targeting amd64. My first instinct is to dive into the code, but before I get too deep, let's just make a quick sanity check. The diff is screaming "wrong architecture" at me, and I need to verify that I am not wasting time on a false positive. Right off the bat, I see the diffs are all within `arch/arm64/`. Every single one. That's a huge red flag. Now, I have to refer to the instructions provided. Section 2, specifically the "NEGATIVE CRITERIA," comes into play. It states that if all modifications are exclusive to a different architecture, then the patch is not worth fuzzing. My target is amd64. The code is exclusively in the arm64 architecture. Can arm64 KVM code even be *compiled* or *executed* on amd64? No, absolutely not. The kernel build system won't even try. It's an architecture-specific directory, and therefore not worth fuzzing. The patch is most likely related to arm64 and is not something that would affect amd64. But, I am not going to let this through without a double-check. I will quickly confirm via `git log` or `grep` that there are no cross-architecture dependencies or build configurations that would somehow include or execute the `arch/arm64/` code on amd64, just to be *completely* certain. After that, I will give the negative assessment, as instructed. |
| 4/2 | 2026/10/15 13:42 | tool | grepper |
0mError:no matches Args: {
"Expression": "arch/arm64/kvm",
"PathPrefixes": [
"arch/x86",
"virt/kvm"
]
}Results: {
"error": "no matches"
} |
| 5/2 | 2026/10/15 13:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 8198 output: 104 thoughts: 305 Thoughts: **Analyzing the Potential for Fuzzing** Okay, so I've been given a set of changes located specifically within the `arch/arm64/` directory. That immediately sets off a red flag in my mind because the target architecture is `amd64`. The instructions are clear: code paths *exclusive* to architectures other than the target are not worth fuzzing, which means the changes in those directories do not need my attention. Let's confirm that logic for `WorthFuzzing=false`. The explanation given is concise and accurate, the modifications are solely within the ARM64 KVM code. This KVM code is structurally unreachable on the amd64 architecture, so it's a dead end as far as fuzzing this architecture is concerned. Now, a quick review of the parameters I need for the `set-results` tool call. We have: `EnableConfigs` as an empty list, `FocusSymbols` is also empty, `Reasoning` is a string confirming why fuzzing is not necessary, and finally, `WorthFuzzing` is set to `false`. That's all good, it looks like everything is in order and ready to proceed. |
| 6/2 | 2026/10/15 13:42 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are strictly confined to the ARM64 KVM subsystem (arch/arm64/include/asm/kvm_host.h and arch/arm64/kvm/*). These files and code paths are exclusive to the ARM64 architecture and are not compiled or executable on the target architecture (amd64).",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are strictly confined to the ARM64 KVM subsystem (arch/arm64/include/asm/kvm_host.h and arch/arm64/kvm/*). These files and code paths are exclusive to the ARM64 architecture and are not compiled or executable on the target architecture (amd64).",
"WorthFuzzing": false
} |
| 7/1 | 2026/10/15 13:42 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|