| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/11 07:02 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"KVM",
"VIRTUALIZATION"
],
"FocusSymbols": [
"kvm_arch_vcpu_pre_fault_memory",
"kvm_riscv_gstage_map_page"
],
"KMSANReasoning": "The patch implements the `KVM_CAP_PRE_FAULT_MEMORY` capability for RISC-V by adding `kvm_arch_vcpu_pre_fault_memory` and wiring it up in the MMU. The only data structure involved in user space communication is `struct kvm_pre_fault_memory`, which is handled by generic KVM code (`virt/kvm/kvm_main.c`). The generic code fully initializes the struct via `copy_from_user` before modifying its `size` and `gpa` fields and copying it back to user space. Any padding fields simply echo back the user-provided values, preventing any kernel memory info-leaks. The local variable `out_map` of type `struct kvm_gstage_mapping` is explicitly zero-initialized (`= { 0 }`) before being passed to `kvm_riscv_mmu_map`. There are no new complex allocations, uninitialized variables, or info-leaks introduced by this patch. Standard KASAN is sufficient to catch any potential memory corruption or out-of-bounds accesses.",
"NeedsKMSAN": false,
"Reasoning": "The patch enables the KVM_CAP_PRE_FAULT_MEMORY capability and its corresponding ioctl (KVM_PRE_FAULT_MEMORY) for RISC-V KVM. It implements the architecture-specific handler `kvm_arch_vcpu_pre_fault_memory` and modifies `kvm_riscv_gstage_map_page` to return mapping information. This introduces new reachable code paths in the RISC-V KVM subsystem that can be triggered from userspace via the ioctl.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/11 07:02 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b0b60a0c79f3c22f9af68768880d26cfb2522502\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Aug 11 07:01:59 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig\nindex ec2cee0a39e01..8ac209e8ac870 100644\n--- a/arch/riscv/kvm/Kconfig\n+++ b/arch/riscv/kvm/Kconfig\n@@ -28,6 +28,7 @@ config KVM\n \tselect KVM_COMMON\n \tselect KVM_GENERIC_DIRTYLOG_READ_PROTECT\n \tselect KVM_GENERIC_HARDWARE_ENABLING\n+\tselect KVM_GENERIC_PRE_FAULT_MEMORY\n \tselect KVM_MMIO\n \tselect VIRT_XFER_TO_GUEST_WORK\n \tselect SCHED_INFO\ndiff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c\nindex e5002cb9cbef1..6bd8b8fd6ceb2 100644\n--- a/arch/riscv/kvm/gstage.c\n+++ b/arch/riscv/kvm/gstage.c\n@@ -280,6 +280,9 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,\n \t\t\t\t\t\t out_map-\u003elevel, true);\n \t\t} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {\n \t\t\tkvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);\n+\t\t\tout_map-\u003eaddr = ALIGN_DOWN(gpa, page_size);\n+\t\t\tout_map-\u003elevel = ptep_level;\n+\t\t\tout_map-\u003epte = ptep_get(ptep);\n \t\t\treturn 0;\n \t\t}\n \t}\ndiff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c\nindex 6035b5ec95039..c96e21740c913 100644\n--- a/arch/riscv/kvm/mmu.c\n+++ b/arch/riscv/kvm/mmu.c\n@@ -748,6 +748,39 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n \treturn ret;\n }\n \n+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_pre_fault_memory *range)\n+{\n+\tstruct kvm_gstage_mapping out_map = { 0 };\n+\tstruct kvm_memory_slot *memslot;\n+\tunsigned long map_size;\n+\tunsigned long hva;\n+\tgpa_t end;\n+\tgfn_t gfn;\n+\tint ret;\n+\n+\tgfn = gpa_to_gfn(range-\u003egpa);\n+\tmemslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);\n+\tif (!memslot)\n+\t\treturn -ENOENT;\n+\n+\thva = gfn_to_hva_memslot_prot(memslot, gfn, NULL);\n+\tif (kvm_is_error_hva(hva))\n+\t\treturn -ENOENT;\n+\n+\tret = kvm_riscv_mmu_map(vcpu, memslot, range-\u003egpa, hva, false, \u0026out_map);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!pte_val(out_map.pte))\n+\t\treturn -EAGAIN;\n+\n+\tmap_size = PAGE_SIZE \u003c\u003c (out_map.level * kvm_riscv_gstage_index_bits);\n+\tend = ALIGN_DOWN(range-\u003egpa, map_size) + map_size;\n+\n+\treturn min_t(u64, range-\u003esize, end - range-\u003egpa);\n+}\n+\n int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)\n {\n \tstruct page *pgd_page;\ndiff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c\nindex a9f083feeb767..58500a19b33bd 100644\n--- a/arch/riscv/kvm/vm.c\n+++ b/arch/riscv/kvm/vm.c\n@@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)\n \tcase KVM_CAP_MP_STATE:\n \tcase KVM_CAP_IMMEDIATE_EXIT:\n \tcase KVM_CAP_SET_GUEST_DEBUG:\n+\tcase KVM_CAP_PRE_FAULT_MEMORY:\n \t\tr = 1;\n \t\tbreak;\n \tcase KVM_CAP_NR_VCPUS:\ndiff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm\nindex 6fc34e9bf8e1b..ac64ac92fd4b0 100644\n--- a/tools/testing/selftests/kvm/Makefile.kvm\n+++ b/tools/testing/selftests/kvm/Makefile.kvm\n@@ -225,6 +225,7 @@ TEST_GEN_PROGS_riscv += coalesced_io_test\n TEST_GEN_PROGS_riscv += dirty_log_perf_test\n TEST_GEN_PROGS_riscv += get-reg-list\n TEST_GEN_PROGS_riscv += mmu_stress_test\n+TEST_GEN_PROGS_riscv += pre_fault_memory_test\n TEST_GEN_PROGS_riscv += rseq_test\n TEST_GEN_PROGS_riscv += steal_time\n \ndiff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h\nindex e3acf2ae9881e..70487c8ed1553 100644\n--- a/tools/testing/selftests/kvm/include/riscv/processor.h\n+++ b/tools/testing/selftests/kvm/include/riscv/processor.h\n@@ -12,6 +12,9 @@\n #include \u003casm/vdso/processor.h\u003e\n #include \"kvm_util.h\"\n \n+#define PAGE_SHIFT\t\t12\n+#define PAGE_SIZE\t\tBIT_ULL(PAGE_SHIFT)\n+\n #define INSN_OPCODE_MASK\t0x007c\n #define INSN_OPCODE_SHIFT\t2\n #define INSN_OPCODE_SYSTEM\t28\n@@ -127,6 +130,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handl\n \n void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler);\n \n+/* L4 index Bit[56:48] */\n+#define PGTBL_L4_INDEX_MASK\t\t\t0x01FF000000000000ULL\n+#define PGTBL_L4_INDEX_SHIFT\t\t\t48\n /* L3 index Bit[47:39] */\n #define PGTBL_L3_INDEX_MASK\t\t\t0x0000FF8000000000ULL\n #define PGTBL_L3_INDEX_SHIFT\t\t\t39\ndiff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c\nindex ded5429f34483..b4d41a4075536 100644\n--- a/tools/testing/selftests/kvm/lib/riscv/processor.c\n+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c\n@@ -43,6 +43,7 @@ static u64 pte_index_mask[] = {\n \tPGTBL_L1_INDEX_MASK,\n \tPGTBL_L2_INDEX_MASK,\n \tPGTBL_L3_INDEX_MASK,\n+\tPGTBL_L4_INDEX_MASK,\n };\n \n static u32 pte_index_shift[] = {\n@@ -50,6 +51,7 @@ static u32 pte_index_shift[] = {\n \tPGTBL_L1_INDEX_SHIFT,\n \tPGTBL_L2_INDEX_SHIFT,\n \tPGTBL_L3_INDEX_SHIFT,\n+\tPGTBL_L4_INDEX_SHIFT,\n };\n \n static u64 pte_index(struct kvm_vm *vm, gva_t gva, int level)\ndiff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c\nindex a0fcae3cb7a8b..6eebf05246736 100644\n--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c\n+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c\n@@ -8,6 +8,7 @@\n #include \u003clinux/sizes.h\u003e\n \n #include \u003ctest_util.h\u003e\n+#include \u003cguest_modes.h\u003e\n #include \u003ckvm_util.h\u003e\n #include \u003cprocessor.h\u003e\n #include \u003cpthread.h\u003e\n@@ -219,6 +220,8 @@ static void test_pre_fault_memory(unsigned long vm_type, bool private)\n \n int main(int argc, char *argv[])\n {\n+\tguest_modes_append_default();\n+\n \tTEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));\n \n \ttest_pre_fault_memory(0, false);\n"
} |
| 2/1 | 2026/08/11 07:02 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"KVM",
"VIRTUALIZATION"
],
"FocusSymbols": [
"kvm_arch_vcpu_pre_fault_memory",
"kvm_riscv_gstage_map_page"
],
"Reasoning": "The patch enables the KVM_CAP_PRE_FAULT_MEMORY capability and its corresponding ioctl (KVM_PRE_FAULT_MEMORY) for RISC-V KVM. It implements the architecture-specific handler `kvm_arch_vcpu_pre_fault_memory` and modifies `kvm_riscv_gstage_map_page` to return mapping information. This introduces new reachable code paths in the RISC-V KVM subsystem that can be triggered from userspace via the ioctl.",
"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 b0b60a0c79f3c22f9af68768880d26cfb2522502
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Aug 11 07:01:59 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig
index ec2cee0a39e01..8ac209e8ac870 100644
--- a/arch/riscv/kvm/Kconfig
+++ b/arch/riscv/kvm/Kconfig
@@ -28,6 +28,7 @@ config KVM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
+ select KVM_GENERIC_PRE_FAULT_MEMORY
select KVM_MMIO
select VIRT_XFER_TO_GUEST_WORK
select SCHED_INFO
diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef1..6bd8b8fd6ceb2 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -280,6 +280,9 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
out_map->level, true);
} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {
kvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);
+ out_map->addr = ALIGN_DOWN(gpa, page_size);
+ out_map->level = ptep_level;
+ out_map->pte = ptep_get(ptep);
return 0;
}
}
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 6035b5ec95039..c96e21740c913 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,39 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
return ret;
}
+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range)
+{
+ struct kvm_gstage_mapping out_map = { 0 };
+ struct kvm_memory_slot *memslot;
+ unsigned long map_size;
+ unsigned long hva;
+ gpa_t end;
+ gfn_t gfn;
+ int ret;
+
+ gfn = gpa_to_gfn(range->gpa);
+ memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+ if (!memslot)
+ return -ENOENT;
+
+ hva = gfn_to_hva_memslot_prot(memslot, gfn, NULL);
+ if (kvm_is_error_hva(hva))
+ return -ENOENT;
+
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ return -EAGAIN;
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = ALIGN_DOWN(range->gpa, map_size) + map_size;
+
+ return min_t(u64, range->size, end - range->gpa);
+}
+
int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)
{
struct page *pgd_page;
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index a9f083feeb767..58500a19b33bd 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_SET_GUEST_DEBUG:
+ case KVM_CAP_PRE_FAULT_MEMORY:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 6fc34e9bf8e1b..ac64ac92fd4b0 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -225,6 +225,7 @@ TEST_GEN_PROGS_riscv += coalesced_io_test
TEST_GEN_PROGS_riscv += dirty_log_perf_test
TEST_GEN_PROGS_riscv += get-reg-list
TEST_GEN_PROGS_riscv += mmu_stress_test
+TEST_GEN_PROGS_riscv += pre_fault_memory_test
TEST_GEN_PROGS_riscv += rseq_test
TEST_GEN_PROGS_riscv += steal_time
diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h
index e3acf2ae9881e..70487c8ed1553 100644
--- a/tools/testing/selftests/kvm/include/riscv/processor.h
+++ b/tools/testing/selftests/kvm/include/riscv/processor.h
@@ -12,6 +12,9 @@
#include <asm/vdso/processor.h>
#include "kvm_util.h"
+#define PAGE_SHIFT 12
+#define PAGE_SIZE BIT_ULL(PAGE_SHIFT)
+
#define INSN_OPCODE_MASK 0x007c
#define INSN_OPCODE_SHIFT 2
#define INSN_OPCODE_SYSTEM 28
@@ -127,6 +130,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handl
void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler);
+/* L4 index Bit[56:48] */
+#define PGTBL_L4_INDEX_MASK 0x01FF000000000000ULL
+#define PGTBL_L4_INDEX_SHIFT 48
/* L3 index Bit[47:39] */
#define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL
#define PGTBL_L3_INDEX_SHIFT 39
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index ded5429f34483..b4d41a4075536 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -43,6 +43,7 @@ static u64 pte_index_mask[] = {
PGTBL_L1_INDEX_MASK,
PGTBL_L2_INDEX_MASK,
PGTBL_L3_INDEX_MASK,
+ PGTBL_L4_INDEX_MASK,
};
static u32 pte_index_shift[] = {
@@ -50,6 +51,7 @@ static u32 pte_index_shift[] = {
PGTBL_L1_INDEX_SHIFT,
PGTBL_L2_INDEX_SHIFT,
PGTBL_L3_INDEX_SHIFT,
+ PGTBL_L4_INDEX_SHIFT,
};
static u64 pte_index(struct kvm_vm *vm, gva_t gva, int level)
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index a0fcae3cb7a8b..6eebf05246736 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -8,6 +8,7 @@
#include <linux/sizes.h>
#include <test_util.h>
+#include <guest_modes.h>
#include <kvm_util.h>
#include <processor.h>
#include <pthread.h>
@@ -219,6 +220,8 @@ static void test_pre_fault_memory(unsigned long vm_type, bool private)
int main(int argc, char *argv[])
{
+ guest_modes_append_default();
+
TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));
test_pre_fault_memory(0, false);
|
| 3/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 4380 output: 27 thoughts: 439 Thoughts: **Analyzing the RISC-V KVM Pre-Fault Memory Patch** Okay, so I'm looking at this patch for RISC-V KVM that's adding support for `KVM_CAP_PRE_FAULT_MEMORY`. It looks pretty straightforward on the surface. We're modifying `Kconfig` to select `KVM_GENERIC_PRE_FAULT_MEMORY`, which makes sense; this enables the generic pre-faulting mechanism. Then there are changes in `gstage.c` to handle mapping, `mmu.c` which actually adds the core function `kvm_arch_vcpu_pre_fault_memory`, and `vm.c` to advertise the capability. Plus, they've included a self-test. Solid. This clearly introduces a new capability, `KVM_CAP_PRE_FAULT_MEMORY`, and the associated `KVM_PRE_FAULT_MEMORY` ioctl for the vCPU. Functionally sound, that's good. The next thought is, can this be effectively tested in virtualized environments? Of course, this is KVM code. Syzkaller is the primary fuzzing tool that comes to mind, and while it heavily targets x86_64, it *does* have some support for ARM64 and RISC-V. Wait, it *does* support RISC-V64, great. Now, I need to check for any specific configuration requirements. It looks like we just need `CONFIG_KVM`, which is standard for KVM guests. Alright, let's drill down. The key function is `kvm_arch_vcpu_pre_fault_memory`. I'm going to look at it in `arch/riscv/kvm/mmu.c`. It looks like it calls `kvm_riscv_mmu_map` to do the actual mapping. To be thorough, I'm going to leverage `default_api:grepper` to see if `kvm_arch_vcpu_pre_fault_memory` is ever called directly from generic KVM code. This will help confirm this specific RISC-V code path. I want to see how tightly coupled this is to generic KVM operations. |
| 4/2 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "kvm_arch_vcpu_pre_fault_memory"
}Results: {
"Output": "arch/riscv/kvm/mmu.c=623=int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n--\narch/riscv/kvm/mmu.c-750-\narch/riscv/kvm/mmu.c:751:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/riscv/kvm/mmu.c-752-\t\t\t\t struct kvm_pre_fault_memory *range)\n--\narch/s390/kvm/kvm-s390.c=5797=void kvm_arch_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/kvm-s390.c-5840-/**\narch/s390/kvm/kvm-s390.c:5841: * kvm_arch_vcpu_pre_fault_memory() -- pre-fault and link gmap dat tables\narch/s390/kvm/kvm-s390.c-5842- * @vcpu: the vcpu that shall appear to have generated the fault-in.\n--\narch/s390/kvm/kvm-s390.c-5859- */\narch/s390/kvm/kvm-s390.c:5860:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)\narch/s390/kvm/kvm-s390.c-5861-{\n--\narch/x86/kvm/mmu/mmu.c=4973=static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa,\n--\narch/x86/kvm/mmu/mmu.c-5016-\narch/x86/kvm/mmu/mmu.c:5017:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/x86/kvm/mmu/mmu.c-5018-\t\t\t\t struct kvm_pre_fault_memory *range)\n--\narch/x86/kvm/vmx/tdx.c=1701=static int tdx_sept_map_leaf_spte(struct kvm *kvm, gfn_t gfn, enum pg_level level,\n--\narch/x86/kvm/vmx/tdx.c-1713-\t/*\narch/x86/kvm/vmx/tdx.c:1714:\t * Ensure pre_fault_allowed is read by kvm_arch_vcpu_pre_fault_memory()\narch/x86/kvm/vmx/tdx.c-1715-\t * before kvm_tdx-\u003estate. Userspace must not be allowed to pre-fault\n--\ninclude/linux/kvm_host.h=2610=void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);\n--\ninclude/linux/kvm_host.h-2613-#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY\ninclude/linux/kvm_host.h:2614:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\ninclude/linux/kvm_host.h-2615-\t\t\t\t struct kvm_pre_fault_memory *range);\n--\nvirt/kvm/kvm_main.c=4334=static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n--\nvirt/kvm/kvm_main.c-4358-\nvirt/kvm/kvm_main.c:4359:\t\tr = kvm_arch_vcpu_pre_fault_memory(vcpu, range);\nvirt/kvm/kvm_main.c-4360-\t\tif (WARN_ON_ONCE(r == 0 || r == -EIO))\n"
} |
| 5/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6412 output: 33 thoughts: 276 Thoughts: **My Initial Assessment of the RISC-V KVM Pre-Fault Memory Patch** Okay, so this patch introduces support for the `KVM_PRE_FAULT_MEMORY` ioctl specifically for RISC-V. It's called through `kvm_vcpu_pre_fault_memory` from `kvm_main.c`, triggered by the ioctl itself. Since this is a new ioctl handler, fuzzing is definitely warranted; that's a prime target for finding potential vulnerabilities. The core implementation seems to reside in `arch/riscv/kvm/mmu.c`, which makes sense given the memory-related nature of the ioctl. The main function I need to focus on is `kvm_arch_vcpu_pre_fault_memory`, although the naming is a bit misleading since it's defined specifically for RISC-V. It's actually in `arch/riscv/kvm/mmu.c`. Also worth noting is the modification to `kvm_riscv_gstage_map_page`. I'll check `arch/riscv/kvm/Kconfig` to see if there are any specific kernel configurations required for this functionality to be enabled or if there are any interesting options that could impact its behavior. This could provide valuable context for testing and fuzzing. |
| 6/2 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "config KVM",
"PathPrefix": "arch/riscv/kvm/Kconfig"
}Results: {
"Output": "arch/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"
} |
| 7/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7102 output: 35 thoughts: 27 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, and delivered as a first-person summary: **Kernel Configuration Dependencies: KVM and Virtualization** Alright, I'm diving into this kernel configuration, and the first thing that jumps out is the absolute requirement for `CONFIG_KVM`. That's a given – can't do anything KVM-related without that enabled, obviously. Now, the next logical question is: does enabling KVM necessitate, or at least highly suggest, that we also consider `CONFIG_VIRTUALIZATION`? The relationship there is key. It's almost certain that the underlying hypervisor support will be needed, but I need to quickly confirm whether `VIRTUALIZATION` is *strictly* a prerequisite, or if it's more of an ancillary feature that is best practice to enable when enabling KVM. I need to understand that dependency path clearly to make the right configuration decisions. It depends on whether we are dealing with a type 1 or type 2 hypervisor, and how much is being virtualized, or emulated. |
| 8/2 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "config VIRTUALIZATION",
"PathPrefix": "arch/riscv/kvm/Kconfig"
}Results: {
"Output": "arch/riscv/kvm/Kconfig=6=source \"virt/kvm/Kconfig\"\narch/riscv/kvm/Kconfig-7-\narch/riscv/kvm/Kconfig:8:menuconfig VIRTUALIZATION\narch/riscv/kvm/Kconfig-9-\tbool \"Virtualization\"\n"
} |
| 9/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7485 output: 45 thoughts: 54 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience: **Kernel Configuration and MMU Function Review** Alright, first things first, seems like we're looking at KVM on RISC-V. Therefore, `CONFIG_KVM` and `CONFIG_VIRTUALIZATION` are definitely prerequisites. Nothing surprising there. I need to make sure those are enabled, obviously. Next, I'm thinking of diving into the MMU-related code, specifically within the RISC-V KVM implementation. The function I want to look at is `kvm_arch_vcpu_pre_fault_memory` – I'm assuming that's where the core pre-fault handling happens and likely what I need to understand for whatever task I've got in mind. Time to get digging in `arch/riscv/kvm/mmu.c`. |
| 10/2 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "kvm_arch_vcpu_pre_fault_memory",
"PathPrefix": "arch/riscv/kvm/mmu.c"
}Results: {
"Output": "arch/riscv/kvm/mmu.c=623=int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n--\narch/riscv/kvm/mmu.c-750-\narch/riscv/kvm/mmu.c:751:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/riscv/kvm/mmu.c-752-\t\t\t\t struct kvm_pre_fault_memory *range)\n"
} |
| 11/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7932 output: 44 thoughts: 77 Thoughts: Here's my summary, as though I'm thinking through this process: **Focusing on Memory Faults in KVM-RISCV** Alright, the core of this memory fault investigation seems to lie within `kvm_arch_vcpu_pre_fault_memory`. That's definitely where I need to start digging. This is likely where the virtual CPU is intercepting the memory access before the fault even occurs, allowing for our intervention. And, from the looks of it, it seems like `kvm_riscv_gstage_map_page` has seen some modifications. I'll need to understand how those changes in `kvm_riscv_gstage_map_page` are interacting with the fault handling in `kvm_arch_vcpu_pre_fault_memory`. Gotta figure out the interplay. First, let's pull up the source for `kvm_riscv_gstage_map_page`. I'll find it in `arch/riscv/kvm/gstage.c` and see how this is affecting the mapping of guest physical pages within the global stage. It seems like the modifications there are crucial for understanding how the memory faults are handled in RISC-V. That's the priority now. |
| 12/2 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_gstage_map_page",
"PathPrefix": "arch/riscv/kvm/gstage.c"
}Results: {
"Output": "arch/riscv/kvm/gstage.c=186=static void kvm_riscv_gstage_update_pte_prot(struct kvm_gstage *gstage, u32 level,\n--\narch/riscv/kvm/gstage.c-206-\narch/riscv/kvm/gstage.c:207:int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,\narch/riscv/kvm/gstage.c-208-\t\t\t struct kvm_mmu_memory_cache *pcache,\n"
} |
| 13/2 | 2026/08/11 07:02 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8481 output: 180 thoughts: 258 Thoughts: **My Assessment of the RISC-V KVM Patch**
Okay, so I've been looking at this RISC-V KVM patch, and it seems like `kvm_riscv_gstage_map_page` and `kvm_arch_vcpu_pre_fault_memory` are the key functions to focus on. They are the primary targets here.
Let me just quickly check for any other relevant configurations. Ah, yes, `KVM_GENERIC_PRE_FAULT_MEMORY` is indeed selected when `KVM` is enabled for RISC-V. So, just enabling `KVM` should suffice.
Now, let's format my findings for easy consumption.
Essentially, this patch is adding the `KVM_CAP_PRE_FAULT_MEMORY` capability and its associated ioctl, `KVM_PRE_FAULT_MEMORY`, for RISC-V KVM. The architecture-specific pre-fault handler, `kvm_arch_vcpu_pre_fault_memory`, is being introduced. Plus, `kvm_riscv_gstage_map_page` is being updated to return mapping information.
This means new, potentially reachable code paths are being opened up in the RISC-V KVM subsystem, and userspace can trigger them via this new ioctl.
Here's the data for my records:
* **WorthFuzzing**: `true`
* **FocusSymbols**:
* `kvm_arch_vcpu_pre_fault_memory`
* `kvm_riscv_gstage_map_page`
* **EnableConfigs**:
* `KVM`
* `VIRTUALIZATION`
* **Reasoning**: This patch enables the KVM_CAP_PRE_FAULT_MEMORY capability and its corresponding ioctl (KVM_PRE_FAULT_MEMORY) for RISC-V KVM. It implements the architecture-specific handler `kvm_arch_vcpu_pre_fault_memory` and modifies `kvm_riscv_gstage_map_page` to return mapping information. This introduces new reachable code paths in the RISC-V KVM subsystem that can be triggered from userspace via the ioctl.
|
| 14/2 | 2026/08/11 07:02 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM",
"VIRTUALIZATION"
],
"FocusSymbols": [
"kvm_arch_vcpu_pre_fault_memory",
"kvm_riscv_gstage_map_page"
],
"Reasoning": "The patch enables the KVM_CAP_PRE_FAULT_MEMORY capability and its corresponding ioctl (KVM_PRE_FAULT_MEMORY) for RISC-V KVM. It implements the architecture-specific handler `kvm_arch_vcpu_pre_fault_memory` and modifies `kvm_riscv_gstage_map_page` to return mapping information. This introduces new reachable code paths in the RISC-V KVM subsystem that can be triggered from userspace via the ioctl.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM",
"VIRTUALIZATION"
],
"FocusSymbols": [
"kvm_arch_vcpu_pre_fault_memory",
"kvm_riscv_gstage_map_page"
],
"Reasoning": "The patch enables the KVM_CAP_PRE_FAULT_MEMORY capability and its corresponding ioctl (KVM_PRE_FAULT_MEMORY) for RISC-V KVM. It implements the architecture-specific handler `kvm_arch_vcpu_pre_fault_memory` and modifies `kvm_riscv_gstage_map_page` to return mapping information. This introduces new reachable code paths in the RISC-V KVM subsystem that can be triggered from userspace via the ioctl.",
"WorthFuzzing": true
} |
| 15/1 | 2026/08/11 07:02 | action | If |
1mArgs:{
"WorthFuzzing": true
}Results: null |
| 16/2 | 2026/08/11 07:02 | agent | kmsan-evaluator |
1mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch implements the `KVM_CAP_PRE_FAULT_MEMORY` capability for RISC-V by adding `kvm_arch_vcpu_pre_fault_memory` and wiring it up in the MMU. The only data structure involved in user space communication is `struct kvm_pre_fault_memory`, which is handled by generic KVM code (`virt/kvm/kvm_main.c`). The generic code fully initializes the struct via `copy_from_user` before modifying its `size` and `gpa` fields and copying it back to user space. Any padding fields simply echo back the user-provided values, preventing any kernel memory info-leaks. The local variable `out_map` of type `struct kvm_gstage_mapping` is explicitly zero-initialized (`= { 0 }`) before being passed to `kvm_riscv_mmu_map`. There are no new complex allocations, uninitialized variables, or info-leaks introduced by this patch. Standard KASAN is sufficient to catch any potential memory corruption or out-of-bounds accesses.",
"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 b0b60a0c79f3c22f9af68768880d26cfb2522502
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Aug 11 07:01:59 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig
index ec2cee0a39e01..8ac209e8ac870 100644
--- a/arch/riscv/kvm/Kconfig
+++ b/arch/riscv/kvm/Kconfig
@@ -28,6 +28,7 @@ config KVM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
+ select KVM_GENERIC_PRE_FAULT_MEMORY
select KVM_MMIO
select VIRT_XFER_TO_GUEST_WORK
select SCHED_INFO
diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef1..6bd8b8fd6ceb2 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -280,6 +280,9 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
out_map->level, true);
} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {
kvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);
+ out_map->addr = ALIGN_DOWN(gpa, page_size);
+ out_map->level = ptep_level;
+ out_map->pte = ptep_get(ptep);
return 0;
}
}
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 6035b5ec95039..c96e21740c913 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -748,6 +748,39 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
return ret;
}
+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range)
+{
+ struct kvm_gstage_mapping out_map = { 0 };
+ struct kvm_memory_slot *memslot;
+ unsigned long map_size;
+ unsigned long hva;
+ gpa_t end;
+ gfn_t gfn;
+ int ret;
+
+ gfn = gpa_to_gfn(range->gpa);
+ memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+ if (!memslot)
+ return -ENOENT;
+
+ hva = gfn_to_hva_memslot_prot(memslot, gfn, NULL);
+ if (kvm_is_error_hva(hva))
+ return -ENOENT;
+
+ ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map);
+ if (ret)
+ return ret;
+
+ if (!pte_val(out_map.pte))
+ return -EAGAIN;
+
+ map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits);
+ end = ALIGN_DOWN(range->gpa, map_size) + map_size;
+
+ return min_t(u64, range->size, end - range->gpa);
+}
+
int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)
{
struct page *pgd_page;
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index a9f083feeb767..58500a19b33bd 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_SET_GUEST_DEBUG:
+ case KVM_CAP_PRE_FAULT_MEMORY:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 6fc34e9bf8e1b..ac64ac92fd4b0 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -225,6 +225,7 @@ TEST_GEN_PROGS_riscv += coalesced_io_test
TEST_GEN_PROGS_riscv += dirty_log_perf_test
TEST_GEN_PROGS_riscv += get-reg-list
TEST_GEN_PROGS_riscv += mmu_stress_test
+TEST_GEN_PROGS_riscv += pre_fault_memory_test
TEST_GEN_PROGS_riscv += rseq_test
TEST_GEN_PROGS_riscv += steal_time
diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h
index e3acf2ae9881e..70487c8ed1553 100644
--- a/tools/testing/selftests/kvm/include/riscv/processor.h
+++ b/tools/testing/selftests/kvm/include/riscv/processor.h
@@ -12,6 +12,9 @@
#include <asm/vdso/processor.h>
#include "kvm_util.h"
+#define PAGE_SHIFT 12
+#define PAGE_SIZE BIT_ULL(PAGE_SHIFT)
+
#define INSN_OPCODE_MASK 0x007c
#define INSN_OPCODE_SHIFT 2
#define INSN_OPCODE_SYSTEM 28
@@ -127,6 +130,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handl
void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler);
+/* L4 index Bit[56:48] */
+#define PGTBL_L4_INDEX_MASK 0x01FF000000000000ULL
+#define PGTBL_L4_INDEX_SHIFT 48
/* L3 index Bit[47:39] */
#define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL
#define PGTBL_L3_INDEX_SHIFT 39
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index ded5429f34483..b4d41a4075536 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -43,6 +43,7 @@ static u64 pte_index_mask[] = {
PGTBL_L1_INDEX_MASK,
PGTBL_L2_INDEX_MASK,
PGTBL_L3_INDEX_MASK,
+ PGTBL_L4_INDEX_MASK,
};
static u32 pte_index_shift[] = {
@@ -50,6 +51,7 @@ static u32 pte_index_shift[] = {
PGTBL_L1_INDEX_SHIFT,
PGTBL_L2_INDEX_SHIFT,
PGTBL_L3_INDEX_SHIFT,
+ PGTBL_L4_INDEX_SHIFT,
};
static u64 pte_index(struct kvm_vm *vm, gva_t gva, int level)
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index a0fcae3cb7a8b..6eebf05246736 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -8,6 +8,7 @@
#include <linux/sizes.h>
#include <test_util.h>
+#include <guest_modes.h>
#include <kvm_util.h>
#include <processor.h>
#include <pthread.h>
@@ -219,6 +220,8 @@ static void test_pre_fault_memory(unsigned long vm_type, bool private)
int main(int argc, char *argv[])
{
+ guest_modes_append_default();
+
TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));
test_pre_fault_memory(0, false);
|
| 17/3 | 2026/08/11 07:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 4377 output: 27 thoughts: 701 Thoughts: **RISC-V KVM Pre-Fault Memory Support Implementation**
Okay, so I'm looking at this patch for RISC-V KVM. The core of it seems to be about adding support for `KVM_CAP_PRE_FAULT_MEMORY`. Essentially, it's about proactively faulting in memory regions, which can improve performance by reducing the latency of the first access.
The first thing I see is the `Kconfig` change; it's selecting `KVM_GENERIC_PRE_FAULT_MEMORY`. Good, we are reusing the generic framework where possible. Then there are the modifications to `gstage.c` – presumably populating `out_map` fields – and `mmu.c`, which implements the key function: `kvm_arch_vcpu_pre_fault_memory`. Finally, it reports the new capability as supported and updates selftests. Seems straightforward so far.
Now let's dive into that `kvm_arch_vcpu_pre_fault_memory` function. I'm seeing a local `struct kvm_gstage_mapping out_map = { 0 };` being initialized to zero. I then see that `kvm_riscv_mmu_map` is being called with `&out_map` as an argument. I see that the `out_map` struct is used later to calculate `map_size` which, given my understanding of the pre-faulting process, seems correct. We're effectively figuring out the mapping's size, based on the MMU's page table level. The `end` calculation then uses the `map_size` to figure out the actual bytes to pre-fault. The function returns the number of bytes that were successfully pre-faulted, or an error.
The important thing is this zero initialization of `out_map`. Is this okay? It could cause problems, it's something I need to look into.
The next point I need to clarify is whether the `struct kvm_pre_fault_memory` is being copied to/from userspace. Because the function is called as an `ioctl` and, given my knowledge of how this typically works with KVM, I'm pretty sure that this is indeed the case. That means there's a good chance this is a vulnerability. I'll need to check the generic KVM code for the `KVM_PRE_FAULT_MEMORY` ioctl implementation. I can use `grepper` to find out where `kvm_arch_vcpu_pre_fault_memory` is actually called. This will give me the full picture.
|
| 18/3 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "kvm_arch_vcpu_pre_fault_memory"
}Results: {
"Output": "arch/riscv/kvm/mmu.c=623=int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n--\narch/riscv/kvm/mmu.c-750-\narch/riscv/kvm/mmu.c:751:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/riscv/kvm/mmu.c-752-\t\t\t\t struct kvm_pre_fault_memory *range)\n--\narch/s390/kvm/kvm-s390.c=5797=void kvm_arch_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/kvm-s390.c-5840-/**\narch/s390/kvm/kvm-s390.c:5841: * kvm_arch_vcpu_pre_fault_memory() -- pre-fault and link gmap dat tables\narch/s390/kvm/kvm-s390.c-5842- * @vcpu: the vcpu that shall appear to have generated the fault-in.\n--\narch/s390/kvm/kvm-s390.c-5859- */\narch/s390/kvm/kvm-s390.c:5860:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)\narch/s390/kvm/kvm-s390.c-5861-{\n--\narch/x86/kvm/mmu/mmu.c=4973=static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa,\n--\narch/x86/kvm/mmu/mmu.c-5016-\narch/x86/kvm/mmu/mmu.c:5017:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/x86/kvm/mmu/mmu.c-5018-\t\t\t\t struct kvm_pre_fault_memory *range)\n--\narch/x86/kvm/vmx/tdx.c=1701=static int tdx_sept_map_leaf_spte(struct kvm *kvm, gfn_t gfn, enum pg_level level,\n--\narch/x86/kvm/vmx/tdx.c-1713-\t/*\narch/x86/kvm/vmx/tdx.c:1714:\t * Ensure pre_fault_allowed is read by kvm_arch_vcpu_pre_fault_memory()\narch/x86/kvm/vmx/tdx.c-1715-\t * before kvm_tdx-\u003estate. Userspace must not be allowed to pre-fault\n--\ninclude/linux/kvm_host.h=2610=void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);\n--\ninclude/linux/kvm_host.h-2613-#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY\ninclude/linux/kvm_host.h:2614:long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\ninclude/linux/kvm_host.h-2615-\t\t\t\t struct kvm_pre_fault_memory *range);\n--\nvirt/kvm/kvm_main.c=4334=static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n--\nvirt/kvm/kvm_main.c-4358-\nvirt/kvm/kvm_main.c:4359:\t\tr = kvm_arch_vcpu_pre_fault_memory(vcpu, range);\nvirt/kvm/kvm_main.c-4360-\t\tif (WARN_ON_ONCE(r == 0 || r == -EIO))\n"
} |
| 19/3 | 2026/08/11 07:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6757 output: 25 thoughts: 31 Thoughts: Okay, let's dive into this. Here's my thought process on tackling this particular function, `kvm_vcpu_pre_fault_memory`, found in `virt/kvm/kvm_main.c`: **Diving into `kvm_vcpu_pre_fault_memory`** Alright, the next step in this investigation is to get a handle on `kvm_vcpu_pre_fault_memory`. I need to figure out what's happening *before* a memory fault occurs, specifically within the KVM environment. Given the name, it's pretty clear this is a pre-fault handler, likely crucial for KVM's memory management and exception handling. The fact that it's in `kvm_main.c` suggests it's a central component, probably involved in the core VCPU lifecycle and memory access operations. I'll need to understand how this function fits into the overall KVM architecture and its interaction with the underlying host memory and the guest's virtual memory. I'm anticipating that this is where crucial checks, pre-emptive actions (like dirty bit handling), or optimizations are implemented to prevent the fault itself or to prepare for its resolution. I'll need to pay close attention to the data structures involved, such as the VCPU's state, the guest's page tables, and any relevant KVM-specific memory descriptors. Time to get my hands dirty and start reading some code! |
| 20/3 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "kvm_vcpu_pre_fault_memory"
}Results: {
"Output": "virt/kvm/kvm_main.c=4308=static int kvm_vcpu_ioctl_get_stats_fd(struct kvm_vcpu *vcpu)\n--\nvirt/kvm/kvm_main.c-4333-#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY\nvirt/kvm/kvm_main.c:4334:static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\nvirt/kvm/kvm_main.c-4335-\t\t\t\t struct kvm_pre_fault_memory *range)\n--\nvirt/kvm/kvm_main.c=4406=static long kvm_vcpu_ioctl(struct file *filp,\n--\nvirt/kvm/kvm_main.c-4638-\t\t\tbreak;\nvirt/kvm/kvm_main.c:4639:\t\tr = kvm_vcpu_pre_fault_memory(vcpu, \u0026range);\nvirt/kvm/kvm_main.c-4640-\t\t/* Pass back leftover range. */\n"
} |
| 21/3 | 2026/08/11 07:02 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7409 output: 22 thoughts: 25 Thoughts: Okay, let's dive into this `kvm_vcpu_ioctl` business, specifically the handling of `KVM_PRE_FAULT_MEMORY`. Here's my take on it: **Dissecting the KVM_PRE_FAULT_MEMORY ioctl in kvm_vcpu_ioctl** Alright, so we're looking at pre-faulting memory. That ioctl is key, `KVM_PRE_FAULT_MEMORY`. My initial thought is to consider the context: we're likely trying to optimize memory access in the guest, by bringing pages into the guest's working set *before* they're actually accessed. Smart. This suggests pre-loading pages for a reason, perhaps performance profiling detected some latency in the application. Now, within `kvm_vcpu_ioctl`, it's all about how `KVM_PRE_FAULT_MEMORY` is *handled*. What are the steps? Where does it fit into the overall ioctl structure? Is it a simple "fault this range" or are there more complex considerations, like handling page faults and the interaction with the MMU? Given its name, it’s most likely setting up the pre-fault for a given range of memory. How are we identifying the memory? Probably some sort of address range with start and end. Are we using guest physical addresses or virtual addresses within the VM? We'll need to translate as necessary to the host. I'd expect to see a check for validity of the requested range, error handling if the operation fails, and most importantly, the actual mechanism for bringing those pages into memory. Is KVM leveraging some host system calls or tricks to proactively touch the guest's memory? I'm curious: are there any flags or options associated with this ioctl? Are we looking at *just* prefaulting or is there a way to pre-populate and prevent a real page fault later? I would be interested in the mechanisms in place that prevent a race condition or conflict, and how they handle the VM’s paging structures. Also, how are we dealing with possible NUMA considerations in this context? Ultimately, my focus is on understanding the efficiency and safety of this pre-faulting process, and how it interacts with the VM's memory management, and how this fits into KVM's overall architecture. I want to see how this translates into real-world performance improvements, or if there is ever any scenario where it could introduce additional overhead. It's time to dig into the code and see how it's done. |
| 22/3 | 2026/08/11 07:02 | tool | grepper |
0mArgs:{
"Expression": "KVM_PRE_FAULT_MEMORY"
}Results: {
"Output": "Documentation/virt/kvm/api.rst=6471=See KVM_SET_USER_MEMORY_REGION2 for additional details.\nDocumentation/virt/kvm/api.rst-6472-\nDocumentation/virt/kvm/api.rst:6473:4.143 KVM_PRE_FAULT_MEMORY\nDocumentation/virt/kvm/api.rst-6474----------------------------\n--\nDocumentation/virt/kvm/api.rst=6482=Errors:\n--\nDocumentation/virt/kvm/api.rst-6506-\nDocumentation/virt/kvm/api.rst:6507:KVM_PRE_FAULT_MEMORY populates KVM's stage-2 page tables used to map memory\nDocumentation/virt/kvm/api.rst-6508-for the current vCPU state. KVM maps memory as if the vCPU generated a\n--\narch/x86/kvm/svm/sev.c=2539=static int snp_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)\n--\narch/x86/kvm/svm/sev.c-2598-\t * can be given to the guest simply by marking the RMP entry as private.\narch/x86/kvm/svm/sev.c:2599:\t * This can happen on first access and also with KVM_PRE_FAULT_MEMORY.\narch/x86/kvm/svm/sev.c-2600-\t */\n--\ninclude/uapi/linux/kvm.h=1658=struct kvm_create_guest_memfd {\n--\ninclude/uapi/linux/kvm.h-1663-\ninclude/uapi/linux/kvm.h:1664:#define KVM_PRE_FAULT_MEMORY\t_IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)\ninclude/uapi/linux/kvm.h-1665-\n--\ntools/include/uapi/linux/kvm.h=1658=struct kvm_create_guest_memfd {\n--\ntools/include/uapi/linux/kvm.h-1663-\ntools/include/uapi/linux/kvm.h:1664:#define KVM_PRE_FAULT_MEMORY\t_IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)\ntools/include/uapi/linux/kvm.h-1665-\n--\ntools/testing/selftests/kvm/pre_fault_memory_test.c=66=static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,\n--\ntools/testing/selftests/kvm/pre_fault_memory_test.c-96-\t\tprev = range.size;\ntools/testing/selftests/kvm/pre_fault_memory_test.c:97:\t\tret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, \u0026range);\ntools/testing/selftests/kvm/pre_fault_memory_test.c-98-\t\tsave_errno = errno;\n--\ntools/testing/selftests/kvm/pre_fault_memory_test.c-157-\tif (!expected_left)\ntools/testing/selftests/kvm/pre_fault_memory_test.c:158:\t\tTEST_ASSERT_VM_VCPU_IOCTL(!ret, KVM_PRE_FAULT_MEMORY, ret, vcpu-\u003evm);\ntools/testing/selftests/kvm/pre_fault_memory_test.c-159-\telse\ntools/testing/selftests/kvm/pre_fault_memory_test.c-160-\t\tTEST_ASSERT_VM_VCPU_IOCTL(ret \u0026\u0026 save_errno == ENOENT,\ntools/testing/selftests/kvm/pre_fault_memory_test.c:161:\t\t\t\t\t KVM_PRE_FAULT_MEMORY, ret, vcpu-\u003evm);\ntools/testing/selftests/kvm/pre_fault_memory_test.c-162-}\n--\nvirt/kvm/kvm_main.c=4406=static long kvm_vcpu_ioctl(struct file *filp,\n--\nvirt/kvm/kvm_main.c-4632-#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY\nvirt/kvm/kvm_main.c:4633:\tcase KVM_PRE_FAULT_MEMORY: {\nvirt/kvm/kvm_main.c-4634-\t\tstruct kvm_pre_fault_memory range;\n"
} |
| 23/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9164 output: 40 thoughts: 35 Thoughts: Here's my analysis of the provided snippet, framed as my own thought process: **Diving into KVM's Core** Okay, let's get down to brass tacks. I need to understand this KVM interaction, specifically how the virtual CPU is managed. The first place I'm going to look is the `kvm_vcpu_ioctl` function. I remember that's the primary entry point for control operations on the virtual CPU. Now, the hint also mentions the file and line, which should expedite things; it's going to be in `virt/kvm/kvm_main.c` around line 4633. Knowing the file location is key - it places this functionality within the broader context of KVM's core architecture. With the line number, I can start right where I need to be. |
| 24/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "virt/kvm/kvm_main.c",
"FirstLine": 4625,
"LineCount": 30
}Results: {
"Contents": "4625:\t\t\tr = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu);\n4626:\t\t\tbreak;\n4627:\t\t}\n4628:\t\tcase KVM_GET_STATS_FD: {\n4629:\t\t\tr = kvm_vcpu_ioctl_get_stats_fd(vcpu);\n4630:\t\t\tbreak;\n4631:\t\t}\n4632:\t#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY\n4633:\t\tcase KVM_PRE_FAULT_MEMORY: {\n4634:\t\t\tstruct kvm_pre_fault_memory range;\n4635:\t\n4636:\t\t\tr = -EFAULT;\n4637:\t\t\tif (copy_from_user(\u0026range, argp, sizeof(range)))\n4638:\t\t\t\tbreak;\n4639:\t\t\tr = kvm_vcpu_pre_fault_memory(vcpu, \u0026range);\n4640:\t\t\t/* Pass back leftover range. */\n4641:\t\t\tif (copy_to_user(argp, \u0026range, sizeof(range)))\n4642:\t\t\t\tr = -EFAULT;\n4643:\t\t\tbreak;\n4644:\t\t}\n4645:\t#endif\n4646:\t\tdefault:\n4647:\t\t\tr = kvm_arch_vcpu_ioctl(filp, ioctl, arg);\n4648:\t\t}\n4649:\tout:\n4650:\t\tmutex_unlock(\u0026vcpu-\u003emutex);\n4651:\t\tkfree(fpu);\n4652:\t\tkfree(kvm_sregs);\n4653:\t\treturn r;\n4654:\t}\n"
} |
| 25/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9872 output: 40 thoughts: 100 Thoughts: **Analyzing the KVM Pre-Fault Memory Process** Okay, so I'm looking at this `KVM_PRE_FAULT_MEMORY` operation, and it seems like the sequence of events is pretty straightforward at first glance. It copies a memory `range` from userspace, calls `kvm_vcpu_pre_fault_memory` with that `range`, and then copies the potentially modified `range` back to userspace. But wait a minute... does `kvm_vcpu_pre_fault_memory` actually *modify* that `range`? That's the crucial detail I need to nail down. If it does, and how it is modified, that will change everything about how I see this function! Okay, time to dive into the source code to get the definitive answer. I'll need to check the implementation of `kvm_vcpu_pre_fault_memory`, and from my experience, that function is probably in `virt/kvm/kvm_main.c`. Let's see what's actually happening to this `range` within that function. I need to understand its side effects if I'm going to understand this function completely. |
| 26/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "virt/kvm/kvm_main.c",
"FirstLine": 4334,
"LineCount": 40
}Results: {
"Contents": "4334:\tstatic int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n4335:\t\t\t\t\t struct kvm_pre_fault_memory *range)\n4336:\t{\n4337:\t\tint idx;\n4338:\t\tlong r;\n4339:\t\tu64 full_size;\n4340:\t\n4341:\t\tif (range-\u003eflags)\n4342:\t\t\treturn -EINVAL;\n4343:\t\n4344:\t\tif (!PAGE_ALIGNED(range-\u003egpa) ||\n4345:\t\t !PAGE_ALIGNED(range-\u003esize) ||\n4346:\t\t range-\u003egpa + range-\u003esize \u003c= range-\u003egpa)\n4347:\t\t\treturn -EINVAL;\n4348:\t\n4349:\t\tvcpu_load(vcpu);\n4350:\t\tidx = srcu_read_lock(\u0026vcpu-\u003ekvm-\u003esrcu);\n4351:\t\n4352:\t\tfull_size = range-\u003esize;\n4353:\t\tdo {\n4354:\t\t\tif (signal_pending(current)) {\n4355:\t\t\t\tr = -EINTR;\n4356:\t\t\t\tbreak;\n4357:\t\t\t}\n4358:\t\n4359:\t\t\tr = kvm_arch_vcpu_pre_fault_memory(vcpu, range);\n4360:\t\t\tif (WARN_ON_ONCE(r == 0 || r == -EIO))\n4361:\t\t\t\tbreak;\n4362:\t\n4363:\t\t\tif (r \u003c 0)\n4364:\t\t\t\tbreak;\n4365:\t\n4366:\t\t\trange-\u003esize -= r;\n4367:\t\t\trange-\u003egpa += r;\n4368:\t\t\tcond_resched();\n4369:\t\t} while (range-\u003esize);\n4370:\t\n4371:\t\tsrcu_read_unlock(\u0026vcpu-\u003ekvm-\u003esrcu, idx);\n4372:\t\tvcpu_put(vcpu);\n4373:\t\n"
} |
| 27/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10821 output: 24 thoughts: 113 Thoughts: **Analyzing Potential Memory Leaks and Padding in `kvm_pre_fault_memory`** Okay, so I'm looking at this code where `range` is being manipulated. The size and GPA are adjusted (`range->size -= r; range->gpa += r;`) and then copied back to the user space. My initial thought is to quickly scan for a possible uninitialized memory leak. However, I remember that the `range` variable is *fully* initialized right at the beginning by the `copy_from_user` call. So, that's good. But, and this is where I need to be careful, what about padding? I need to consider if there might be any padding within the `struct kvm_pre_fault_memory` structure. This could lead to issues if not handled properly during the copy operations. To ensure this is handled safely, I should immediately reference the definition of `struct kvm_pre_fault_memory` in `include/uapi/linux/kvm.h`. That's where the definitive answer will be. |
| 28/3 | 2026/08/11 07:03 | tool | grepper |
0mArgs:{
"Expression": "struct kvm_pre_fault_memory \\{"
}Results: {
"Output": "Documentation/virt/kvm/api.rst=6482=Errors:\n--\nDocumentation/virt/kvm/api.rst-6497-\nDocumentation/virt/kvm/api.rst:6498: struct kvm_pre_fault_memory {\nDocumentation/virt/kvm/api.rst-6499-\t/* in/out */\n--\ninclude/uapi/linux/kvm.h=1658=struct kvm_create_guest_memfd {\n--\ninclude/uapi/linux/kvm.h-1665-\ninclude/uapi/linux/kvm.h:1666:struct kvm_pre_fault_memory {\ninclude/uapi/linux/kvm.h-1667-\t__u64 gpa;\n--\ntools/include/uapi/linux/kvm.h=1658=struct kvm_create_guest_memfd {\n--\ntools/include/uapi/linux/kvm.h-1665-\ntools/include/uapi/linux/kvm.h:1666:struct kvm_pre_fault_memory {\ntools/include/uapi/linux/kvm.h-1667-\t__u64 gpa;\n"
} |
| 29/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11505 output: 40 thoughts: 25 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into KVM's Memory Region Definitions** Okay, time to get my hands dirty. I'm going to start digging into the low-level details of KVM's memory region management. Specifically, I need to focus on the structures that define how guest physical memory is mapped to host virtual memory, so I'll be heading to `include/uapi/linux/kvm.h`. I'm guessing around line 1666 should be a good starting point to find the relevant structs. This is where I expect to find the meat of the memory map configuration. I'm looking for things like the `kvm_userspace_memory_region` structure and its related fields. I want to refresh my understanding of how user-space interacts with the KVM core to set up memory regions, the implications of different flags and attributes, and any alignment constraints. Hopefully, this will give me the information I need. |
| 30/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "include/uapi/linux/kvm.h",
"FirstLine": 1660,
"LineCount": 20
}Results: {
"Contents": "1660:\t\t__u64 flags;\n1661:\t\t__u64 reserved[6];\n1662:\t};\n1663:\t\n1664:\t#define KVM_PRE_FAULT_MEMORY\t_IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)\n1665:\t\n1666:\tstruct kvm_pre_fault_memory {\n1667:\t\t__u64 gpa;\n1668:\t\t__u64 size;\n1669:\t\t__u64 flags;\n1670:\t\t__u64 padding[5];\n1671:\t};\n1672:\t\n1673:\t#endif /* __LINUX_KVM_H */\n"
} |
| 31/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11996 output: 40 thoughts: 666 Thoughts: **Analyzing `kvm_pre_fault_memory` and Potential Information Leaks** Okay, so I'm looking at this `struct kvm_pre_fault_memory` and noticing that it has some padding. My initial thought was, if we copy this struct from user space using `copy_from_user` into a `range` variable, then modify certain fields like `range->size` and `range->gpa`, and then `copy_to_user` it back, there shouldn't be a vulnerability. The padding fields just echo back whatever the user sent. There's no uninitialized kernel memory being leaked here, because the kernel is merely reflecting the user's input. But, hold on. What if `copy_from_user` fails? Then the copy-back doesn't happen. What if `copy_from_user` *succeeds* but the kernel somehow didn't initialize `range` first? Ah, but wait, the entire `range` struct is initialized by `copy_from_user`, so that's a moot point. Let me revisit the core logic within `kvm_arch_vcpu_pre_fault_memory`. It looks like it initializes a `kvm_gstage_mapping` struct called `out_map` to all zeros. It then calls `kvm_riscv_mmu_map` to populate it. I see that `kvm_riscv_mmu_map` is the crucial part that likely populates `out_map`. That's the function I need to investigate in `arch/riscv/kvm/mmu.c`. |
| 32/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "arch/riscv/kvm/mmu.c",
"FirstLine": 730,
"LineCount": 25
}Results: {
"Contents": " 730:\t\tif (!logging \u0026\u0026 !is_hugetlb \u0026\u0026 vma_pagesize == PAGE_SIZE)\n 731:\t\t\tvma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, \u0026hfn, \u0026gpa);\n 732:\t\n 733:\t\tif (writable) {\n 734:\t\t\tmark_page_dirty_in_slot(kvm, memslot, gfn);\n 735:\t\t\tret = kvm_riscv_gstage_map_page(\u0026gstage, pcache, gpa, hfn \u003c\u003c PAGE_SHIFT,\n 736:\t\t\t\t\t\t\tvma_pagesize, false, true, out_map);\n 737:\t\t} else {\n 738:\t\t\tret = kvm_riscv_gstage_map_page(\u0026gstage, pcache, gpa, hfn \u003c\u003c PAGE_SHIFT,\n 739:\t\t\t\t\t\t\tvma_pagesize, true, true, out_map);\n 740:\t\t}\n 741:\t\n 742:\t\tif (ret)\n 743:\t\t\tkvm_err(\"Failed to map in G-stage\\n\");\n 744:\t\n 745:\tout_unlock:\n 746:\t\tkvm_release_faultin_page(kvm, page, ret \u0026\u0026 ret != -EEXIST, writable);\n 747:\t\twrite_unlock(\u0026kvm-\u003emmu_lock);\n 748:\t\treturn ret;\n 749:\t}\n 750:\t\n 751:\tlong kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n 752:\t\t\t\t\t struct kvm_pre_fault_memory *range)\n 753:\t{\n 754:\t\tstruct kvm_gstage_mapping out_map = { 0 };\n"
} |
| 33/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13528 output: 40 thoughts: 33 Thoughts: Here's a summary of my thought process: **Diving into KVM for RISC-V: gstage and Page Mapping** Alright, let's get down to brass tacks. I need to understand how KVM interacts with the RISC-V architecture at a fundamental level, particularly regarding memory management within the guest environment. The function `kvm_riscv_gstage_map_page` in `arch/riscv/kvm/gstage.c` seems like a critical piece of that puzzle. It's time to dissect its inner workings. I suspect this function is where the magic happens, where the guest's virtual addresses are translated and mapped to the host's physical memory, potentially using the gstage mechanisms. I'm especially interested in how it handles page table walks, the interaction with RISC-V's page table structures, and any specific optimizations for the architecture. Time to dig in and see how the KVM machinery translates a guest virtual address into a physical address on the host. This likely involves some clever manipulations and considerations for performance, virtual memory protection, and how it all works under the hood. Let's see what's actually going on. |
| 34/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "arch/riscv/kvm/gstage.c",
"FirstLine": 270,
"LineCount": 25
}Results: {
"Contents": " 270:\t\t\t *\n 271:\t\t\t * It is better to recover the huge page mapping in the ioctl context when\n 272:\t\t\t * disabling dirty logging.\n 273:\t\t\t *\n 274:\t\t\t * 3) ptep_level == out_map-\u003elevel\n 275:\t\t\t * We already have the ptep, just update the pte prot if the pfn not change.\n 276:\t\t\t * There is no need to invoke `kvm_riscv_gstage_set_pte` again.\n 277:\t\t\t */\n 278:\t\t\tif (ptep_level \u003e out_map-\u003elevel) {\n 279:\t\t\t\tkvm_riscv_gstage_split_huge(gstage, pcache, gpa,\n 280:\t\t\t\t\t\t\t out_map-\u003elevel, true);\n 281:\t\t\t} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {\n 282:\t\t\t\tkvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);\n 283:\t\t\t\tout_map-\u003eaddr = ALIGN_DOWN(gpa, page_size);\n 284:\t\t\t\tout_map-\u003elevel = ptep_level;\n 285:\t\t\t\tout_map-\u003epte = ptep_get(ptep);\n 286:\t\t\t\treturn 0;\n 287:\t\t\t}\n 288:\t\t}\n 289:\t\n 290:\t\tout_map-\u003epte = pfn_pte(PFN_DOWN(hpa), prot);\n 291:\t\tout_map-\u003epte = pte_mkdirty(out_map-\u003epte);\n 292:\t\n 293:\t\treturn kvm_riscv_gstage_set_pte(gstage, pcache, out_map);\n 294:\t}\n"
} |
| 35/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14352 output: 26 thoughts: 75 Thoughts: Here's my summary, as the expert: **Investigating the `out_map` Parameter in KVM-RISCV G-Stage Mapping** Okay, so I see `out_map` is being fed into `kvm_riscv_gstage_map_page`. That's interesting. The way the code's structured, it looks like `out_map` is acting as both an input *and* an output parameter within that function. I need to clarify what's actually happening here. Given my experience, that's not necessarily a bad thing, but I want to make sure I grasp the intent fully. Let me quickly examine the function signature of `kvm_riscv_gstage_map_page` to verify how it handles `out_map`. That'll be key to figuring out how this memory mapping is functioning. |
| 36/3 | 2026/08/11 07:03 | tool | grepper |
0mArgs:{
"Expression": "kvm_riscv_gstage_map_page"
}Results: {
"Output": "arch/riscv/include/asm/kvm_gstage.h=57=bool kvm_riscv_gstage_try_update_pte(struct kvm_gstage *gstage, u32 level,\n--\narch/riscv/include/asm/kvm_gstage.h-60-\narch/riscv/include/asm/kvm_gstage.h:61:int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,\narch/riscv/include/asm/kvm_gstage.h-62-\t\t\t struct kvm_mmu_memory_cache *pcache,\n--\narch/riscv/kvm/gstage.c=186=static void kvm_riscv_gstage_update_pte_prot(struct kvm_gstage *gstage, u32 level,\n--\narch/riscv/kvm/gstage.c-206-\narch/riscv/kvm/gstage.c:207:int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,\narch/riscv/kvm/gstage.c-208-\t\t\t struct kvm_mmu_memory_cache *pcache,\n--\narch/riscv/kvm/mmu.c=623=int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n--\narch/riscv/kvm/mmu.c-734-\t\tmark_page_dirty_in_slot(kvm, memslot, gfn);\narch/riscv/kvm/mmu.c:735:\t\tret = kvm_riscv_gstage_map_page(\u0026gstage, pcache, gpa, hfn \u003c\u003c PAGE_SHIFT,\narch/riscv/kvm/mmu.c-736-\t\t\t\t\t\tvma_pagesize, false, true, out_map);\narch/riscv/kvm/mmu.c-737-\t} else {\narch/riscv/kvm/mmu.c:738:\t\tret = kvm_riscv_gstage_map_page(\u0026gstage, pcache, gpa, hfn \u003c\u003c PAGE_SHIFT,\narch/riscv/kvm/mmu.c-739-\t\t\t\t\t\tvma_pagesize, true, true, out_map);\n"
} |
| 37/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15234 output: 40 thoughts: 40 Thoughts: Okay, let's dive into this. I'm going to pull up `kvm_riscv_gstage_map_page` in `arch/riscv/kvm/gstage.c`, specifically starting at line 207. I need to refresh my understanding of the gstage mapping process within the KVM/RISC-V architecture. I'm interested in how this particular function is handling the mapping of a page within the guest stage. Let's see what's happening and how it fits into the larger context of virtual memory translation and the guest's view of the physical address space. I'm expecting to find details about page table walks, permission checks, and the interaction with the host's physical memory. I'll be looking for any RISC-V specific intricacies. |
| 38/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "arch/riscv/kvm/gstage.c",
"FirstLine": 207,
"LineCount": 40
}Results: {
"Contents": " 207:\tint kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,\n 208:\t\t\t\t struct kvm_mmu_memory_cache *pcache,\n 209:\t\t\t\t gpa_t gpa, phys_addr_t hpa, unsigned long page_size,\n 210:\t\t\t\t bool page_rdonly, bool page_exec,\n 211:\t\t\t\t struct kvm_gstage_mapping *out_map)\n 212:\t{\n 213:\t\tbool found_leaf;\n 214:\t\tu32 ptep_level;\n 215:\t\tpgprot_t prot;\n 216:\t\tpte_t *ptep;\n 217:\t\tint ret;\n 218:\t\n 219:\t\tout_map-\u003eaddr = gpa;\n 220:\t\tout_map-\u003elevel = 0;\n 221:\t\n 222:\t\tret = gstage_page_size_to_level(gstage, page_size, \u0026out_map-\u003elevel);\n 223:\t\tif (ret)\n 224:\t\t\treturn ret;\n 225:\t\n 226:\t\t/*\n 227:\t\t * A RISC-V implementation can choose to either:\n 228:\t\t * 1) Update 'A' and 'D' PTE bits in hardware\n 229:\t\t * 2) Generate page fault when 'A' and/or 'D' bits are not set\n 230:\t\t * PTE so that software can update these bits.\n 231:\t\t *\n 232:\t\t * We support both options mentioned above. To achieve this, we\n 233:\t\t * always set 'A' and 'D' PTE bits at time of creating G-stage\n 234:\t\t * mapping. To support KVM dirty page logging with both options\n 235:\t\t * mentioned above, we will write-protect G-stage PTEs to track\n 236:\t\t * dirty pages.\n 237:\t\t */\n 238:\t\n 239:\t\tif (page_exec) {\n 240:\t\t\tif (page_rdonly)\n 241:\t\t\t\tprot = PAGE_READ_EXEC;\n 242:\t\t\telse\n 243:\t\t\t\tprot = PAGE_WRITE_EXEC;\n 244:\t\t} else {\n 245:\t\t\tif (page_rdonly)\n 246:\t\t\t\tprot = PAGE_READ;\n"
} |
| 39/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16124 output: 40 thoughts: 69 Thoughts: Here's my understanding of the `kvm_riscv_gstage_map_page` function, focusing on the mapping setup: **My Perspective on the Mapping Process** Okay, so I see that we're initially setting up the address mapping with `out_map->addr = gpa;` and `out_map->level = 0;`. This suggests we're getting the ground physical address (GPA) directly associated with a map entry, and starting at the very base level of the page table hierarchy. I'd expect this level to be a bit coarse at this point, before any more specific configuration. Then, the code calls `gstage_page_size_to_level`, and *that's* where the crucial part happens. This implies this function is responsible for determining the correct page table level to use based on the page size. I'd bet this function takes into consideration hardware page table support (e.g., specific page size capabilities of the RISC-V architecture), and potentially also any guest-configured page size overrides or constraints. In other words, it's making the decision on *how* granular the mapping should be, and sets the appropriate `out_map->level`. Finally, after all of that mapping setup, the function concludes with all the necessary information ready to go. I see the final configuration is complete at this point. |
| 40/3 | 2026/08/11 07:03 | tool | read-file |
0mArgs:{
"File": "arch/riscv/kvm/gstage.c",
"FirstLine": 247,
"LineCount": 50
}Results: {
"Contents": " 247:\t\t\telse\n 248:\t\t\t\tprot = PAGE_WRITE;\n 249:\t\t}\n 250:\t\n 251:\t\tfound_leaf = kvm_riscv_gstage_get_leaf(gstage, gpa, \u0026ptep, \u0026ptep_level);\n 252:\t\tif (found_leaf) {\n 253:\t\t\t/*\n 254:\t\t\t * ptep_level is the current gstage mapping level of addr, out_map-\u003elevel\n 255:\t\t\t * is the required mapping level during fault handling.\n 256:\t\t\t *\n 257:\t\t\t * 1) ptep_level \u003e out_map-\u003elevel\n 258:\t\t\t * This happens when dirty logging is enabled and huge pages are used.\n 259:\t\t\t * KVM must track the pages at 4K level, and split the huge mapping\n 260:\t\t\t * into 4K mappings.\n 261:\t\t\t *\n 262:\t\t\t * 2) ptep_level \u003c out_map-\u003elevel\n 263:\t\t\t * This happens when dirty logging is disabled and huge pages are used.\n 264:\t\t\t * The gstage is split into 4K mappings, but the out_map level is now\n 265:\t\t\t * back to the huge page level. Ignore the out_map level this time, and\n 266:\t\t\t * just update the pte prot here. Otherwise, we would fall back to mapping\n 267:\t\t\t * the gstage at huge page level in `kvm_riscv_gstage_set_pte`, with the\n 268:\t\t\t * overhead of freeing the page tables(not support now), which would slow\n 269:\t\t\t * down the vCPUs' performance.\n 270:\t\t\t *\n 271:\t\t\t * It is better to recover the huge page mapping in the ioctl context when\n 272:\t\t\t * disabling dirty logging.\n 273:\t\t\t *\n 274:\t\t\t * 3) ptep_level == out_map-\u003elevel\n 275:\t\t\t * We already have the ptep, just update the pte prot if the pfn not change.\n 276:\t\t\t * There is no need to invoke `kvm_riscv_gstage_set_pte` again.\n 277:\t\t\t */\n 278:\t\t\tif (ptep_level \u003e out_map-\u003elevel) {\n 279:\t\t\t\tkvm_riscv_gstage_split_huge(gstage, pcache, gpa,\n 280:\t\t\t\t\t\t\t out_map-\u003elevel, true);\n 281:\t\t\t} else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) {\n 282:\t\t\t\tkvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot);\n 283:\t\t\t\tout_map-\u003eaddr = ALIGN_DOWN(gpa, page_size);\n 284:\t\t\t\tout_map-\u003elevel = ptep_level;\n 285:\t\t\t\tout_map-\u003epte = ptep_get(ptep);\n 286:\t\t\t\treturn 0;\n 287:\t\t\t}\n 288:\t\t}\n 289:\t\n 290:\t\tout_map-\u003epte = pfn_pte(PFN_DOWN(hpa), prot);\n 291:\t\tout_map-\u003epte = pte_mkdirty(out_map-\u003epte);\n 292:\t\n 293:\t\treturn kvm_riscv_gstage_set_pte(gstage, pcache, out_map);\n 294:\t}\n 295:\t\n 296:\tstatic inline unsigned long make_child_pte(unsigned long huge_pte, int index,\n"
} |
| 41/3 | 2026/08/11 07:03 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17487 output: 23 thoughts: 917 Thoughts: **Analyzing Potential Uninitialized Memory Issues in RISC-V KVM PRE_FAULT_MEMORY Implementation**
Okay, so I'm stepping through this `kvm_arch_vcpu_pre_fault_memory` function, and my initial thought is, "Are there any vulnerabilities here concerning uninitialized memory being exposed to user space?" I see `out_map->addr`, `out_map->level`, and `out_map->pte` being set, which immediately triggers the question, "Is this potentially leaking kernel information?"
But wait. `out_map` is a local variable within `kvm_arch_vcpu_pre_fault_memory`. It's used internally to calculate `map_size` and `end`. The relevant code snippet makes that quite clear. It's not copied back to user space directly. The return value, which is a length calculation using those values, *does* modify fields within the `range` struct, specifically `size` and `gpa` in `kvm_vcpu_pre_fault_memory`, but it's fundamentally just a length. The `range` struct itself is handled by `copy_from_user` in the caller.
So, I'm thinking, "No, it doesn't look like there's any direct uninitialized memory exposure from `out_map` to user space." The `range` struct comes from user space, and while its `size` and `gpa` members are modified, the padding is untouched, echoing back what the user initially supplied.
I need to be thorough, though. I ask myself, "Is there another location where uninitialized memory could be in play?" I consider `out_map` again. It's initialized to `{ 0 }`, and `kvm_riscv_mmu_map` populates it. Even if that function didn't populate every field, which seems unlikely, it's initialized to zero, and the return value is the key factor. The function's return value is used to update `range->size` and `range->gpa`, but that's just a length, derived from internally calculated values.
Now, let's widen the scope. I look at all the changed files: `arch/riscv/kvm/Kconfig`, `arch/riscv/kvm/gstage.c`, `arch/riscv/kvm/mmu.c`, `arch/riscv/kvm/vm.c`, and the relevant selftests. The changes are all quite targeted, focusing on implementing `kvm_arch_vcpu_pre_fault_memory` specifically for RISC-V. There aren't any new structs being introduced that are *copied* to user space. The `KVM_PRE_FAULT_MEMORY` ioctl already handles the user space copy for the existing `range` struct. The `range` struct is fully initialized by the `copy_from_user` call.
Okay, let's step back and summarize. `out_map` is initialized to zero. The `range` struct is copied *from* user space, not the other way around. No new data structures are introduced that are copied to user space. No complex allocations are performed that would potentially expose uninitialized memory.
Therefore, my assessment is that KMSAN (Kernel Memory Sanitizer) isn't necessary here to address uninitialized memory reads. KASAN (Kernel Address Sanitizer) should be sufficient to catch any out-of-bounds or use-after-free issues, though I'm not seeing any obvious ones at this stage. I'll need to double-check the `kvm_riscv_gstage_mapping` struct just to be absolutely sure.
|
| 42/3 | 2026/08/11 07:04 | tool | grepper |
0mArgs:{
"Expression": "struct kvm_gstage_mapping \\{"
}Results: {
"Output": "arch/riscv/include/asm/kvm_gstage.h=12=struct kvm_gstage {\n--\narch/riscv/include/asm/kvm_gstage.h-20-\narch/riscv/include/asm/kvm_gstage.h:21:struct kvm_gstage_mapping {\narch/riscv/include/asm/kvm_gstage.h-22-\tgpa_t addr;\n"
} |
| 43/3 | 2026/08/11 07:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19342 output: 43 thoughts: 28 Thoughts: Okay, let's dive into this. Here's my take on those thoughts, as though they were my own: **Analyzing `arch/riscv/include/asm/kvm_gstage.h`** Alright, I'm thinking about digging into the RISC-V KVM implementation, specifically the `kvm_gstage.h` header file. It's often the place to find crucial definitions related to the guest stage, so that's where I'm focusing. Line 21, in particular, seems like a reasonable starting point. I'm hoping to get a quick overview of how the KVM handles guest state, address translation, or perhaps some fundamental data structures related to the g-stage. Depending on the sophistication of the RISC-V implementation, it could be a simple structure, a complex set of macros, or perhaps even a novel approach. I'll need to examine what's declared there to get a better grasp of the overall design and what kind of details are important. |
| 44/3 | 2026/08/11 07:04 | tool | read-file |
0mArgs:{
"File": "arch/riscv/include/asm/kvm_gstage.h",
"FirstLine": 20,
"LineCount": 10
}Results: {
"Contents": " 20:\t\n 21:\tstruct kvm_gstage_mapping {\n 22:\t\tgpa_t addr;\n 23:\t\tpte_t pte;\n 24:\t\tu32 level;\n 25:\t};\n 26:\t\n 27:\t#ifdef CONFIG_64BIT\n 28:\t#define kvm_riscv_gstage_index_bits\t9\n 29:\t#else\n"
} |
| 45/3 | 2026/08/11 07:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19754 output: 261 thoughts: 749 Thoughts: **My Assessment of the Patch's Memory Safety**
Okay, let's break this down. My initial concern was, as always, uninitialized memory and potential information leaks, particularly given the interaction with user space. I've focused on two key data structures: `kvm_gstage_mapping` and `kvm_pre_fault_memory`.
First, the `kvm_gstage_mapping` struct. This is used internally in the RISC-V MMU code. I see that it's initialized with `{ 0 }` within `kvm_arch_vcpu_pre_fault_memory`. So, `addr`, `pte`, and `level` are all zeroed out at the start. Then, `kvm_riscv_mmu_map` gets a chance to modify these, and even if it didn't, we are starting from a clean slate. No risk there.
Next, I examined `struct kvm_pre_fault_memory`. This is where the user space interaction occurs, through the `KVM_PRE_FAULT_MEMORY` ioctl in `kvm_main.c`. Here's the critical bit: the `range` variable of this type is fully populated by `copy_from_user` from the user-provided data. The code then modifies `range.size` and `range.gpa` inside `kvm_vcpu_pre_fault_memory`. And finally, the entire `range` struct, including the `padding` fields, is copied back to user space using `copy_to_user`. The padding fields are simply echoing the user's input, which is a common and safe pattern for ioctls. There's no kernel memory leak here because the contents of the padding originate from the user.
Looking at the overall context, the patch simply enables the existing `KVM_CAP_PRE_FAULT_MEMORY` feature for RISC-V. It doesn't introduce any new allocation patterns or data structures that would raise alarm bells. The patch is relatively simple; it is just wiring up an existing generic KVM feature.
Based on this analysis, I'm confident that this patch doesn't introduce any new risks related to uninitialized memory, information leaks, or memory corruption. The existing KASAN checks are sufficient to handle any unforeseen issues. So, I will mark this as `NeedsKMSAN=false`.
|
| 46/3 | 2026/08/11 07:04 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch implements the `KVM_CAP_PRE_FAULT_MEMORY` capability for RISC-V by adding `kvm_arch_vcpu_pre_fault_memory` and wiring it up in the MMU. The only data structure involved in user space communication is `struct kvm_pre_fault_memory`, which is handled by generic KVM code (`virt/kvm/kvm_main.c`). The generic code fully initializes the struct via `copy_from_user` before modifying its `size` and `gpa` fields and copying it back to user space. Any padding fields simply echo back the user-provided values, preventing any kernel memory info-leaks. The local variable `out_map` of type `struct kvm_gstage_mapping` is explicitly zero-initialized (`= { 0 }`) before being passed to `kvm_riscv_mmu_map`. There are no new complex allocations, uninitialized variables, or info-leaks introduced by this patch. Standard KASAN is sufficient to catch any potential memory corruption or out-of-bounds accesses.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch implements the `KVM_CAP_PRE_FAULT_MEMORY` capability for RISC-V by adding `kvm_arch_vcpu_pre_fault_memory` and wiring it up in the MMU. The only data structure involved in user space communication is `struct kvm_pre_fault_memory`, which is handled by generic KVM code (`virt/kvm/kvm_main.c`). The generic code fully initializes the struct via `copy_from_user` before modifying its `size` and `gpa` fields and copying it back to user space. Any padding fields simply echo back the user-provided values, preventing any kernel memory info-leaks. The local variable `out_map` of type `struct kvm_gstage_mapping` is explicitly zero-initialized (`= { 0 }`) before being passed to `kvm_riscv_mmu_map`. There are no new complex allocations, uninitialized variables, or info-leaks introduced by this patch. Standard KASAN is sufficient to catch any potential memory corruption or out-of-bounds accesses.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|