AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/07 20:04 flow patch-triage
2m Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvmppc_get_compat_caps"
  ],
  "KMSANReasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` which takes a struct `kvm_ppc_compat_caps` from userspace, populates it with host capabilities, and copies it back. The struct `host_caps` is allocated on the stack and explicitly zero-initialized using `= {}`. The kernel uses the standard `copy_struct_from_user()` and `copy_struct_to_user()` helpers, which safely handle size mismatches between userspace and kernel space. Specifically, `copy_struct_from_user()` zeroes any trailing bytes if the userspace struct is smaller than the kernel's, and `copy_struct_to_user()` ensures that only initialized bytes up to the requested size are copied back to userspace, clearing any trailing bytes in the userspace buffer if necessary. The `kvmppc_get_compat_caps()` function only modifies the `compat_capabilities` field using fully initialized local variables. There are no uninitialized variables, padding bytes, or complex data structures that could lead to an info-leak or uninitialized memory usage. Any potential bugs introduced by this patch (such as invalid user pointers or out-of-bounds accesses) would be caught by standard KASAN and other bug detectors. Thus, a dedicated KMSAN fuzzing session is not needed.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` for PowerPC to retrieve CPU compatibility capabilities. The ioctl is accessible via the KVM VM file descriptor and implements new logic in `kvm_arch_vm_ioctl` and `kvmppc_get_compat_caps`. This is a reachable functional change that should be fuzzed.",
  "WorthFuzzing": true
}

1/1 2026/08/07 20:04 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit ea2facd0ccc71155a2a0483542232cd184f45ab9\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Aug 7 20:04:28 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst\nindex e3003a241d5b0..e656d117cd0b1 100644\n--- a/Documentation/virt/kvm/api.rst\n+++ b/Documentation/virt/kvm/api.rst\n@@ -6566,6 +6566,95 @@ KVM_S390_KEYOP_SSKE\n   Sets the storage key for the guest address ``guest_addr`` to the key\n   specified in ``key``, returning the previous value in ``key``.\n \n+4.145 KVM_PPC_GET_COMPAT_CAPS\n+-----------------------------\n+:Capability: KVM_CAP_PPC_COMPAT_CAPS\n+:Architectures: powerpc\n+:Type: vm ioctl\n+:Parameters: struct kvm_ppc_compat_caps (in/out)\n+:Returns: 0 on success, negative value on failure\n+\n+Errors include:\n+\n+  ======== ============================================================\n+  EFAULT   if ``struct kvm_ppc_compat_caps`` cannot be read from or\n+           written to userspace\n+  EINVAL   if the ``size`` field is smaller than\n+           ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field\n+           is non-zero, or if the backend fails to retrieve or map\n+           CPU compatibility capabilities\n+  E2BIG    if ``size`` exceeds ``PAGE_SIZE`` (pathological input guard),\n+           or if ``size`` is larger than the kernel's struct size and\n+           the unknown trailing bytes are non-zero (new userspace on\n+           old kernel with non-default fields set); in the latter case\n+           the kernel writes back its own struct size into the ``size``\n+           field so userspace can retry with the correct size\n+  ENOTTY   if the backend does not implement the ``get_compat_caps``\n+           operation (e.g., on non-HV KVM implementations where the\n+           required KVM operations are not available)\n+  ======== ============================================================\n+\n+IBM POWER system server-based processors provide a compatibility mode feature\n+where an Nth generation processor can operate in modes consistent with earlier\n+generations such as (N-1) and (N-2).\n+\n+This ioctl provides userspace with information about the CPU compatibility modes\n+supported by the current host processor for booting the nested KVM guests on\n+KVM on PowerNV (nested API v1) and KVM on PowerVM (nested API v2) platforms.\n+\n+::\n+\n+  struct kvm_ppc_compat_caps {\n+\t__u64\tsize;\t\t\t/* Size of this structure */\n+\t__u64\tflags;\t\t\t/* Reserved for future use, must be 0 */\n+\t__u64\tcompat_capabilities;\t/* Capabilities supported by the host */\n+  };\n+\n+Before calling this ioctl, userspace must set the ``size`` field to\n+``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.\n+The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent\n+uninitialized stack values from being silently accepted, keeping the\n+field available for future use without ABI ambiguity.\n+\n+The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``\n+to support extensible versioning across three cases:\n+\n+- If ``size`` is smaller than the kernel's struct size (old userspace,\n+  new kernel), the kernel zero-pads the unknown trailing fields before\n+  returning, and writes back ``size`` unchanged so userspace knows how\n+  many bytes were filled.\n+- If ``size`` equals the kernel's struct size, the struct is copied\n+  verbatim.\n+- If ``size`` is larger than the kernel's struct size (new userspace,\n+  old kernel) and the unknown trailing bytes are all zero, the call\n+  succeeds as if the sizes matched. If any trailing bytes are non-zero,\n+  the kernel returns ``-E2BIG`` and writes back its own struct size into\n+  the ``size`` field so userspace can retry with the correct size.\n+\n+``KVM_PPC_COMPAT_CAPS_SIZE_VER0`` (24) is a frozen constant marking the\n+size of the initial struct version.\n+\n+The ``compat_capabilities`` bit field describes the processor compatibility\n+modes supported by the host. The following bits indicate support for specific\n+processor modes (using IBM's MSB-0 convention where bit 0 is the most\n+significant bit):\n+\n+- ``KVM_PPC_COMPAT_CAP_POWER9``  (bit 1) -- KVM guests can run in Power9 processor mode\n+- ``KVM_PPC_COMPAT_CAP_POWER10`` (bit 2) -- KVM guests can run in Power10 processor mode\n+- ``KVM_PPC_COMPAT_CAP_POWER11`` (bit 3) -- KVM guests can run in Power11 processor mode\n+\n+.. note::\n+\n+   The bit numbering above uses IBM's MSB-0 convention (bit 0 is the most\n+   significant bit). In the actual implementation, these are defined as:\n+\n+   - ``KVM_PPC_COMPAT_CAP_POWER9``  = ``(1ULL \u003c\u003c 62)``\n+   - ``KVM_PPC_COMPAT_CAP_POWER10`` = ``(1ULL \u003c\u003c 61)``\n+   - ``KVM_PPC_COMPAT_CAP_POWER11`` = ``(1ULL \u003c\u003c 60)``\n+\n+   Userspace should use the defined constants from ``\u003clinux/kvm.h\u003e`` rather\n+   than hardcoding bit positions.\n+\n .. _kvm_run:\n \n 5. The kvm_run structure\ndiff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h\nindex 0953f2daa4660..169ea6a7fbad4 100644\n--- a/arch/powerpc/include/asm/kvm_ppc.h\n+++ b/arch/powerpc/include/asm/kvm_ppc.h\n@@ -319,6 +319,7 @@ struct kvmppc_ops {\n \tbool (*hash_v3_possible)(void);\n \tint (*create_vm_debugfs)(struct kvm *kvm);\n \tint (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);\n+\tint (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps);\n };\n \n extern struct kvmppc_ops *kvmppc_hv_ops;\ndiff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h\nindex 077c5437f5219..913a64b901a3d 100644\n--- a/arch/powerpc/include/uapi/asm/kvm.h\n+++ b/arch/powerpc/include/uapi/asm/kvm.h\n@@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char {\n \t__u64\tbehaviour_mask;\t\t/* valid bits in behaviour */\n };\n \n+/* For KVM_PPC_GET_COMPAT_CAPS */\n+struct kvm_ppc_compat_caps {\n+\t__u64\tsize;\t\t\t/* Size of this structure */\n+\t__u64\tflags;\t\t\t/* Reserved for future use */\n+\t__u64\tcompat_capabilities;\t/* Capabilities supported by the host */\n+};\n+#define KVM_PPC_COMPAT_CAPS_SIZE_VER0\t24 /* sizeof first published struct */\n+\n+/*\n+ * Capability bits for compat_capabilities field in kvm_ppc_compat_caps.\n+ * These bits indicate which processor compatibility modes are supported.\n+ */\n+#define KVM_PPC_COMPAT_CAP_POWER9\t(1ULL \u003c\u003c 62)\n+#define KVM_PPC_COMPAT_CAP_POWER10\t(1ULL \u003c\u003c 61)\n+#define KVM_PPC_COMPAT_CAP_POWER11\t(1ULL \u003c\u003c 60)\n+#define KVM_PPC_COMPAT_BITMASK\t\t(KVM_PPC_COMPAT_CAP_POWER9 | \\\n+\t\t\t\t\t KVM_PPC_COMPAT_CAP_POWER10 | \\\n+\t\t\t\t\t KVM_PPC_COMPAT_CAP_POWER11)\n /*\n  * Values for character and character_mask.\n  * These are identical to the values used by H_GET_CPU_CHARACTERISTICS.\ndiff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c\nindex 61dbeea317f3b..77558f6eed864 100644\n--- a/arch/powerpc/kvm/book3s_hv.c\n+++ b/arch/powerpc/kvm/book3s_hv.c\n@@ -6510,6 +6510,61 @@ static bool kvmppc_hash_v3_possible(void)\n \treturn true;\n }\n \n+static int kvmppc_map_compat_capabilities(u32 cpu_version,\n+\t\t\t\t\t  unsigned long *capabilities)\n+{\n+\tswitch (cpu_version) {\n+\tcase PVR_ARCH_31_P11:\n+\t\t*capabilities |= KVM_PPC_COMPAT_CAP_POWER11;\n+\t\tfallthrough;\n+\tcase PVR_ARCH_31:\n+\t\t*capabilities |= KVM_PPC_COMPAT_CAP_POWER10;\n+\t\tfallthrough;\n+\tcase PVR_ARCH_300:\n+\t\t*capabilities |= KVM_PPC_COMPAT_CAP_POWER9;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)\n+{\n+\tstruct device_node *np;\n+\tunsigned long capabilities = 0;\n+\tlong rc = -EINVAL;\n+\tu32 cpu_version = 0;\n+\n+\tif (kvmhv_on_pseries()) {\n+\t\tif (kvmhv_is_nestedv2()) {\n+\t\t\tWARN_ON_ONCE(!nested_capabilities);\n+\t\t\tcapabilities = nested_capabilities;\n+\t\t\trc = 0;\n+\t\t} else {\n+\t\t\tfor_each_node_by_type(np, \"cpu\") {\n+\t\t\t\tif (!of_property_read_u32(np, \"cpu-version\",\n+\t\t\t\t\t\t\t  \u0026cpu_version)) {\n+\t\t\t\t\tof_node_put(np);\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (!cpu_version)\n+\t\t\t\treturn -EINVAL;\n+\t\t\trc = kvmppc_map_compat_capabilities(cpu_version,\n+\t\t\t\t\t\t\t    \u0026capabilities);\n+\t\t}\n+\t}\n+\n+\tif (rc \u003c 0)\n+\t\treturn rc;\n+\n+\thost_caps-\u003ecompat_capabilities = capabilities \u0026 KVM_PPC_COMPAT_BITMASK;\n+\n+\treturn rc;\n+}\n+\n static struct kvmppc_ops kvm_ops_hv = {\n \t.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,\n \t.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,\n@@ -6552,6 +6607,7 @@ static struct kvmppc_ops kvm_ops_hv = {\n \t.hash_v3_possible = kvmppc_hash_v3_possible,\n \t.create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv,\n \t.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,\n+\t.get_compat_caps = kvmppc_get_compat_caps,\n };\n \n static int kvm_init_subcore_bitmap(void)\ndiff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c\nindex 00302399fc37b..2fe4ea0ca4ff1 100644\n--- a/arch/powerpc/kvm/powerpc.c\n+++ b/arch/powerpc/kvm/powerpc.c\n@@ -697,6 +697,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)\n \t\t\t}\n \t\t}\n \t\tbreak;\n+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)\n+\tcase KVM_CAP_PPC_COMPAT_CAPS:\n+\t\tr = 0;\n+\t\tif (hv_enabled \u0026\u0026 kvmhv_on_pseries())\n+\t\t\tr = 1;\n+\t\tbreak;\n+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */\n \tdefault:\n \t\tr = 0;\n \t\tbreak;\n@@ -2463,6 +2470,77 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n \t\tr = kvm-\u003earch.kvm_ops-\u003esvm_off(kvm);\n \t\tbreak;\n \t}\n+\tcase KVM_PPC_GET_COMPAT_CAPS: {\n+\t\tstruct kvm_ppc_compat_caps host_caps = {};\n+\t\tu64 usize;\n+\n+\t\t/*\n+\t\t * Read the size field first to drive copy_struct_from_user.\n+\t\t * size must be the first field of the struct.\n+\t\t */\n+\t\tr = -EFAULT;\n+\t\tif (get_user(usize, (__u64 __user *)argp))\n+\t\t\tgoto out;\n+\n+\t\tr = -E2BIG;\n+\t\tif (unlikely(usize \u003e PAGE_SIZE))\n+\t\t\tgoto out;\n+\n+\t\t/*\n+\t\t * Enforce a minimum: reject buffers smaller than the initial\n+\t\t * struct version (VER0). This allows old userspace compiled\n+\t\t * against the original struct to still work on a newer kernel\n+\t\t * that has grown the struct with appended fields.\n+\t\t */\n+\t\tr = -EINVAL;\n+\t\tif (usize \u003c KVM_PPC_COMPAT_CAPS_SIZE_VER0)\n+\t\t\tgoto out;\n+\n+\t\t/*\n+\t\t * copy_struct_from_user() handles forward/backward compat:\n+\t\t *   usize == ksize: verbatim copy\n+\t\t *   usize \u003c  ksize: zero-pad trailing (old userspace, new kernel)\n+\t\t *   usize \u003e  ksize: succeed iff trailing bytes are zero, else -E2BIG\n+\t\t */\n+\t\tr = copy_struct_from_user(\u0026host_caps, sizeof(host_caps),\n+\t\t\t\t\t  argp, usize);\n+\t\tif (r) {\n+\t\t\t/*\n+\t\t\t * New userspace with a larger struct called an older\n+\t\t\t * kernel. Write back ksize in host_caps.size so\n+\t\t\t * userspace knows which older struct to retry with,\n+\t\t\t * then fail with -E2BIG.\n+\t\t\t */\n+\t\t\tif (r == -E2BIG)\n+\t\t\t\tif (put_user((__u64)sizeof(host_caps),\n+\t\t\t\t\t     (__u64 __user *)argp))\n+\t\t\t\t\tr = -EFAULT;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\t/* Reserved fields must be zero */\n+\t\tr = -EINVAL;\n+\t\tif (host_caps.flags)\n+\t\t\tgoto out;\n+\n+\t\tr = -ENOTTY;\n+\t\tif (!kvm-\u003earch.kvm_ops-\u003eget_compat_caps)\n+\t\t\tgoto out;\n+\n+\t\tr = kvm-\u003earch.kvm_ops-\u003eget_compat_caps(\u0026host_caps);\n+\t\tif (r)\n+\t\t\tgoto out;\n+\n+\t\t/*\n+\t\t * Report the number of bytes actually populated by the kernel,\n+\t\t * not usize: if new userspace passed a larger struct with zero\n+\t\t * trailing bytes, we only filled sizeof(host_caps) bytes.\n+\t\t */\n+\t\thost_caps.size = min_t(u64, usize, sizeof(host_caps));\n+\t\tr = copy_struct_to_user(argp, usize, \u0026host_caps,\n+\t\t\t\t\tsizeof(host_caps), NULL);\n+\t\tbreak;\n+\t}\n \tdefault: {\n \t\tstruct kvm *kvm = filp-\u003eprivate_data;\n \t\tr = kvm-\u003earch.kvm_ops-\u003earch_vm_ioctl(filp, ioctl, arg);\ndiff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h\nindex 419011097fa8e..70e36e6a0ad4b 100644\n--- a/include/uapi/linux/kvm.h\n+++ b/include/uapi/linux/kvm.h\n@@ -997,6 +997,7 @@ struct kvm_enable_cap {\n #define KVM_CAP_S390_KEYOP 247\n #define KVM_CAP_S390_VSIE_ESAMODE 248\n #define KVM_CAP_S390_HPAGE_2G 249\n+#define KVM_CAP_PPC_COMPAT_CAPS 250\n \n struct kvm_irq_routing_irqchip {\n \t__u32 irqchip;\n@@ -1341,6 +1342,8 @@ struct kvm_s390_keyop {\n /* Available with KVM_CAP_COUNTER_OFFSET */\n #define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO,  0xb5, struct kvm_arm_counter_offset)\n #define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO,  0xb6, struct reg_mask_range)\n+/* Available with KVM_CAP_PPC_COMPAT_CAPS */\n+#define KVM_PPC_GET_COMPAT_CAPS\t_IO(KVMIO,  0xb8)\n \n /* ioctl for vm fd */\n #define KVM_CREATE_DEVICE\t  _IOWR(KVMIO,  0xe0, struct kvm_create_device)\n"
}

2/1 2026/08/07 20:04 agent patch-evaluator
1m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvmppc_get_compat_caps"
  ],
  "Reasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` for PowerPC to retrieve CPU compatibility capabilities. The ioctl is accessible via the KVM VM file descriptor and implements new logic in `kvm_arch_vm_ioctl` and `kvmppc_get_compat_caps`. This is a reachable functional change 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).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

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.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
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.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. 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 ea2facd0ccc71155a2a0483542232cd184f45ab9
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Aug 7 20:04:28 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e3003a241d5b0..e656d117cd0b1 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6566,6 +6566,95 @@ KVM_S390_KEYOP_SSKE
   Sets the storage key for the guest address ``guest_addr`` to the key
   specified in ``key``, returning the previous value in ``key``.
 
+4.145 KVM_PPC_GET_COMPAT_CAPS
+-----------------------------
+:Capability: KVM_CAP_PPC_COMPAT_CAPS
+:Architectures: powerpc
+:Type: vm ioctl
+:Parameters: struct kvm_ppc_compat_caps (in/out)
+:Returns: 0 on success, negative value on failure
+
+Errors include:
+
+  ======== ============================================================
+  EFAULT   if ``struct kvm_ppc_compat_caps`` cannot be read from or
+           written to userspace
+  EINVAL   if the ``size`` field is smaller than
+           ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
+           is non-zero, or if the backend fails to retrieve or map
+           CPU compatibility capabilities
+  E2BIG    if ``size`` exceeds ``PAGE_SIZE`` (pathological input guard),
+           or if ``size`` is larger than the kernel's struct size and
+           the unknown trailing bytes are non-zero (new userspace on
+           old kernel with non-default fields set); in the latter case
+           the kernel writes back its own struct size into the ``size``
+           field so userspace can retry with the correct size
+  ENOTTY   if the backend does not implement the ``get_compat_caps``
+           operation (e.g., on non-HV KVM implementations where the
+           required KVM operations are not available)
+  ======== ============================================================
+
+IBM POWER system server-based processors provide a compatibility mode feature
+where an Nth generation processor can operate in modes consistent with earlier
+generations such as (N-1) and (N-2).
+
+This ioctl provides userspace with information about the CPU compatibility modes
+supported by the current host processor for booting the nested KVM guests on
+KVM on PowerNV (nested API v1) and KVM on PowerVM (nested API v2) platforms.
+
+::
+
+  struct kvm_ppc_compat_caps {
+	__u64	size;			/* Size of this structure */
+	__u64	flags;			/* Reserved for future use, must be 0 */
+	__u64	compat_capabilities;	/* Capabilities supported by the host */
+  };
+
+Before calling this ioctl, userspace must set the ``size`` field to
+``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
+The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
+uninitialized stack values from being silently accepted, keeping the
+field available for future use without ABI ambiguity.
+
+The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
+to support extensible versioning across three cases:
+
+- If ``size`` is smaller than the kernel's struct size (old userspace,
+  new kernel), the kernel zero-pads the unknown trailing fields before
+  returning, and writes back ``size`` unchanged so userspace knows how
+  many bytes were filled.
+- If ``size`` equals the kernel's struct size, the struct is copied
+  verbatim.
+- If ``size`` is larger than the kernel's struct size (new userspace,
+  old kernel) and the unknown trailing bytes are all zero, the call
+  succeeds as if the sizes matched. If any trailing bytes are non-zero,
+  the kernel returns ``-E2BIG`` and writes back its own struct size into
+  the ``size`` field so userspace can retry with the correct size.
+
+``KVM_PPC_COMPAT_CAPS_SIZE_VER0`` (24) is a frozen constant marking the
+size of the initial struct version.
+
+The ``compat_capabilities`` bit field describes the processor compatibility
+modes supported by the host. The following bits indicate support for specific
+processor modes (using IBM's MSB-0 convention where bit 0 is the most
+significant bit):
+
+- ``KVM_PPC_COMPAT_CAP_POWER9``  (bit 1) -- KVM guests can run in Power9 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER10`` (bit 2) -- KVM guests can run in Power10 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER11`` (bit 3) -- KVM guests can run in Power11 processor mode
+
+.. note::
+
+   The bit numbering above uses IBM's MSB-0 convention (bit 0 is the most
+   significant bit). In the actual implementation, these are defined as:
+
+   - ``KVM_PPC_COMPAT_CAP_POWER9``  = ``(1ULL << 62)``
+   - ``KVM_PPC_COMPAT_CAP_POWER10`` = ``(1ULL << 61)``
+   - ``KVM_PPC_COMPAT_CAP_POWER11`` = ``(1ULL << 60)``
+
+   Userspace should use the defined constants from ``<linux/kvm.h>`` rather
+   than hardcoding bit positions.
+
 .. _kvm_run:
 
 5. The kvm_run structure
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 0953f2daa4660..169ea6a7fbad4 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -319,6 +319,7 @@ struct kvmppc_ops {
 	bool (*hash_v3_possible)(void);
 	int (*create_vm_debugfs)(struct kvm *kvm);
 	int (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);
+	int (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps);
 };
 
 extern struct kvmppc_ops *kvmppc_hv_ops;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 077c5437f5219..913a64b901a3d 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char {
 	__u64	behaviour_mask;		/* valid bits in behaviour */
 };
 
+/* For KVM_PPC_GET_COMPAT_CAPS */
+struct kvm_ppc_compat_caps {
+	__u64	size;			/* Size of this structure */
+	__u64	flags;			/* Reserved for future use */
+	__u64	compat_capabilities;	/* Capabilities supported by the host */
+};
+#define KVM_PPC_COMPAT_CAPS_SIZE_VER0	24 /* sizeof first published struct */
+
+/*
+ * Capability bits for compat_capabilities field in kvm_ppc_compat_caps.
+ * These bits indicate which processor compatibility modes are supported.
+ */
+#define KVM_PPC_COMPAT_CAP_POWER9	(1ULL << 62)
+#define KVM_PPC_COMPAT_CAP_POWER10	(1ULL << 61)
+#define KVM_PPC_COMPAT_CAP_POWER11	(1ULL << 60)
+#define KVM_PPC_COMPAT_BITMASK		(KVM_PPC_COMPAT_CAP_POWER9 | \
+					 KVM_PPC_COMPAT_CAP_POWER10 | \
+					 KVM_PPC_COMPAT_CAP_POWER11)
 /*
  * Values for character and character_mask.
  * These are identical to the values used by H_GET_CPU_CHARACTERISTICS.
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 61dbeea317f3b..77558f6eed864 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -6510,6 +6510,61 @@ static bool kvmppc_hash_v3_possible(void)
 	return true;
 }
 
+static int kvmppc_map_compat_capabilities(u32 cpu_version,
+					  unsigned long *capabilities)
+{
+	switch (cpu_version) {
+	case PVR_ARCH_31_P11:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER11;
+		fallthrough;
+	case PVR_ARCH_31:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER10;
+		fallthrough;
+	case PVR_ARCH_300:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER9;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
+{
+	struct device_node *np;
+	unsigned long capabilities = 0;
+	long rc = -EINVAL;
+	u32 cpu_version = 0;
+
+	if (kvmhv_on_pseries()) {
+		if (kvmhv_is_nestedv2()) {
+			WARN_ON_ONCE(!nested_capabilities);
+			capabilities = nested_capabilities;
+			rc = 0;
+		} else {
+			for_each_node_by_type(np, "cpu") {
+				if (!of_property_read_u32(np, "cpu-version",
+							  &cpu_version)) {
+					of_node_put(np);
+					break;
+				}
+			}
+			if (!cpu_version)
+				return -EINVAL;
+			rc = kvmppc_map_compat_capabilities(cpu_version,
+							    &capabilities);
+		}
+	}
+
+	if (rc < 0)
+		return rc;
+
+	host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
+
+	return rc;
+}
+
 static struct kvmppc_ops kvm_ops_hv = {
 	.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
 	.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -6552,6 +6607,7 @@ static struct kvmppc_ops kvm_ops_hv = {
 	.hash_v3_possible = kvmppc_hash_v3_possible,
 	.create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv,
 	.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,
+	.get_compat_caps = kvmppc_get_compat_caps,
 };
 
 static int kvm_init_subcore_bitmap(void)
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 00302399fc37b..2fe4ea0ca4ff1 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -697,6 +697,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 			}
 		}
 		break;
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
+	case KVM_CAP_PPC_COMPAT_CAPS:
+		r = 0;
+		if (hv_enabled && kvmhv_on_pseries())
+			r = 1;
+		break;
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 	default:
 		r = 0;
 		break;
@@ -2463,6 +2470,77 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
 		r = kvm->arch.kvm_ops->svm_off(kvm);
 		break;
 	}
+	case KVM_PPC_GET_COMPAT_CAPS: {
+		struct kvm_ppc_compat_caps host_caps = {};
+		u64 usize;
+
+		/*
+		 * Read the size field first to drive copy_struct_from_user.
+		 * size must be the first field of the struct.
+		 */
+		r = -EFAULT;
+		if (get_user(usize, (__u64 __user *)argp))
+			goto out;
+
+		r = -E2BIG;
+		if (unlikely(usize > PAGE_SIZE))
+			goto out;
+
+		/*
+		 * Enforce a minimum: reject buffers smaller than the initial
+		 * struct version (VER0). This allows old userspace compiled
+		 * against the original struct to still work on a newer kernel
+		 * that has grown the struct with appended fields.
+		 */
+		r = -EINVAL;
+		if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
+			goto out;
+
+		/*
+		 * copy_struct_from_user() handles forward/backward compat:
+		 *   usize == ksize: verbatim copy
+		 *   usize <  ksize: zero-pad trailing (old userspace, new kernel)
+		 *   usize >  ksize: succeed iff trailing bytes are zero, else -E2BIG
+		 */
+		r = copy_struct_from_user(&host_caps, sizeof(host_caps),
+					  argp, usize);
+		if (r) {
+			/*
+			 * New userspace with a larger struct called an older
+			 * kernel. Write back ksize in host_caps.size so
+			 * userspace knows which older struct to retry with,
+			 * then fail with -E2BIG.
+			 */
+			if (r == -E2BIG)
+				if (put_user((__u64)sizeof(host_caps),
+					     (__u64 __user *)argp))
+					r = -EFAULT;
+			goto out;
+		}
+
+		/* Reserved fields must be zero */
+		r = -EINVAL;
+		if (host_caps.flags)
+			goto out;
+
+		r = -ENOTTY;
+		if (!kvm->arch.kvm_ops->get_compat_caps)
+			goto out;
+
+		r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
+		if (r)
+			goto out;
+
+		/*
+		 * Report the number of bytes actually populated by the kernel,
+		 * not usize: if new userspace passed a larger struct with zero
+		 * trailing bytes, we only filled sizeof(host_caps) bytes.
+		 */
+		host_caps.size = min_t(u64, usize, sizeof(host_caps));
+		r = copy_struct_to_user(argp, usize, &host_caps,
+					sizeof(host_caps), NULL);
+		break;
+	}
 	default: {
 		struct kvm *kvm = filp->private_data;
 		r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 419011097fa8e..70e36e6a0ad4b 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -997,6 +997,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_S390_KEYOP 247
 #define KVM_CAP_S390_VSIE_ESAMODE 248
 #define KVM_CAP_S390_HPAGE_2G 249
+#define KVM_CAP_PPC_COMPAT_CAPS 250
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1341,6 +1342,8 @@ struct kvm_s390_keyop {
 /* Available with KVM_CAP_COUNTER_OFFSET */
 #define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO,  0xb5, struct kvm_arm_counter_offset)
 #define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO,  0xb6, struct reg_mask_range)
+/* Available with KVM_CAP_PPC_COMPAT_CAPS */
+#define KVM_PPC_GET_COMPAT_CAPS	_IO(KVMIO,  0xb8)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE	  _IOWR(KVMIO,  0xe0, struct kvm_create_device)

3/2 2026/08/07 20:04 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6435
							output: 26
							thoughts: 442
						

Thoughts:
**Analyzing the New KVM_PPC_GET_COMPAT_CAPS ioctl for Fuzzing Potential**

Okay, so we have this new `KVM_PPC_GET_COMPAT_CAPS` ioctl. It's added to KVM on PowerPC, accessible through the VM file descriptor. The ioctl expects a `struct kvm_ppc_compat_caps` pointer. Right, I remember seeing the implementation – it lives within `kvm_arch_vm_ioctl` in `arch/powerpc/kvm/powerpc.c`, which calls `kvm->arch.kvm_ops->get_compat_caps(&host_caps)`. And `get_compat_caps` is then defined as `kvmppc_get_compat_caps` within `arch/powerpc/kvm/book3s_hv.c`.

My initial thought is to figure out if this is even fuzzable. A new ioctl in KVM, specifically for PowerPC... that sounds like a good candidate. Okay, it *is* reachable in QEMU, as we can compile for PowerPC. And, wait, Syzkaller supports PowerPC (ppc64le), so that's a big green flag.

The ioctl is `KVM_PPC_GET_COMPAT_CAPS`, and it looks like it's touching core KVM logic for PowerPC. Now, let me see... It's defined as `_IO(KVMIO, 0xb8)`. Hmm, but it takes an argument, doesn't it? Right. `_IO` doesn't encode the size, but the code does use `argp` as a pointer. That's a potential vulnerability point.

Okay, let's dive into the code itself. Need to examine `arch/powerpc/kvm/powerpc.c` and `arch/powerpc/kvm/book3s_hv.c`. Right, the required configuration is `CONFIG_KVM_BOOK3S_HV_POSSIBLE`, which implies `CONFIG_KVM_BOOK3S_64_HV`. Time to check `arch/powerpc/kvm/Kconfig` to confirm those dependencies. That will tell me how to build an environment where this is exposed.



4/2 2026/08/07 20:04 tool grepper
0m Args:
{
  "Expression": "config KVM_BOOK3S_64_HV"
}

Results:
{
  "Output": "arch/powerpc/kvm/Kconfig=62=config KVM_BOOK3S_64\n--\narch/powerpc/kvm/Kconfig-78-\narch/powerpc/kvm/Kconfig:79:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-80-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n"
}

5/2 2026/08/07 20:04 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 7517
							output: 37
							thoughts: 30
						

Thoughts:
Here's my thought process, as if I were considering this myself:

**KVM Configuration Deep Dive**

Okay, so I need to figure out the configuration options related to KVM on the PowerPC architecture, specifically focusing on the `KVM_BOOK3S_64_HV` feature. My immediate instinct is to check the `Kconfig` file within the relevant architecture-specific directory. That would be `arch/powerpc/kvm/Kconfig`. It's almost certain that the definition for `KVM_BOOK3S_64_HV` will reside there, along with all the dependencies and help text. Knowing this Kconfig file will be essential for troubleshooting or modifying the KVM setup on this platform and I will want to cross-reference it with the kernel's Kconfig system.



6/2 2026/08/07 20:04 tool read-file
0m Args:
{
  "File": "arch/powerpc/kvm/Kconfig",
  "FirstLine": 75,
  "LineCount": 20
}

Results:
{
  "Contents": "  75:\t\t  a character device node named /dev/kvm.\n  76:\t\n  77:\t\t  If unsure, say N.\n  78:\t\n  79:\tconfig KVM_BOOK3S_64_HV\n  80:\t\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n  81:\t\tdepends on KVM_BOOK3S_64 \u0026\u0026 PPC_POWERNV\n  82:\t\tselect KVM_BOOK3S_HV_POSSIBLE\n  83:\t\tselect KVM_BOOK3S_HV_PMU\n  84:\t\tselect CMA\n  85:\t\thelp\n  86:\t\t  Support running unmodified book3s_64 guest kernels in\n  87:\t\t  virtual machines on POWER7 and newer processors that have\n  88:\t\t  hypervisor mode available to the host.\n  89:\t\n  90:\t\t  If you say Y here, KVM will use the hardware virtualization\n  91:\t\t  facilities of POWER7 (and later) processors, meaning that\n  92:\t\t  guest operating systems will run at full hardware speed\n  93:\t\t  using supervisor and user modes.  However, this also means\n  94:\t\t  that KVM is not usable under PowerVM (pHyp), is only usable\n"
}

7/2 2026/08/07 20:04 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 8083
							output: 22
							thoughts: 257
						

Thoughts:
**Analyzing the KVM Compatibility Capabilities Logic**

Okay, so the current configuration is `KVM_BOOK3S_64_HV`, which, as I recall, hinges on both `KVM_BOOK3S_64` and `PPC_POWERNV`. Right, got it. Now, let's trace this specific ioctl implementation. Aha, the ioctl in question is implemented for `kvm_ops_hv`, which, naturally, is tied to `KVM_BOOK3S_64_HV`.

Now, I'm curious. Does `KVM_BOOK3S_64_PR` implement it as well? Let's quickly verify. Nope. Only `kvm_ops_hv` is defining `.get_compat_caps = kvmppc_get_compat_caps`. So, the bottom line is that we need both `KVM_BOOK3S_64_HV` and, of course, the general `KVM` enabled.

The ioctl code itself is `KVM_PPC_GET_COMPAT_CAPS`. That’s the key here. Now, the function I should focus on is `kvmppc_get_compat_caps`, but I’ll also need to investigate `kvmppc_map_compat_capabilities`. Also, don't forget that `kvm_arch_vm_ioctl` is what actually handles the `KVM_PPC_GET_COMPAT_CAPS` ioctl.

Now, let me check where `kvm_arch_vm_ioctl` is located. Right, `arch/powerpc/kvm/powerpc.c`. Time to dive in.



8/2 2026/08/07 20:04 tool grepper
0m Args:
{
  "Expression": "kvm_arch_vm_ioctl"
}

Results:
{
  "Output": "arch/arm64/kvm/arm.c=2006=static int kvm_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)\n--\narch/arm64/kvm/arm.c-2015-\narch/arm64/kvm/arm.c:2016:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/arm64/kvm/arm.c-2017-{\n--\narch/loongarch/kvm/vm.c=169=static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)\n--\narch/loongarch/kvm/vm.c-178-\narch/loongarch/kvm/vm.c:179:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/loongarch/kvm/vm.c-180-{\n--\narch/mips/kvm/mips.c=981=int kvm_arch_flush_remote_tlbs(struct kvm *kvm)\n--\narch/mips/kvm/mips.c-986-\narch/mips/kvm/mips.c:987:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/mips/kvm/mips.c-988-{\n--\narch/powerpc/kvm/book3s_hv.c=6124=static void kvmppc_irq_bypass_del_producer_hv(struct irq_bypass_consumer *cons,\n--\narch/powerpc/kvm/book3s_hv.c-6144-\narch/powerpc/kvm/book3s_hv.c:6145:static int kvm_arch_vm_ioctl_hv(struct file *filp,\narch/powerpc/kvm/book3s_hv.c-6146-\t\t\t\tunsigned int ioctl, unsigned long arg)\n--\narch/powerpc/kvm/book3s_hv.c=6568=static struct kvmppc_ops kvm_ops_hv = {\n--\narch/powerpc/kvm/book3s_hv.c-6595-\t.fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv,\narch/powerpc/kvm/book3s_hv.c:6596:\t.arch_vm_ioctl  = kvm_arch_vm_ioctl_hv,\narch/powerpc/kvm/book3s_hv.c-6597-\t.hcall_implemented = kvmppc_hcall_impl_hv,\n--\narch/powerpc/kvm/book3s_pr.c=2026=static int kvmppc_core_check_processor_compat_pr(void)\n--\narch/powerpc/kvm/book3s_pr.c-2038-\narch/powerpc/kvm/book3s_pr.c:2039:static int kvm_arch_vm_ioctl_pr(struct file *filp,\narch/powerpc/kvm/book3s_pr.c-2040-\t\t\t\tunsigned int ioctl, unsigned long arg)\n--\narch/powerpc/kvm/book3s_pr.c=2045=static struct kvmppc_ops kvm_ops_pr = {\n--\narch/powerpc/kvm/book3s_pr.c-2072-\t.fast_vcpu_kick = kvm_vcpu_kick,\narch/powerpc/kvm/book3s_pr.c:2073:\t.arch_vm_ioctl  = kvm_arch_vm_ioctl_pr,\narch/powerpc/kvm/book3s_pr.c-2074-#ifdef CONFIG_PPC_BOOK3S_64\n--\narch/powerpc/kvm/powerpc.c=2294=static int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp)\n--\narch/powerpc/kvm/powerpc.c-2362-\narch/powerpc/kvm/powerpc.c:2363:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/powerpc/kvm/powerpc.c-2364-{\n--\narch/riscv/kvm/vm.c=215=int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)\n--\narch/riscv/kvm/vm.c-267-\narch/riscv/kvm/vm.c:268:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/riscv/kvm/vm.c-269-{\n--\narch/s390/kvm/kvm-s390.c=2900=static int kvm_s390_vm_mem_op(struct kvm *kvm, struct kvm_s390_mem_op *mop)\n--\narch/s390/kvm/kvm-s390.c-2924-\narch/s390/kvm/kvm-s390.c:2925:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/s390/kvm/kvm-s390.c-2926-{\n--\narch/x86/kvm/x86.c=7245=long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,\n--\narch/x86/kvm/x86.c-7257-\narch/x86/kvm/x86.c:7258:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\narch/x86/kvm/x86.c-7259-{\n--\ninclude/linux/kvm_host.h=1594=int kvm_vm_ioctl_enable_cap(struct kvm *kvm,\ninclude/linux/kvm_host.h-1595-\t\t\t    struct kvm_enable_cap *cap);\ninclude/linux/kvm_host.h:1596:int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg);\ninclude/linux/kvm_host.h-1597-long kvm_arch_vm_compat_ioctl(struct file *filp, unsigned int ioctl,\n--\nvirt/kvm/kvm_main.c=5148=static long kvm_vm_ioctl(struct file *filp,\n--\nvirt/kvm/kvm_main.c-5380-\tdefault:\nvirt/kvm/kvm_main.c:5381:\t\tr = kvm_arch_vm_ioctl(filp, ioctl, arg);\nvirt/kvm/kvm_main.c-5382-\t}\n"
}

9/2 2026/08/07 20:04 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10570
							output: 24
							thoughts: 218
						

Thoughts:
**Analyzing the KVM PPC Compat Capabilities IOCTL**

Okay, so I'm looking at this new `KVM_PPC_GET_COMPAT_CAPS` ioctl. It's been added into `kvm_arch_vm_ioctl` within `arch/powerpc/kvm/powerpc.c`. Straightforward; definitely reachable, good. My initial thoughts are to focus my efforts on a few functions. Specifically, `kvmppc_get_compat_caps` and `kvmppc_map_compat_capabilities`. Of course, there's `kvm_arch_vm_ioctl` itself, but that's a pretty generic hot-path function. Well, wait, no, it's *not* a hot-path function, it's an ioctl handler. It's a large function, but my focus should remain on `kvmppc_get_compat_caps` and `kvmppc_map_compat_capabilities` for now.

Let me move on to examining `kvmppc_get_compat_caps`. I'll find it in `arch/powerpc/kvm/book3s_hv.c`.



10/2 2026/08/07 20:04 tool grepper
0m Args:
{
  "Expression": "kvmppc_get_compat_caps"
}

Results:
{
  "Output": "arch/powerpc/kvm/book3s_hv.c=6513=static int kvmppc_map_compat_capabilities(u32 cpu_version,\n--\narch/powerpc/kvm/book3s_hv.c-6532-\narch/powerpc/kvm/book3s_hv.c:6533:static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)\narch/powerpc/kvm/book3s_hv.c-6534-{\n--\narch/powerpc/kvm/book3s_hv.c=6568=static struct kvmppc_ops kvm_ops_hv = {\n--\narch/powerpc/kvm/book3s_hv.c-6609-\t.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,\narch/powerpc/kvm/book3s_hv.c:6610:\t.get_compat_caps = kvmppc_get_compat_caps,\narch/powerpc/kvm/book3s_hv.c-6611-};\n"
}

11/2 2026/08/07 20:04 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11374
							output: 24
							thoughts: 16
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into `kvmppc_map_compat_capabilities`**

Okay, time to dig into `kvmppc_map_compat_capabilities`. This function is likely the linchpin for how KVM handles guest compatibility with the host hardware on PowerPC. I need to understand exactly how it determines which features the guest is allowed to use. It's probably responsible for mapping the guest's view of the hardware capabilities to the host's actual capabilities, taking into account any limitations imposed by the virtualization layer. This is critical for security and stability, making sure the guest doesn't try to access anything it shouldn't, or utilize a feature in a way that would crash the system or expose vulnerabilities.

My immediate questions are:

*   What data structures is it manipulating? `kvm_ppc_vcpu`, `kvm_ppc_pr`, and `kvm_ppc_book3s_64` are probably involved, alongside some bitfields representing the guest's feature set and the host's support. I expect to see checks for CPUID bits, MSRs, and other architectural features.
*   How does it handle feature translation or emulation? Does it selectively enable or disable capabilities based on the host's capabilities, or does it actively rewrite instruction sequences or data structures on the fly? Are there any performance implications?
*   How does it deal with the nuances of different PowerPC architectures and models? We have everything from Book3S to older platforms. This function likely contains a lot of conditional logic, architecture-specific checks, and perhaps even some hardware revision detection.
*   Are there any known vulnerabilities related to how this function works? I'll be particularly interested in any potential for privilege escalation or information leaks due to improper capability mapping.
*   Are there any compatibility options at the QEMU level which might be interacting with this at the point of virtualization?

Let's start by tracing the function's call graph and then drill down into the core logic. I need to see this function at work to understand its behaviour fully.



12/2 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "kvmppc_map_compat_capabilities"
}

Results:
{
  "Output": "arch/powerpc/kvm/book3s_hv.c=6490=static bool kvmppc_hash_v3_possible(void)\n--\narch/powerpc/kvm/book3s_hv.c-6512-\narch/powerpc/kvm/book3s_hv.c:6513:static int kvmppc_map_compat_capabilities(u32 cpu_version,\narch/powerpc/kvm/book3s_hv.c-6514-\t\t\t\t\t  unsigned long *capabilities)\n--\narch/powerpc/kvm/book3s_hv.c=6533=static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)\n--\narch/powerpc/kvm/book3s_hv.c-6554-\t\t\t\treturn -EINVAL;\narch/powerpc/kvm/book3s_hv.c:6555:\t\t\trc = kvmppc_map_compat_capabilities(cpu_version,\narch/powerpc/kvm/book3s_hv.c-6556-\t\t\t\t\t\t\t    \u0026capabilities);\n"
}

13/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12162
							output: 24
							thoughts: 365
						

Thoughts:
**Analyzing the KVM PowerPC Compatibility Capabilities Code**

Okay, so I'm looking at this new code related to PowerPC compatibility capabilities. The key functions I've identified are `kvmppc_get_compat_caps` and `kvmppc_map_compat_capabilities`. Hmm, wait, `kvmppc_map_compat_capabilities` is static, which is interesting. I wonder if it's inlined? Let me see... It's only called once, right within `kvmppc_get_compat_caps`. Ah, but `kvmppc_get_compat_caps` itself is assigned to a function pointer, `.get_compat_caps`, which means it likely won't be inlined. So, I should focus my attention on `kvmppc_get_compat_caps`.

Now, where is this all being called from? Right, `kvm_arch_vm_ioctl` handles the `KVM_PPC_GET_COMPAT_CAPS` ioctl. It's a pretty big function, but the new functionality should be localized within the `case KVM_PPC_GET_COMPAT_CAPS:` block. So it's still fine to just focus on `kvmppc_get_compat_caps`.

Okay, are there any other functions involved? Ah, yes, `kvm_vm_ioctl_check_extension` has also been modified. It's now returning 1 for `KVM_CAP_PPC_COMPAT_CAPS`. That's good to know.

Now, what are the relevant configurations? I need `KVM` and `KVM_BOOK3S_64_HV`, obviously. Wait, `KVM_BOOK3S_64_HV` depends on both `KVM_BOOK3S_64` and `PPC_POWERNV`. Let me double-check that dependency in `arch/powerpc/kvm/Kconfig` to make sure I have it right.



14/2 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "config KVM_BOOK3S_64"
}

Results:
{
  "Output": "arch/powerpc/kvm/Kconfig=29=config KVM_BOOK3S_32_HANDLER\n--\narch/powerpc/kvm/Kconfig-33-\narch/powerpc/kvm/Kconfig:34:config KVM_BOOK3S_64_HANDLER\narch/powerpc/kvm/Kconfig-35-\tbool\n--\narch/powerpc/kvm/Kconfig=45=config KVM_BOOK3S_32\n--\narch/powerpc/kvm/Kconfig-61-\narch/powerpc/kvm/Kconfig:62:config KVM_BOOK3S_64\narch/powerpc/kvm/Kconfig-63-\ttristate \"KVM support for PowerPC book3s_64 processors\"\n--\narch/powerpc/kvm/Kconfig-78-\narch/powerpc/kvm/Kconfig:79:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-80-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-99-\narch/powerpc/kvm/Kconfig:100:config KVM_BOOK3S_64_PR\narch/powerpc/kvm/Kconfig-101-\ttristate \"KVM support without using hypervisor mode in host\"\n"
}

15/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13350
							output: 37
							thoughts: 47
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience:

**Analyzing the KVM_BOOK3S_64_HV Configuration**

Right, so we're looking at `KVM_BOOK3S_64_HV` – that's the configuration we're dealing with. My immediate thought is, "does this particular KVM configuration have any dependencies or implications regarding `PPC_POWERNV`?" Knowing the nuances of these PowerPC-based KVM environments, it's crucial to quickly determine if these are tightly coupled. We need to be able to predict any potential conflicts, architectural differences or performance implications arising from the interplay between these. The goal is to quickly ascertain the critical dependencies, and if any further research or testing is required.



16/2 2026/08/07 20:05 tool read-file
0m Args:
{
  "File": "arch/powerpc/kvm/Kconfig",
  "FirstLine": 79,
  "LineCount": 10
}

Results:
{
  "Contents": "  79:\tconfig KVM_BOOK3S_64_HV\n  80:\t\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n  81:\t\tdepends on KVM_BOOK3S_64 \u0026\u0026 PPC_POWERNV\n  82:\t\tselect KVM_BOOK3S_HV_POSSIBLE\n  83:\t\tselect KVM_BOOK3S_HV_PMU\n  84:\t\tselect CMA\n  85:\t\thelp\n  86:\t\t  Support running unmodified book3s_64 guest kernels in\n  87:\t\t  virtual machines on POWER7 and newer processors that have\n  88:\t\t  hypervisor mode available to the host.\n"
}

17/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13781
							output: 21
							thoughts: 95
						

Thoughts:
**My Configuration Dependencies**

Okay, so I'm focusing on enabling this functionality, and it looks like it hinges on a couple of key configuration parameters: `KVM_BOOK3S_64` and `PPC_POWERNV`. Right, that makes sense. So, to ensure everything's properly enabled, I need to make sure the following configs are set: `KVM`, `KVM_BOOK3S_64`, `PPC_POWERNV`, and `KVM_BOOK3S_64_HV`.

Now, before I proceed any further, I should probably double-check that `PPC_POWERNV` is actually a valid configuration option within the current environment. I don't want to chase a dead end, so verifying that right now will prevent downstream issues. I'll get on that immediately.



18/2 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "config PPC_POWERNV"
}

Results:
{
  "Output": "arch/powerpc/platforms/powernv/Kconfig-1-# SPDX-License-Identifier: GPL-2.0\narch/powerpc/platforms/powernv/Kconfig:2:config PPC_POWERNV\narch/powerpc/platforms/powernv/Kconfig-3-\tdepends on PPC64 \u0026\u0026 PPC_BOOK3S\n"
}

19/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14171
							output: 169
							thoughts: 471
						

Thoughts:
**Fuzzing Strategy for a New KVM ioctl: KVM_PPC_GET_COMPAT_CAPS**

Okay, first things first, yes, `PPC_POWERNV` looks like a valid configuration. And, wait, `KVM_BOOK3S_64_HV` is tristate, meaning it *can* be built as a module, excellent! That means Syzkaller can fuzz it.

Right, the ioctl in question is `KVM_PPC_GET_COMPAT_CAPS`. The function of interest here is clearly `kvmppc_get_compat_caps`. Now, a quick thought – is it worth adding `kvm_arch_vm_ioctl`? It’s a fairly large function, but the specific case we care about, `KVM_PPC_GET_COMPAT_CAPS`, *is* new. Hmmm, since it's generic, better to avoid it. We don't want to skew the fuzzing towards all VM ioctls.

Wait, on second thought, `kvm_arch_vm_ioctl` is an API entry point, so I'll just add `kvmppc_get_compat_caps`.

Okay, let's double-check. Anything else modified? Yup, `kvm_vm_ioctl_check_extension` is also touched. That's fine, I'll add `kvmppc_get_compat_caps`.

Now, time for a quick review. This patch introduces a new KVM ioctl, `KVM_PPC_GET_COMPAT_CAPS`, for PowerPC. It's accessible from userspace via the KVM VM file descriptor, and the change is functional and worth fuzzing. I can get some great fuzzing coverage here.

The key function is `kvmppc_get_compat_caps`.

So, the reasoning is solid. The patch gives us a new way to interact with PowerPC KVM, which is a big win.



20/2 2026/08/07 20:05 tool set-results
0m Error:
the following configs do not exist in the kernel tree: KVM_BOOK3S_64, PPC_POWERNV, KVM_BOOK3S_64_HV

Args:
{
  "EnableConfigs": [
    "KVM",
    "KVM_BOOK3S_64",
    "PPC_POWERNV",
    "KVM_BOOK3S_64_HV"
  ],
  "FocusSymbols": [
    "kvmppc_get_compat_caps"
  ],
  "Reasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` for PowerPC to retrieve CPU compatibility capabilities. The ioctl is accessible via the KVM VM file descriptor and implements new logic in `kvm_arch_vm_ioctl` and `kvmppc_get_compat_caps`. This is a reachable functional change that should be fuzzed.",
  "WorthFuzzing": true
}

Results:
{
  "error": "the following configs do not exist in the kernel tree: KVM_BOOK3S_64, PPC_POWERNV, KVM_BOOK3S_64_HV"
}

21/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15302
							output: 26
							thoughts: 17
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Configuration Conundrum**

Alright, hang on a second. Something feels off... the configuration files are missing? That's not supposed to happen. Okay, let's not jump to conclusions. First, let me quickly verify their existence. I need to confirm if the expected configuration files are actually present. Need to rule out any simple oversight before I start digging into more complex issues like deployment scripts or infrastructure problems. Let me run a quick check...



22/2 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "config KVM_BOOK3S_64_HV"
}

Results:
{
  "Output": "arch/powerpc/kvm/Kconfig=62=config KVM_BOOK3S_64\n--\narch/powerpc/kvm/Kconfig-78-\narch/powerpc/kvm/Kconfig:79:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-80-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n"
}

23/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15572
							output: 17
							thoughts: 187
						

Thoughts:
**Investigating the Configuration Options**

Okay, so I'm seeing this odd behavior. The tool, `set-results`, is telling me that certain configuration options related to KVM for PowerPC don't exist. But I know they're there! I can *see* them right here in `arch/powerpc/kvm/Kconfig`. It's a bit perplexing.

My first thought was that the tool might be architecture-specific, only checking the x86_64 configs, which would explain the discrepancy. But, no, it's supposed to check against the entire kernel tree, so that shouldn't be it. Let me just double-check that `arch/powerpc/kvm/Kconfig` one more time, just to be sure... yep, still there.

Hmm... Perhaps the tool only looks at `Kconfig` files that are *directly* included in the main `Kconfig`. But wait, `arch/powerpc/Kconfig` *does* include `arch/powerpc/kvm/Kconfig`, so that's not the issue either!

Okay, I'm starting to think the tool might be using a pre-generated list of configs, and maybe that list is x86_64-centric. In any case, if it claims these PowerPC KVM options don't exist, I'm going to have to either omit them, or, at a minimum, only include `KVM` and hope for the best. Time to check if `KVM` itself is even defined...



24/2 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "config KVM"
}

Results:
{
  "Output": "arch/arm64/kvm/Kconfig=18=if VIRTUALIZATION\narch/arm64/kvm/Kconfig-19-\narch/arm64/kvm/Kconfig:20:menuconfig KVM\narch/arm64/kvm/Kconfig-21-\tbool \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/loongarch/kvm/Kconfig=18=if VIRTUALIZATION\narch/loongarch/kvm/Kconfig-19-\narch/loongarch/kvm/Kconfig:20:config KVM\narch/loongarch/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig=16=if VIRTUALIZATION\narch/mips/kvm/Kconfig-17-\narch/mips/kvm/Kconfig:18:config KVM\narch/mips/kvm/Kconfig-19-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig-30-\narch/mips/kvm/Kconfig:31:config KVM_MIPS_DEBUG_COP0_COUNTERS\narch/mips/kvm/Kconfig-32-\tbool \"Maintain counters for COP0 accesses\"\n--\narch/powerpc/kvm/Kconfig=18=if VIRTUALIZATION\narch/powerpc/kvm/Kconfig-19-\narch/powerpc/kvm/Kconfig:20:config KVM\narch/powerpc/kvm/Kconfig-21-\tbool\n--\narch/powerpc/kvm/Kconfig-25-\narch/powerpc/kvm/Kconfig:26:config KVM_BOOK3S_HANDLER\narch/powerpc/kvm/Kconfig-27-\tbool\narch/powerpc/kvm/Kconfig-28-\narch/powerpc/kvm/Kconfig:29:config KVM_BOOK3S_32_HANDLER\narch/powerpc/kvm/Kconfig-30-\tbool\n--\narch/powerpc/kvm/Kconfig-33-\narch/powerpc/kvm/Kconfig:34:config KVM_BOOK3S_64_HANDLER\narch/powerpc/kvm/Kconfig-35-\tbool\n--\narch/powerpc/kvm/Kconfig-37-\narch/powerpc/kvm/Kconfig:38:config KVM_BOOK3S_PR_POSSIBLE\narch/powerpc/kvm/Kconfig-39-\tbool\n--\narch/powerpc/kvm/Kconfig-41-\narch/powerpc/kvm/Kconfig:42:config KVM_BOOK3S_HV_POSSIBLE\narch/powerpc/kvm/Kconfig-43-\tbool\narch/powerpc/kvm/Kconfig-44-\narch/powerpc/kvm/Kconfig:45:config KVM_BOOK3S_32\narch/powerpc/kvm/Kconfig-46-\ttristate \"KVM support for PowerPC book3s_32 processors\"\n--\narch/powerpc/kvm/Kconfig-61-\narch/powerpc/kvm/Kconfig:62:config KVM_BOOK3S_64\narch/powerpc/kvm/Kconfig-63-\ttristate \"KVM support for PowerPC book3s_64 processors\"\n--\narch/powerpc/kvm/Kconfig-78-\narch/powerpc/kvm/Kconfig:79:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-80-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-99-\narch/powerpc/kvm/Kconfig:100:config KVM_BOOK3S_64_PR\narch/powerpc/kvm/Kconfig-101-\ttristate \"KVM support without using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-125-\narch/powerpc/kvm/Kconfig:126:config KVM_BOOK3S_HV_EXIT_TIMING\narch/powerpc/kvm/Kconfig-127-\tbool\narch/powerpc/kvm/Kconfig-128-\narch/powerpc/kvm/Kconfig:129:config KVM_BOOK3S_HV_P9_TIMING\narch/powerpc/kvm/Kconfig-130-\tbool \"Detailed timing for the P9 entry point\"\n--\narch/powerpc/kvm/Kconfig-141-\narch/powerpc/kvm/Kconfig:142:config KVM_BOOK3S_HV_P8_TIMING\narch/powerpc/kvm/Kconfig-143-\tbool \"Detailed timing for hypervisor real-mode code (for POWER8)\"\n--\narch/powerpc/kvm/Kconfig-156-\narch/powerpc/kvm/Kconfig:157:config KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND\narch/powerpc/kvm/Kconfig-158-\tbool \"Nested L0 host workaround for L1 KVM host PMU handling bug\" if EXPERT\n--\narch/powerpc/kvm/Kconfig-171-\narch/powerpc/kvm/Kconfig:172:config KVM_BOOK3S_HV_PMU\narch/powerpc/kvm/Kconfig-173-\ttristate \"Hypervisor Perf events for KVM Book3s-HV\"\n--\narch/powerpc/kvm/Kconfig-183-\narch/powerpc/kvm/Kconfig:184:config KVM_BOOKE_HV\narch/powerpc/kvm/Kconfig-185-\tbool\narch/powerpc/kvm/Kconfig-186-\narch/powerpc/kvm/Kconfig:187:config KVM_EXIT_TIMING\narch/powerpc/kvm/Kconfig-188-\tbool \"Detailed exit timing\"\n--\narch/powerpc/kvm/Kconfig-197-\narch/powerpc/kvm/Kconfig:198:config KVM_E500V2\narch/powerpc/kvm/Kconfig-199-\tbool \"KVM support for PowerPC E500v2 processors\"\n--\narch/powerpc/kvm/Kconfig-212-\narch/powerpc/kvm/Kconfig:213:config KVM_E500MC\narch/powerpc/kvm/Kconfig-214-\tbool \"KVM support for PowerPC E500MC/E5500/E6500 processors\"\n--\narch/powerpc/kvm/Kconfig-228-\narch/powerpc/kvm/Kconfig:229:config KVM_MPIC\narch/powerpc/kvm/Kconfig-230-\tbool \"KVM in-kernel MPIC emulation\"\n--\narch/powerpc/kvm/Kconfig-240-\narch/powerpc/kvm/Kconfig:241:config KVM_XICS\narch/powerpc/kvm/Kconfig-242-\tbool \"KVM in-kernel XICS emulation\"\n--\narch/powerpc/kvm/Kconfig-250-\narch/powerpc/kvm/Kconfig:251:config KVM_XIVE\narch/powerpc/kvm/Kconfig-252-\tbool\n--\narch/powerpc/platforms/Kconfig=22=source \"arch/powerpc/platforms/microwatt/Kconfig\"\narch/powerpc/platforms/Kconfig-23-\narch/powerpc/platforms/Kconfig:24:config KVM_GUEST\narch/powerpc/platforms/Kconfig-25-\tbool \"KVM Guest support\"\n--\narch/riscv/kvm/Kconfig=18=if VIRTUALIZATION\narch/riscv/kvm/Kconfig-19-\narch/riscv/kvm/Kconfig:20:config KVM\narch/riscv/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/s390/kvm/Kconfig=17=if VIRTUALIZATION\narch/s390/kvm/Kconfig-18-\narch/s390/kvm/Kconfig:19:config KVM\narch/s390/kvm/Kconfig-20-\tdef_tristate y\n--\narch/s390/kvm/Kconfig-46-\narch/s390/kvm/Kconfig:47:config KVM_S390_UCONTROL\narch/s390/kvm/Kconfig-48-\tbool \"Userspace controlled virtual machines\"\n--\narch/x86/Kconfig=826=source \"arch/x86/xen/Kconfig\"\narch/x86/Kconfig-827-\narch/x86/Kconfig:828:config KVM_GUEST\narch/x86/Kconfig-829-\tbool \"KVM Guest support (including kvmclock)\"\n--\narch/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--\nvirt/kvm/Kconfig-3-\nvirt/kvm/Kconfig:4:config KVM_COMMON\nvirt/kvm/Kconfig-5-       bool\n--\nvirt/kvm/Kconfig=39=config NEED_KVM_DIRTY_RING_WITH_BITMAP\n--\nvirt/kvm/Kconfig-42-\nvirt/kvm/Kconfig:43:config KVM_MMIO\nvirt/kvm/Kconfig-44-       bool\nvirt/kvm/Kconfig-45-\nvirt/kvm/Kconfig:46:config KVM_ASYNC_PF\nvirt/kvm/Kconfig-47-       bool\n--\nvirt/kvm/Kconfig-49-# Toggle to switch between direct notification and batch job\nvirt/kvm/Kconfig:50:config KVM_ASYNC_PF_SYNC\nvirt/kvm/Kconfig-51-       bool\n--\nvirt/kvm/Kconfig=59=config HAVE_KVM_CPU_RELAX_INTERCEPT\n--\nvirt/kvm/Kconfig-61-\nvirt/kvm/Kconfig:62:config KVM_VFIO\nvirt/kvm/Kconfig-63-       bool\n--\nvirt/kvm/Kconfig=65=config HAVE_KVM_INVALID_WAKEUPS\n--\nvirt/kvm/Kconfig-67-\nvirt/kvm/Kconfig:68:config KVM_GENERIC_DIRTYLOG_READ_PROTECT\nvirt/kvm/Kconfig-69-       bool\nvirt/kvm/Kconfig-70-\nvirt/kvm/Kconfig:71:config KVM_GENERIC_PRE_FAULT_MEMORY\nvirt/kvm/Kconfig-72-       bool\nvirt/kvm/Kconfig-73-\nvirt/kvm/Kconfig:74:config KVM_COMPAT\nvirt/kvm/Kconfig-75-       def_bool y\n--\nvirt/kvm/Kconfig=91=config HAVE_KVM_PM_NOTIFIER\n--\nvirt/kvm/Kconfig-93-\nvirt/kvm/Kconfig:94:config KVM_GENERIC_HARDWARE_ENABLING\nvirt/kvm/Kconfig-95-       bool\nvirt/kvm/Kconfig-96-\nvirt/kvm/Kconfig:97:config KVM_ELIDE_TLB_FLUSH_IF_YOUNG\nvirt/kvm/Kconfig-98-       bool\nvirt/kvm/Kconfig-99-\nvirt/kvm/Kconfig:100:config KVM_MMU_LOCKLESS_AGING\nvirt/kvm/Kconfig-101-       bool\nvirt/kvm/Kconfig-102-\nvirt/kvm/Kconfig:103:config KVM_GENERIC_MEMORY_ATTRIBUTES\nvirt/kvm/Kconfig-104-       bool\nvirt/kvm/Kconfig-105-\nvirt/kvm/Kconfig:106:config KVM_GUEST_MEMFD\nvirt/kvm/Kconfig-107-       select XARRAY_MULTI\n"
}

25/2 2026/08/07 20:05 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 20395
							output: 133
							thoughts: 108
						

Thoughts:
**Addressing the Configuration Verification**

Okay, so this tool is checking my configuration against the current architecture, which is almost certainly x86_64. No surprises there. Right, so I see `KVM_BOOK3S_64` flagged as an issue. That's a PowerPC-specific setting, and it's definitely not going to be in an x86_64 kernel tree. Makes sense. I can clearly simplify this; I'll just supply `KVM` and `KVM_COMPAT`, or perhaps just `KVM`. That should cover the general case. Hmm, but wait. The tool is now explicitly flagging those configs as non-existent within the kernel tree. Okay, let's keep it simple; `KVM` should work, and the rest should be figured out by the kernel build system automatically. I can see why the other configs are causing issues.



26/2 2026/08/07 20:05 tool set-results
0m Args:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvmppc_get_compat_caps"
  ],
  "Reasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` for PowerPC to retrieve CPU compatibility capabilities. The ioctl is accessible via the KVM VM file descriptor and implements new logic in `kvm_arch_vm_ioctl` and `kvmppc_get_compat_caps`. This is a reachable functional change that should be fuzzed.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvmppc_get_compat_caps"
  ],
  "Reasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` for PowerPC to retrieve CPU compatibility capabilities. The ioctl is accessible via the KVM VM file descriptor and implements new logic in `kvm_arch_vm_ioctl` and `kvmppc_get_compat_caps`. This is a reachable functional change that should be fuzzed.",
  "WorthFuzzing": true
}

27/1 2026/08/07 20:05 action If
0m Args:
{
  "WorthFuzzing": true
}

Results:
null

28/2 2026/08/07 20:05 agent kmsan-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "KMSANReasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` which takes a struct `kvm_ppc_compat_caps` from userspace, populates it with host capabilities, and copies it back. The struct `host_caps` is allocated on the stack and explicitly zero-initialized using `= {}`. The kernel uses the standard `copy_struct_from_user()` and `copy_struct_to_user()` helpers, which safely handle size mismatches between userspace and kernel space. Specifically, `copy_struct_from_user()` zeroes any trailing bytes if the userspace struct is smaller than the kernel's, and `copy_struct_to_user()` ensures that only initialized bytes up to the requested size are copied back to userspace, clearing any trailing bytes in the userspace buffer if necessary. The `kvmppc_get_compat_caps()` function only modifies the `compat_capabilities` field using fully initialized local variables. There are no uninitialized variables, padding bytes, or complex data structures that could lead to an info-leak or uninitialized memory usage. Any potential bugs introduced by this patch (such as invalid user pointers or out-of-bounds accesses) would be caught by standard KASAN and other bug detectors. Thus, a dedicated KMSAN fuzzing session is not needed.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 ea2facd0ccc71155a2a0483542232cd184f45ab9
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Aug 7 20:04:28 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e3003a241d5b0..e656d117cd0b1 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6566,6 +6566,95 @@ KVM_S390_KEYOP_SSKE
   Sets the storage key for the guest address ``guest_addr`` to the key
   specified in ``key``, returning the previous value in ``key``.
 
+4.145 KVM_PPC_GET_COMPAT_CAPS
+-----------------------------
+:Capability: KVM_CAP_PPC_COMPAT_CAPS
+:Architectures: powerpc
+:Type: vm ioctl
+:Parameters: struct kvm_ppc_compat_caps (in/out)
+:Returns: 0 on success, negative value on failure
+
+Errors include:
+
+  ======== ============================================================
+  EFAULT   if ``struct kvm_ppc_compat_caps`` cannot be read from or
+           written to userspace
+  EINVAL   if the ``size`` field is smaller than
+           ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
+           is non-zero, or if the backend fails to retrieve or map
+           CPU compatibility capabilities
+  E2BIG    if ``size`` exceeds ``PAGE_SIZE`` (pathological input guard),
+           or if ``size`` is larger than the kernel's struct size and
+           the unknown trailing bytes are non-zero (new userspace on
+           old kernel with non-default fields set); in the latter case
+           the kernel writes back its own struct size into the ``size``
+           field so userspace can retry with the correct size
+  ENOTTY   if the backend does not implement the ``get_compat_caps``
+           operation (e.g., on non-HV KVM implementations where the
+           required KVM operations are not available)
+  ======== ============================================================
+
+IBM POWER system server-based processors provide a compatibility mode feature
+where an Nth generation processor can operate in modes consistent with earlier
+generations such as (N-1) and (N-2).
+
+This ioctl provides userspace with information about the CPU compatibility modes
+supported by the current host processor for booting the nested KVM guests on
+KVM on PowerNV (nested API v1) and KVM on PowerVM (nested API v2) platforms.
+
+::
+
+  struct kvm_ppc_compat_caps {
+	__u64	size;			/* Size of this structure */
+	__u64	flags;			/* Reserved for future use, must be 0 */
+	__u64	compat_capabilities;	/* Capabilities supported by the host */
+  };
+
+Before calling this ioctl, userspace must set the ``size`` field to
+``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
+The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
+uninitialized stack values from being silently accepted, keeping the
+field available for future use without ABI ambiguity.
+
+The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
+to support extensible versioning across three cases:
+
+- If ``size`` is smaller than the kernel's struct size (old userspace,
+  new kernel), the kernel zero-pads the unknown trailing fields before
+  returning, and writes back ``size`` unchanged so userspace knows how
+  many bytes were filled.
+- If ``size`` equals the kernel's struct size, the struct is copied
+  verbatim.
+- If ``size`` is larger than the kernel's struct size (new userspace,
+  old kernel) and the unknown trailing bytes are all zero, the call
+  succeeds as if the sizes matched. If any trailing bytes are non-zero,
+  the kernel returns ``-E2BIG`` and writes back its own struct size into
+  the ``size`` field so userspace can retry with the correct size.
+
+``KVM_PPC_COMPAT_CAPS_SIZE_VER0`` (24) is a frozen constant marking the
+size of the initial struct version.
+
+The ``compat_capabilities`` bit field describes the processor compatibility
+modes supported by the host. The following bits indicate support for specific
+processor modes (using IBM's MSB-0 convention where bit 0 is the most
+significant bit):
+
+- ``KVM_PPC_COMPAT_CAP_POWER9``  (bit 1) -- KVM guests can run in Power9 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER10`` (bit 2) -- KVM guests can run in Power10 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER11`` (bit 3) -- KVM guests can run in Power11 processor mode
+
+.. note::
+
+   The bit numbering above uses IBM's MSB-0 convention (bit 0 is the most
+   significant bit). In the actual implementation, these are defined as:
+
+   - ``KVM_PPC_COMPAT_CAP_POWER9``  = ``(1ULL << 62)``
+   - ``KVM_PPC_COMPAT_CAP_POWER10`` = ``(1ULL << 61)``
+   - ``KVM_PPC_COMPAT_CAP_POWER11`` = ``(1ULL << 60)``
+
+   Userspace should use the defined constants from ``<linux/kvm.h>`` rather
+   than hardcoding bit positions.
+
 .. _kvm_run:
 
 5. The kvm_run structure
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 0953f2daa4660..169ea6a7fbad4 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -319,6 +319,7 @@ struct kvmppc_ops {
 	bool (*hash_v3_possible)(void);
 	int (*create_vm_debugfs)(struct kvm *kvm);
 	int (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);
+	int (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps);
 };
 
 extern struct kvmppc_ops *kvmppc_hv_ops;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 077c5437f5219..913a64b901a3d 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char {
 	__u64	behaviour_mask;		/* valid bits in behaviour */
 };
 
+/* For KVM_PPC_GET_COMPAT_CAPS */
+struct kvm_ppc_compat_caps {
+	__u64	size;			/* Size of this structure */
+	__u64	flags;			/* Reserved for future use */
+	__u64	compat_capabilities;	/* Capabilities supported by the host */
+};
+#define KVM_PPC_COMPAT_CAPS_SIZE_VER0	24 /* sizeof first published struct */
+
+/*
+ * Capability bits for compat_capabilities field in kvm_ppc_compat_caps.
+ * These bits indicate which processor compatibility modes are supported.
+ */
+#define KVM_PPC_COMPAT_CAP_POWER9	(1ULL << 62)
+#define KVM_PPC_COMPAT_CAP_POWER10	(1ULL << 61)
+#define KVM_PPC_COMPAT_CAP_POWER11	(1ULL << 60)
+#define KVM_PPC_COMPAT_BITMASK		(KVM_PPC_COMPAT_CAP_POWER9 | \
+					 KVM_PPC_COMPAT_CAP_POWER10 | \
+					 KVM_PPC_COMPAT_CAP_POWER11)
 /*
  * Values for character and character_mask.
  * These are identical to the values used by H_GET_CPU_CHARACTERISTICS.
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 61dbeea317f3b..77558f6eed864 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -6510,6 +6510,61 @@ static bool kvmppc_hash_v3_possible(void)
 	return true;
 }
 
+static int kvmppc_map_compat_capabilities(u32 cpu_version,
+					  unsigned long *capabilities)
+{
+	switch (cpu_version) {
+	case PVR_ARCH_31_P11:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER11;
+		fallthrough;
+	case PVR_ARCH_31:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER10;
+		fallthrough;
+	case PVR_ARCH_300:
+		*capabilities |= KVM_PPC_COMPAT_CAP_POWER9;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
+{
+	struct device_node *np;
+	unsigned long capabilities = 0;
+	long rc = -EINVAL;
+	u32 cpu_version = 0;
+
+	if (kvmhv_on_pseries()) {
+		if (kvmhv_is_nestedv2()) {
+			WARN_ON_ONCE(!nested_capabilities);
+			capabilities = nested_capabilities;
+			rc = 0;
+		} else {
+			for_each_node_by_type(np, "cpu") {
+				if (!of_property_read_u32(np, "cpu-version",
+							  &cpu_version)) {
+					of_node_put(np);
+					break;
+				}
+			}
+			if (!cpu_version)
+				return -EINVAL;
+			rc = kvmppc_map_compat_capabilities(cpu_version,
+							    &capabilities);
+		}
+	}
+
+	if (rc < 0)
+		return rc;
+
+	host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
+
+	return rc;
+}
+
 static struct kvmppc_ops kvm_ops_hv = {
 	.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
 	.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -6552,6 +6607,7 @@ static struct kvmppc_ops kvm_ops_hv = {
 	.hash_v3_possible = kvmppc_hash_v3_possible,
 	.create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv,
 	.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,
+	.get_compat_caps = kvmppc_get_compat_caps,
 };
 
 static int kvm_init_subcore_bitmap(void)
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 00302399fc37b..2fe4ea0ca4ff1 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -697,6 +697,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 			}
 		}
 		break;
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
+	case KVM_CAP_PPC_COMPAT_CAPS:
+		r = 0;
+		if (hv_enabled && kvmhv_on_pseries())
+			r = 1;
+		break;
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 	default:
 		r = 0;
 		break;
@@ -2463,6 +2470,77 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
 		r = kvm->arch.kvm_ops->svm_off(kvm);
 		break;
 	}
+	case KVM_PPC_GET_COMPAT_CAPS: {
+		struct kvm_ppc_compat_caps host_caps = {};
+		u64 usize;
+
+		/*
+		 * Read the size field first to drive copy_struct_from_user.
+		 * size must be the first field of the struct.
+		 */
+		r = -EFAULT;
+		if (get_user(usize, (__u64 __user *)argp))
+			goto out;
+
+		r = -E2BIG;
+		if (unlikely(usize > PAGE_SIZE))
+			goto out;
+
+		/*
+		 * Enforce a minimum: reject buffers smaller than the initial
+		 * struct version (VER0). This allows old userspace compiled
+		 * against the original struct to still work on a newer kernel
+		 * that has grown the struct with appended fields.
+		 */
+		r = -EINVAL;
+		if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
+			goto out;
+
+		/*
+		 * copy_struct_from_user() handles forward/backward compat:
+		 *   usize == ksize: verbatim copy
+		 *   usize <  ksize: zero-pad trailing (old userspace, new kernel)
+		 *   usize >  ksize: succeed iff trailing bytes are zero, else -E2BIG
+		 */
+		r = copy_struct_from_user(&host_caps, sizeof(host_caps),
+					  argp, usize);
+		if (r) {
+			/*
+			 * New userspace with a larger struct called an older
+			 * kernel. Write back ksize in host_caps.size so
+			 * userspace knows which older struct to retry with,
+			 * then fail with -E2BIG.
+			 */
+			if (r == -E2BIG)
+				if (put_user((__u64)sizeof(host_caps),
+					     (__u64 __user *)argp))
+					r = -EFAULT;
+			goto out;
+		}
+
+		/* Reserved fields must be zero */
+		r = -EINVAL;
+		if (host_caps.flags)
+			goto out;
+
+		r = -ENOTTY;
+		if (!kvm->arch.kvm_ops->get_compat_caps)
+			goto out;
+
+		r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
+		if (r)
+			goto out;
+
+		/*
+		 * Report the number of bytes actually populated by the kernel,
+		 * not usize: if new userspace passed a larger struct with zero
+		 * trailing bytes, we only filled sizeof(host_caps) bytes.
+		 */
+		host_caps.size = min_t(u64, usize, sizeof(host_caps));
+		r = copy_struct_to_user(argp, usize, &host_caps,
+					sizeof(host_caps), NULL);
+		break;
+	}
 	default: {
 		struct kvm *kvm = filp->private_data;
 		r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 419011097fa8e..70e36e6a0ad4b 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -997,6 +997,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_S390_KEYOP 247
 #define KVM_CAP_S390_VSIE_ESAMODE 248
 #define KVM_CAP_S390_HPAGE_2G 249
+#define KVM_CAP_PPC_COMPAT_CAPS 250
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1341,6 +1342,8 @@ struct kvm_s390_keyop {
 /* Available with KVM_CAP_COUNTER_OFFSET */
 #define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO,  0xb5, struct kvm_arm_counter_offset)
 #define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO,  0xb6, struct reg_mask_range)
+/* Available with KVM_CAP_PPC_COMPAT_CAPS */
+#define KVM_PPC_GET_COMPAT_CAPS	_IO(KVMIO,  0xb8)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE	  _IOWR(KVMIO,  0xe0, struct kvm_create_device)

29/3 2026/08/07 20:05 llm kmsan-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6432
							output: 21
							thoughts: 856
						

Thoughts:
**Assessing the KMSAN Fuzzing Necessity**

Okay, so we have this new patch that introduces a `KVM_PPC_GET_COMPAT_CAPS` ioctl. It seems pretty straightforward: userspace provides a `kvm_ppc_compat_caps` struct, the kernel processes it, and then copies data back to userspace. My initial thought is to figure out if this deserves its own KMSAN fuzzing session. Let's dig into the implementation in `arch/powerpc/kvm/powerpc.c`.

I'm seeing it reads a size value from userspace, does some size checks to handle old/new versions of the struct and then uses `copy_struct_from_user` to read the struct itself. It then validates some flags, calls a `kvm->arch.kvm_ops->get_compat_caps` callback, and finally uses `copy_struct_to_user` to write the processed data back to userspace.

Wait a second... `copy_struct_to_user`? I don't recall seeing that function before. Is this some new helper? It's not immediately springing to mind as a standard kernel function. I'm going to have to do a quick `grep` to see where this is defined and used. Let's see what we can find.



30/3 2026/08/07 20:05 tool grepper
0m Args:
{
  "Expression": "copy_struct_to_user"
}

Results:
{
  "Output": "Documentation/virt/kvm/api.rst=6617=field available for future use without ABI ambiguity.\nDocumentation/virt/kvm/api.rst-6618-\nDocumentation/virt/kvm/api.rst:6619:The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``\nDocumentation/virt/kvm/api.rst-6620-to support extensible versioning across three cases:\n--\narch/powerpc/kvm/powerpc.c=2363=int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n--\narch/powerpc/kvm/powerpc.c-2539-\t\thost_caps.size = min_t(u64, usize, sizeof(host_caps));\narch/powerpc/kvm/powerpc.c:2540:\t\tr = copy_struct_to_user(argp, usize, \u0026host_caps,\narch/powerpc/kvm/powerpc.c-2541-\t\t\t\t\tsizeof(host_caps), NULL);\n--\nblock/blk-integrity.c=58=int blk_get_meta_cap(struct block_device *bdev, unsigned int cmd,\n--\nblock/blk-integrity.c-118-out:\nblock/blk-integrity.c:119:\treturn copy_struct_to_user(argp, usize, \u0026meta_cap, sizeof(meta_cap),\nblock/blk-integrity.c-120-\t\t\t\t   NULL);\n--\ndrivers/accel/ethosu/ethosu_drv.c=25=static int ethosu_ioctl_dev_query(struct drm_device *ddev, void *data,\n--\ndrivers/accel/ethosu/ethosu_drv.c-44-\t\t\treturn -EINVAL;\ndrivers/accel/ethosu/ethosu_drv.c:45:\t\treturn copy_struct_to_user(u64_to_user_ptr(args-\u003epointer),\ndrivers/accel/ethosu/ethosu_drv.c-46-\t\t\t\t\t   args-\u003esize,\n--\ndrivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c=1218=tegra241_cmdqv_init_vintf_user(struct arm_vsmmu *vsmmu,\n--\ndrivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c-1268-\tdata.out_vintf_mmap_offset = vintf-\u003emmap_offset;\ndrivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c:1269:\tret = iommu_copy_struct_to_user(user_data, \u0026data,\ndrivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c-1270-\t\t\t\t\tIOMMU_VIOMMU_TYPE_TEGRA241_CMDQV,\n--\ndrivers/iommu/iommufd/selftest.c=791=static int mock_viommu_init(struct iommufd_viommu *viommu,\n--\ndrivers/iommu/iommufd/selftest.c-824-\t\tdata.out_mmap_offset = mock_viommu-\u003emmap_offset;\ndrivers/iommu/iommufd/selftest.c:825:\t\trc = iommu_copy_struct_to_user(\ndrivers/iommu/iommufd/selftest.c-826-\t\t\tuser_data, \u0026data, IOMMU_VIOMMU_TYPE_SELFTEST, out_data);\n--\nfs/file_attr.c=374=SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,\n--\nfs/file_attr.c-420-\tfileattr_to_file_attr(\u0026fa, \u0026fattr);\nfs/file_attr.c:421:\terror = copy_struct_to_user(ufattr, usize, \u0026fattr,\nfs/file_attr.c-422-\t\t\t\t    sizeof(struct file_attr), NULL);\n--\nfs/pidfs.c=365=static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)\n--\nfs/pidfs.c-495-\t */\nfs/pidfs.c:496:\treturn copy_struct_to_user(uinfo, usize, \u0026kinfo, sizeof(kinfo), NULL);\nfs/pidfs.c-497-}\n--\ninclude/linux/iommu.h=562=iommu_copy_struct_from_full_user_array(void *kdst, size_t kdst_entry_size,\n--\ninclude/linux/iommu.h-593-/**\ninclude/linux/iommu.h:594: * __iommu_copy_struct_to_user - Report iommu driver specific user space data\ninclude/linux/iommu.h-595- * @dst_data: Pointer to a struct iommu_user_data for user space data location\n--\ninclude/linux/iommu.h=604=static inline int\ninclude/linux/iommu.h:605:__iommu_copy_struct_to_user(const struct iommu_user_data *dst_data,\ninclude/linux/iommu.h-606-\t\t\t    void *src_data, unsigned int data_type,\n--\ninclude/linux/iommu.h-614-\t\treturn -EINVAL;\ninclude/linux/iommu.h:615:\treturn copy_struct_to_user(dst_data-\u003euptr, dst_data-\u003elen, src_data,\ninclude/linux/iommu.h-616-\t\t\t\t   data_len, NULL);\n--\ninclude/linux/iommu.h-619-/**\ninclude/linux/iommu.h:620: * iommu_copy_struct_to_user - Report iommu driver specific user space data\ninclude/linux/iommu.h-621- * @user_data: Pointer to a struct iommu_user_data for user space data location\n--\ninclude/linux/iommu.h-628- */\ninclude/linux/iommu.h:629:#define iommu_copy_struct_to_user(user_data, ksrc, data_type, min_last)        \\\ninclude/linux/iommu.h:630:\t__iommu_copy_struct_to_user(user_data, ksrc, data_type, sizeof(*ksrc), \\\ninclude/linux/iommu.h-631-\t\t\t\t    offsetofend(typeof(*ksrc), min_last))\n--\ninclude/linux/sockptr.h=111=copy_struct_to_sockptr(sockptr_t dst, size_t usize, const void *src,\n--\ninclude/linux/sockptr.h-114-\tif (!sockptr_is_kernel(dst))\ninclude/linux/sockptr.h:115:\t\treturn copy_struct_to_user(dst.user, usize, src, ksize, ignored_trailing);\ninclude/linux/sockptr.h-116-\n--\ninclude/linux/uaccess.h=393=copy_struct_from_user(void *dst, size_t ksize, const void __user *src,\n--\ninclude/linux/uaccess.h-417-/**\ninclude/linux/uaccess.h:418: * copy_struct_to_user: copy a struct to userspace\ninclude/linux/uaccess.h-419- * @dst:   Destination address, in userspace. This buffer must be @ksize\n--\ninclude/linux/uaccess.h-464- *\ninclude/linux/uaccess.h:465: *      err = copy_struct_to_user(uarg, usize, \u0026karg, sizeof(karg),\ninclude/linux/uaccess.h-466- *\t\t\t\t  \u0026ignored_trailing);\n--\ninclude/linux/uaccess.h=489=static __always_inline __must_check int\ninclude/linux/uaccess.h:490:copy_struct_to_user(void __user *dst, size_t usize, const void *src,\ninclude/linux/uaccess.h-491-\t\t    size_t ksize, bool *ignored_trailing)\n--\ninclude/linux/uaccess.h=538=copy_struct_from_bounce_buffer(void *dst, size_t dstsize,\n--\ninclude/linux/uaccess.h-556-/**\ninclude/linux/uaccess.h:557: * This is like copy_struct_to_user(), but the\ninclude/linux/uaccess.h-558- * dst buffer is a kernel bounce buffer instead\n--\nio_uring/query.c=69=static int io_handle_query_entry(union io_query_data *data, void __user *uhdr,\n--\nio_uring/query.c-116-\nio_uring/query.c:117:\tif (copy_struct_to_user(udata, usize, data, hdr.size, NULL))\nio_uring/query.c-118-\t\treturn -EFAULT;\n--\nkernel/sched/syscalls.c=1060=SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,\n--\nkernel/sched/syscalls.c-1103-\tkattr.size = min(usize, sizeof(kattr));\nkernel/sched/syscalls.c:1104:\treturn copy_struct_to_user(uattr, usize, \u0026kattr, sizeof(kattr), NULL);\nkernel/sched/syscalls.c-1105-}\n"
}

31/3 2026/08/07 20:05 llm kmsan-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10063
							output: 38
							thoughts: 1479
						

Thoughts:
**Analysis of Potential Uninitialized Memory Leak in KVM PPC Compatibility Capabilities Handling**

Okay, let's break this down systematically. I see the function `copy_struct_to_user` from `include/linux/uaccess.h` is involved, and it handles the transfer of a struct from kernel space to user space, taking size differences into account. Specifically, I'm focusing on the interaction with `host_caps` in this KVM PPC context.

First, `host_caps` is initialized to zero (`struct kvm_ppc_compat_caps host_caps = {};`).  That's good, means all fields start clean. Then, `copy_struct_from_user` copies user-provided data into `host_caps`. If the user provides a smaller size (`usize < sizeof(host_caps)`), the trailing bytes of `host_caps` will remain zero, or will be explicitly zeroed by the function, which is fine.

Now, the `kvm->arch.kvm_ops->get_compat_caps` function gets called. I'm checking it in `arch/powerpc/kvm/book3s_hv.c`. It seems like the only field of `host_caps` modified in this function is `compat_capabilities`. The rest stays as it was from the `copy_struct_from_user` call (potentially user-provided data).

Crucially, `copy_struct_from_user` *overwrites* `host_caps`. So, if the user sends uninitialized data, that uninitialized data ends up in `host_caps`.  Then, `compat_capabilities` gets overwritten with the value from `get_compat_caps`. Then the `size` is rewritten with the min of the size.

Here's the key: the `copy_struct_to_user` then copies `host_caps` *back* to userspace.  This makes me immediately look for any uninitialized memory leakage.

However, `host_caps` is *zero-initialized*. Then, the user's data is copied into `host_caps`. Any remaining bytes are zeroed by the kernel. Then the kernel overwrites `compat_capabilities` and size with known values. This means there's no leak. The data being copied back either *came* from userspace, was explicitly zeroed, or set by the kernel.

I'm also looking at the struct definition:
```c
struct kvm_ppc_compat_caps {
	__u64	size;			/* Size of this structure */
	__u64	flags;			/* Reserved for future use */
	__u64	compat_capabilities;	/* Capabilities supported by the host */
};
```
No padding between fields, all `__u64`, so there are no opportunities for padding-related issues. And even if there *was* padding, the zero-initialization takes care of it. Also, `copy_struct_from_user` would overwrite padding with user data, which is fine to send back.

I need to confirm there are no uninitialized variables in `kvmppc_get_compat_caps`. `capabilities`, `cpu_version`, and `rc` are all initialized before use. No uninitialized variables being used in conditionals either. So I'm good there.

One final check on `copy_struct_from_user` and `copy_struct_to_user` sizes. If `usize > sizeof(host_caps)`, `copy_struct_from_user` checks for trailing non-zero bytes in userspace, and returns `-E2BIG` if they are not zero. If they *are* zero, then it copies `sizeof(host_caps)` bytes into kernel memory, which is what we expect.  Now, the critical part... `copy_struct_to_user` copies back to userspace. And it takes `usize` as input. So even if `usize > sizeof(host_caps)`, `copy_struct_to_user` will copy `sizeof(host_caps)` bytes into userspace, and zero out the remaining bytes in userspace!

I'm now satisfied there is no uninitialized memory leak here, after the double check of `copy_struct_to_user`. I'd want to check the implementation of that function, but the size parameters are enough to confirm the correct behavior.



32/3 2026/08/07 20:06 tool grepper
0m Args:
{
  "Expression": "copy_struct_to_user\\(void __user \\*dst, size_t usize, const void \\*src,"
}

Results:
{
  "Output": "include/linux/uaccess.h=489=static __always_inline __must_check int\ninclude/linux/uaccess.h:490:copy_struct_to_user(void __user *dst, size_t usize, const void *src,\ninclude/linux/uaccess.h-491-\t\t    size_t ksize, bool *ignored_trailing)\n"
}

33/3 2026/08/07 20:06 llm kmsan-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12626
							output: 36
							thoughts: 24
						

Thoughts:
Here's my take on those thoughts:

**Analyzing `copy_struct_to_user` for Efficiency and Security**

Okay, let's dive into `copy_struct_to_user` within `include/linux/uaccess.h`. I need to refresh my understanding of the implications of this function, as it's a critical component when dealing with user-space data structures. My first concern is always performance: how efficiently does it transfer the data? Are there any obvious bottlenecks I should be aware of, perhaps related to alignment issues or redundant checks?

Then, the security implications. `copy_struct_to_user` is a classic area for vulnerabilities. I need to scrutinize any potential for buffer overflows or format string bugs, even if they seem unlikely. Are the source and destination addresses rigorously validated? What about potential race conditions if the user-space data changes concurrently? I need to be sure that this function incorporates robust mechanisms to prevent unauthorized data access or corruption. Is there proper bound checking implemented? Any potential for integer overflows leading to write past the end of the buffer? And finally, does this function handle unaligned accesses gracefully, and if so, at what cost? I can probably optimize this further.



34/3 2026/08/07 20:06 tool read-file
0m Args:
{
  "File": "include/linux/uaccess.h",
  "FirstLine": 489,
  "LineCount": 50
}

Results:
{
  "Contents": " 489:\tstatic __always_inline __must_check int\n 490:\tcopy_struct_to_user(void __user *dst, size_t usize, const void *src,\n 491:\t\t\t    size_t ksize, bool *ignored_trailing)\n 492:\t{\n 493:\t\tsize_t size = min(ksize, usize);\n 494:\t\tsize_t rest = max(ksize, usize) - size;\n 495:\t\n 496:\t\t/* Double check if ksize is larger than a known object size. */\n 497:\t\tif (WARN_ON_ONCE(ksize \u003e __builtin_object_size(src, 1)))\n 498:\t\t\treturn -E2BIG;\n 499:\t\n 500:\t\t/* Deal with trailing bytes. */\n 501:\t\tif (usize \u003e ksize) {\n 502:\t\t\tif (clear_user(dst + size, rest))\n 503:\t\t\t\treturn -EFAULT;\n 504:\t\t}\n 505:\t\tif (ignored_trailing)\n 506:\t\t\t*ignored_trailing = usize \u003c ksize \u0026\u0026\n 507:\t\t\t\tmemchr_inv(src + size, 0, rest) != NULL;\n 508:\t\t/* Copy the interoperable parts of the struct. */\n 509:\t\tif (copy_to_user(dst, src, size))\n 510:\t\t\treturn -EFAULT;\n 511:\t\treturn 0;\n 512:\t}\n 513:\t\n 514:\tstatic __always_inline void\n 515:\t__copy_struct_generic_bounce_buffer(void *dst, size_t dstsize,\n 516:\t\t\t\t\t    const void *src, size_t srcsize,\n 517:\t\t\t\t\t    bool *ignored_trailing)\n 518:\t{\n 519:\t\tsize_t size = min(dstsize, srcsize);\n 520:\t\tsize_t rest = max(dstsize, srcsize) - size;\n 521:\t\n 522:\t\t/* Deal with trailing bytes. */\n 523:\t\tif (dstsize \u003e srcsize)\n 524:\t\t\tmemset(dst + size, 0, rest);\n 525:\t\tif (ignored_trailing)\n 526:\t\t\t*ignored_trailing = dstsize \u003c srcsize \u0026\u0026\n 527:\t\t\t\tmemchr_inv(src + size, 0, rest) != NULL;\n 528:\t\t/* Copy the interoperable parts of the struct. */\n 529:\t\tmemcpy(dst, src, size);\n 530:\t}\n 531:\t\n 532:\t/**\n 533:\t * This is like copy_struct_from_user(), but the\n 534:\t * src buffer was already copied into a kernel\n 535:\t * bounce buffer, so it will never return -EFAULT.\n 536:\t */\n 537:\tstatic __always_inline __must_check int\n 538:\tcopy_struct_from_bounce_buffer(void *dst, size_t dstsize,\n"
}

35/3 2026/08/07 20:06 llm kmsan-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13748
							output: 36
							thoughts: 1345
						

Thoughts:
**Analyzing the Code for Potential Initialization Issues**

Okay, so I've been looking at this code, specifically around the `kvmppc_get_compat_caps` function, trying to ensure there aren't any potential vulnerabilities related to uninitialized variables or information leaks, and this is what I've got so far.

First, I confirmed my understanding of how `copy_struct_to_user` works. It clears trailing bytes in userspace if the copy size (`usize`) is larger than the kernel struct's size (`ksize`).  More importantly, it copies a *maximum* of `min(ksize, usize)` bytes from the source (`src`) to the destination (`dst`), which means it won't read past the end of the initialized source memory. In our case, the source is `&host_caps`, and `ksize` is `sizeof(host_caps)`, which is fully initialized. So it will be safe.

Now, going through `kvmppc_get_compat_caps` itself, I'm tracing the values. `capabilities` is initialized to 0, `rc` to `-EINVAL`, and `cpu_version` to 0. The code branches based on `kvmhv_on_pseries()`. If it's false, `rc` remains `-EINVAL`, and the function returns immediately.

If `kvmhv_on_pseries()` is true and `kvmhv_is_nestedv2()` is also true, `capabilities` gets assigned `nested_capabilities`, and `rc` is set to 0.  That is a conditional set from a pre-defined value.

Otherwise, if `kvmhv_is_nestedv2()` is false, the code iterates through "cpu" nodes using `of_node_put`.  It attempts to read a "cpu-version" property into `cpu_version`. `of_property_read_u32` returns 0 on success, and a negative error code on failure.  Importantly, if the read is successful, the loop breaks. So it effectively finds the *first* CPU node with the property, and there are no race conditions.

If no "cpu-version" property is found, `cpu_version` remains 0, and the function returns `-EINVAL`.  If it *is* found, the non-zero `cpu_version` is passed to `kvmppc_map_compat_capabilities`. This function then populates `capabilities` based on `cpu_version`, and returns a value. `rc` is set to the return value of the map function.

If `rc` is negative, the function returns early. Otherwise, it bitwise ANDs `capabilities` with `KVM_PPC_COMPAT_BITMASK` and stores the result in `host_caps->compat_capabilities`, before returning `rc` (which should now be 0).

So it looks good. Everything I have reviewed seems to be properly initialized before use. The struct `host_caps` is definitely zero-initialized. I'm confident `copy_struct_from_user` and `copy_struct_to_user` handle copying safely. There doesn't appear to be any risk of uninitialized memory usage or potential information leaks here.

I think I've covered all the key areas, but I should probably double-check the precise behavior of `copy_struct_from_user` once more to be completely sure.



36/3 2026/08/07 20:06 tool read-file
0m Args:
{
  "File": "include/linux/uaccess.h",
  "FirstLine": 393,
  "LineCount": 50
}

Results:
{
  "Contents": " 393:\tcopy_struct_from_user(void *dst, size_t ksize, const void __user *src,\n 394:\t\t\t      size_t usize)\n 395:\t{\n 396:\t\tsize_t size = min(ksize, usize);\n 397:\t\tsize_t rest = max(ksize, usize) - size;\n 398:\t\n 399:\t\t/* Double check if ksize is larger than a known object size. */\n 400:\t\tif (WARN_ON_ONCE(ksize \u003e __builtin_object_size(dst, 1)))\n 401:\t\t\treturn -E2BIG;\n 402:\t\n 403:\t\t/* Deal with trailing bytes. */\n 404:\t\tif (usize \u003c ksize) {\n 405:\t\t\tmemset(dst + size, 0, rest);\n 406:\t\t} else if (usize \u003e ksize) {\n 407:\t\t\tint ret = check_zeroed_user(src + size, rest);\n 408:\t\t\tif (ret \u003c= 0)\n 409:\t\t\t\treturn ret ?: -E2BIG;\n 410:\t\t}\n 411:\t\t/* Copy the interoperable parts of the struct. */\n 412:\t\tif (copy_from_user(dst, src, size))\n 413:\t\t\treturn -EFAULT;\n 414:\t\treturn 0;\n 415:\t}\n 416:\t\n 417:\t/**\n 418:\t * copy_struct_to_user: copy a struct to userspace\n 419:\t * @dst:   Destination address, in userspace. This buffer must be @ksize\n 420:\t *         bytes long.\n 421:\t * @usize: (Alleged) size of @dst struct.\n 422:\t * @src:   Source address, in kernel space.\n 423:\t * @ksize: Size of @src struct.\n 424:\t * @ignored_trailing: Set to %true if there was a non-zero byte in @src that\n 425:\t * userspace cannot see because they are using an smaller struct.\n 426:\t *\n 427:\t * Copies a struct from kernel space to userspace, in a way that guarantees\n 428:\t * backwards-compatibility for struct syscall arguments (as long as future\n 429:\t * struct extensions are made such that all new fields are *appended* to the\n 430:\t * old struct, and zeroed-out new fields have the same meaning as the old\n 431:\t * struct).\n 432:\t *\n 433:\t * Some syscalls may wish to make sure that userspace knows about everything in\n 434:\t * the struct, and if there is a non-zero value that userspce doesn't know\n 435:\t * about, they want to return an error (such as -EMSGSIZE) or have some other\n 436:\t * fallback (such as adding a \"you're missing some information\" flag). If\n 437:\t * @ignored_trailing is non-%NULL, it will be set to %true if there was a\n 438:\t * non-zero byte that could not be copied to userspace (ie. was past @usize).\n 439:\t *\n 440:\t * While unconditionally returning an error in this case is the simplest\n 441:\t * solution, for maximum backward compatibility you should try to only return\n 442:\t * -EMSGSIZE if the user explicitly requested the data that couldn't be copied.\n"
}

37/3 2026/08/07 20:06 llm kmsan-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16785
							output: 312
							thoughts: 1030
						

Thoughts:
**KMSAN Fuzzing Session Not Justified**

Okay, let's break this down. Analyzing this patch, it's clear that it's introducing a new `KVM_PPC_GET_COMPAT_CAPS` ioctl. My immediate concern is always uninitialized memory, but after careful examination, I don't see any significant risk here.

First, the `host_caps` struct is allocated on the stack and explicitly zero-initialized with `= {}`. This guarantees a clean slate, removing any potential issues arising from uninitialized data. Furthermore, the code uses `copy_struct_from_user` and `copy_struct_to_user` consistently. These helpers are designed to handle potential size differences between the userspace and kernel-space structs, which is a common source of vulnerabilities. `copy_struct_from_user` is crucial, because it zero-initializes the trailing bytes in the destination buffer if the source is smaller. Since `host_caps` is already zeroed, the memset is redundant, but harmless. `copy_struct_to_user` guarantees that we're only sending back to userspace the size we're supposed to. This eliminates the risk of an info-leak by sending back uninitialized memory or garbage.

Now, looking at the code, `kvmppc_get_compat_caps()` populates the `compat_capabilities` field, which I know is handled using fully initialized local variables within the kernel. Therefore, there are no complex structures to worry about, nothing that could lead to an information leak. I'm confident that the code is sound.

The patch is clean and straightforward. In my professional opinion, given the safety mechanisms already in place, such as `copy_struct_from_user`, and the standard KASAN checks, a dedicated KMSAN fuzzing session would be overkill. I don't see a significant risk of uninitialized memory usage or data leaks.



38/3 2026/08/07 20:06 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` which takes a struct `kvm_ppc_compat_caps` from userspace, populates it with host capabilities, and copies it back. The struct `host_caps` is allocated on the stack and explicitly zero-initialized using `= {}`. The kernel uses the standard `copy_struct_from_user()` and `copy_struct_to_user()` helpers, which safely handle size mismatches between userspace and kernel space. Specifically, `copy_struct_from_user()` zeroes any trailing bytes if the userspace struct is smaller than the kernel's, and `copy_struct_to_user()` ensures that only initialized bytes up to the requested size are copied back to userspace, clearing any trailing bytes in the userspace buffer if necessary. The `kvmppc_get_compat_caps()` function only modifies the `compat_capabilities` field using fully initialized local variables. There are no uninitialized variables, padding bytes, or complex data structures that could lead to an info-leak or uninitialized memory usage. Any potential bugs introduced by this patch (such as invalid user pointers or out-of-bounds accesses) would be caught by standard KASAN and other bug detectors. Thus, a dedicated KMSAN fuzzing session is not needed.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch introduces a new KVM ioctl `KVM_PPC_GET_COMPAT_CAPS` which takes a struct `kvm_ppc_compat_caps` from userspace, populates it with host capabilities, and copies it back. The struct `host_caps` is allocated on the stack and explicitly zero-initialized using `= {}`. The kernel uses the standard `copy_struct_from_user()` and `copy_struct_to_user()` helpers, which safely handle size mismatches between userspace and kernel space. Specifically, `copy_struct_from_user()` zeroes any trailing bytes if the userspace struct is smaller than the kernel's, and `copy_struct_to_user()` ensures that only initialized bytes up to the requested size are copied back to userspace, clearing any trailing bytes in the userspace buffer if necessary. The `kvmppc_get_compat_caps()` function only modifies the `compat_capabilities` field using fully initialized local variables. There are no uninitialized variables, padding bytes, or complex data structures that could lead to an info-leak or uninitialized memory usage. Any potential bugs introduced by this patch (such as invalid user pointers or out-of-bounds accesses) would be caught by standard KASAN and other bug detectors. Thus, a dedicated KMSAN fuzzing session is not needed.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)