| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/25 02:10 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"PER_VMA_LOCK",
"MMU_GATHER_RCU_TABLE_FREE"
],
"FocusSymbols": [
"access_remote_vm_fast",
"__access_remote_vm",
"folio_walk_start",
"copy_folio_pages",
"vma_permits_fast_access"
],
"Reasoning": "The patch introduces a lockless fast path for remote memory access (`__access_remote_vm`), which is reachable via syscalls like `process_vm_readv` and `ptrace`. The fast path relies on per-VMA locks and RCU-freed page tables, making it highly functional and worth fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/06/25 02:10 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 96017442623ea4e6ed50d9b6003bfbe0f4c94389\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Jun 25 02:10:13 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h\nindex ef5b507de34e2e..cee710f64658aa 100644\n--- a/arch/x86/include/asm/mmu_context.h\n+++ b/arch/x86/include/asm/mmu_context.h\n@@ -100,18 +100,18 @@ static inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm)\n static inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm)\n {\n \tmm-\u003econtext.lam_cr3_mask = oldmm-\u003econtext.lam_cr3_mask;\n-\tmm-\u003econtext.untag_mask = oldmm-\u003econtext.untag_mask;\n+\tWRITE_ONCE(mm-\u003econtext.untag_mask, READ_ONCE(oldmm-\u003econtext.untag_mask));\n }\n \n #define mm_untag_mask mm_untag_mask\n static inline unsigned long mm_untag_mask(struct mm_struct *mm)\n {\n-\treturn mm-\u003econtext.untag_mask;\n+\treturn READ_ONCE(mm-\u003econtext.untag_mask);\n }\n \n static inline void mm_reset_untag_mask(struct mm_struct *mm)\n {\n-\tmm-\u003econtext.untag_mask = -1UL;\n+\tWRITE_ONCE(mm-\u003econtext.untag_mask, -1UL);\n }\n \n #define arch_pgtable_dma_compat arch_pgtable_dma_compat\ndiff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h\nindex 20de34cc9aa6e7..933b0b8b4d6047 100644\n--- a/arch/x86/include/asm/uaccess_64.h\n+++ b/arch/x86/include/asm/uaccess_64.h\n@@ -39,11 +39,23 @@ static inline unsigned long __untagged_addr(unsigned long addr)\n \t(__force __typeof__(addr))__untagged_addr(__addr);\t\t\\\n })\n \n+/* Strip the tag bits from a remote mm's address; usable without the mmap lock. */\n+static inline unsigned long __untagged_addr_remote_unlocked(struct mm_struct *mm,\n+\t\t\t\t\t\t\t unsigned long addr)\n+{\n+\treturn addr \u0026 READ_ONCE(mm-\u003econtext.untag_mask);\n+}\n+\n+#define untagged_addr_remote_unlocked(mm, addr)\t({\t\t\t\\\n+\tunsigned long __addr = (__force unsigned long)(addr);\t\t\\\n+\t(__force __typeof__(addr))__untagged_addr_remote_unlocked(mm, __addr); \\\n+})\n+\n static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,\n \t\t\t\t\t\t unsigned long addr)\n {\n \tmmap_assert_locked(mm);\n-\treturn addr \u0026 (mm)-\u003econtext.untag_mask;\n+\treturn __untagged_addr_remote_unlocked(mm, addr);\n }\n \n #define untagged_addr_remote(mm, addr)\t({\t\t\t\t\\\ndiff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c\nindex d44afbe005bb51..55096136de5313 100644\n--- a/arch/x86/kernel/process_64.c\n+++ b/arch/x86/kernel/process_64.c\n@@ -814,7 +814,7 @@ static void enable_lam_func(void *__mm)\n static void mm_enable_lam(struct mm_struct *mm)\n {\n \tmm-\u003econtext.lam_cr3_mask = X86_CR3_LAM_U57;\n-\tmm-\u003econtext.untag_mask = ~GENMASK(62, 57);\n+\tWRITE_ONCE(mm-\u003econtext.untag_mask, ~GENMASK(62, 57));\n \n \t/*\n \t * Even though the process must still be single-threaded at this\ndiff --git a/include/linux/pagewalk.h b/include/linux/pagewalk.h\nindex b41d7265c01bc2..d0387470d7322b 100644\n--- a/include/linux/pagewalk.h\n+++ b/include/linux/pagewalk.h\n@@ -150,6 +150,13 @@ typedef int __bitwise folio_walk_flags_t;\n \n /* Walk shared zeropages (small + huge) as well. */\n #define FW_ZEROPAGE\t\t\t((__force folio_walk_flags_t)BIT(0))\n+/*\n+ * The caller holds the per-VMA lock instead of the mmap lock, with interrupts\n+ * disabled across the walk (until folio_walk_end()) to serialize against page\n+ * table freeing, the same way gup_fast does. Only valid with RCU-freed page\n+ * tables (CONFIG_MMU_GATHER_RCU_TABLE_FREE) and not for hugetlb.\n+ */\n+#define FW_VMA_LOCKED\t\t\t((__force folio_walk_flags_t)BIT(1))\n \n enum folio_walk_level {\n \tFW_LEVEL_PTE,\ndiff --git a/include/linux/uaccess.h b/include/linux/uaccess.h\nindex 8a264662b242c8..c8c83372c9d878 100644\n--- a/include/linux/uaccess.h\n+++ b/include/linux/uaccess.h\n@@ -34,6 +34,17 @@\n })\n #endif\n \n+/*\n+ * Like untagged_addr_remote(), but for callers that stabilize @mm by other\n+ * means (e.g. a per-VMA lock) and must not assert the mmap lock.\n+ */\n+#ifndef untagged_addr_remote_unlocked\n+#define untagged_addr_remote_unlocked(mm, addr)\t({\t\\\n+\t(void)(mm);\t\t\t\t\t\\\n+\tuntagged_addr(addr);\t\t\t\t\\\n+})\n+#endif\n+\n #ifdef masked_user_access_begin\n #define can_do_masked_user_access() 1\n # ifndef masked_user_write_access_begin\ndiff --git a/mm/memory.c b/mm/memory.c\nindex 86a973119bd46c..d2b2f0014a0c66 100644\n--- a/mm/memory.c\n+++ b/mm/memory.c\n@@ -42,6 +42,8 @@\n #include \u003clinux/kernel_stat.h\u003e\n #include \u003clinux/mm.h\u003e\n #include \u003clinux/mm_inline.h\u003e\n+#include \u003clinux/secretmem.h\u003e\n+#include \u003clinux/pagewalk.h\u003e\n #include \u003clinux/sched/mm.h\u003e\n #include \u003clinux/sched/numa_balancing.h\u003e\n #include \u003clinux/sched/task.h\u003e\n@@ -7062,6 +7064,180 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,\n EXPORT_SYMBOL_GPL(generic_access_phys);\n #endif\n \n+/*\n+ * The fast path uses folio_walk_start(FW_VMA_LOCKED), which needs the per-VMA\n+ * lock and RCU-freed page tables to walk page tables without the mmap lock.\n+ */\n+#if defined(CONFIG_PER_VMA_LOCK) \u0026\u0026 defined(CONFIG_MMU_GATHER_RCU_TABLE_FREE)\n+/*\n+ * Read-side VMA checks for the lockless fast path, mirroring the read side of\n+ * check_vma_flags(): reject what FW_VMA_LOCKED cannot handle (hugetlb), what\n+ * needs the -\u003eaccess() handler (VM_IO/VM_PFNMAP), or what has no struct page to\n+ * copy (secretmem); enforce the FOLL_ANON restriction that\n+ * /proc/PID/{cmdline,environ} rely on (CVE-2018-1120); and require read access\n+ * (honoring FOLL_FORCE). Anything not positively allowed falls back to the slow\n+ * path, which re-validates everything.\n+ */\n+static bool vma_permits_fast_access(struct vm_area_struct *vma,\n+\t\t\t\t unsigned int gup_flags)\n+{\n+\tif (vma-\u003evm_flags \u0026 (VM_IO | VM_PFNMAP))\n+\t\treturn false;\n+\tif (is_vm_hugetlb_page(vma) || vma_is_secretmem(vma))\n+\t\treturn false;\n+\tif ((gup_flags \u0026 FOLL_ANON) \u0026\u0026 !vma_is_anonymous(vma))\n+\t\treturn false;\n+\tif (!(vma-\u003evm_flags \u0026 VM_READ) \u0026\u0026\n+\t (!(gup_flags \u0026 FOLL_FORCE) || !(vma-\u003evm_flags \u0026 VM_MAYREAD)))\n+\t\treturn false;\n+\treturn true;\n+}\n+\n+/* Size of the single mapping entry folio_walk_start() landed on. */\n+static unsigned long fw_entry_size(enum folio_walk_level level)\n+{\n+\tswitch (level) {\n+\tcase FW_LEVEL_PUD:\n+\t\treturn PUD_SIZE;\n+\tcase FW_LEVEL_PMD:\n+\t\treturn PMD_SIZE;\n+\tdefault:\n+\t\treturn PAGE_SIZE;\n+\t}\n+}\n+\n+/*\n+ * Copy @len bytes of the pinned @folio out to @buf, starting at byte offset\n+ * @folio_off within the folio (the position of @addr). Maps and copies one\n+ * page at a time -- kmap_local_folio() for HIGHMEM, copy_from_user_page() for\n+ * the per-page flush on aliasing caches -- without re-walking page tables.\n+ * Each page borrows the caller's single folio reference, so the mapping is\n+ * dropped with kunmap_local() rather than folio_release_kmap().\n+ */\n+static void copy_folio_pages(struct vm_area_struct *vma, struct folio *folio,\n+\t\t\t unsigned long folio_off, unsigned long addr,\n+\t\t\t void *buf, unsigned long len)\n+{\n+\tunsigned long done = 0;\n+\n+\twhile (done \u003c len) {\n+\t\tunsigned long pos = folio_off + done;\n+\t\tunsigned long page_idx = pos \u003e\u003e PAGE_SHIFT;\n+\t\tunsigned int page_off = pos \u0026 ~PAGE_MASK;\n+\t\tunsigned int chunk = min_t(unsigned long, len - done,\n+\t\t\t\t\t PAGE_SIZE - page_off);\n+\t\tvoid *kaddr = kmap_local_folio(folio, page_idx \u003c\u003c PAGE_SHIFT);\n+\n+\t\tcopy_from_user_page(vma, folio_page(folio, page_idx),\n+\t\t\t\t addr + done, buf + done, kaddr + page_off,\n+\t\t\t\t chunk);\n+\t\tkunmap_local(kaddr);\n+\t\tdone += chunk;\n+\t}\n+}\n+\n+/*\n+ * Opportunistic lockless fast path for __access_remote_vm() reads.\n+ *\n+ * Memory already resident in @mm can be read without taking the frequently\n+ * contended mmap_lock: a per-VMA lock stabilizes the VMA, and folio_walk_start()\n+ * with FW_VMA_LOCKED grabs a short-lived reference to a present page from a page\n+ * table walk run with interrupts disabled, which serializes against concurrent\n+ * page table freeing the same way gup_fast does (relying on\n+ * MMU_GATHER_RCU_TABLE_FREE).\n+ *\n+ * Only a request that lies entirely within a single VMA is handled here,\n+ * which should not be an issue in practice since every caller has a\n+ * buffer of PAGE_SIZE or smaller. Loop iteration inside this function\n+ * should be rare, too.\n+ *\n+ * Returns the number of bytes transferred via the fast path.\n+ */\n+static int access_remote_vm_fast(struct mm_struct *mm, unsigned long addr,\n+\t\t\t\t void *buf, int len, unsigned int gup_flags)\n+{\n+\tvoid *old_buf = buf;\n+\tstruct vm_area_struct *vma;\n+\n+\taddr = untagged_addr_remote_unlocked(mm, addr);\n+\n+\tvma = lock_vma_under_rcu(mm, addr);\n+\tif (!vma)\n+\t\treturn 0;\n+\n+\t/* Only handle a request contained entirely within this one VMA. */\n+\tif (len \u003e vma-\u003evm_end - addr)\n+\t\tgoto out_unlock;\n+\n+\tif (!vma_permits_fast_access(vma, gup_flags))\n+\t\tgoto out_unlock;\n+\n+\twhile (len) {\n+\t\tstruct folio_walk fw;\n+\t\tstruct folio *folio;\n+\t\tstruct page *page;\n+\t\tunsigned long entry_size, folio_off, span, irq_flags;\n+\n+\t\t/*\n+\t\t * The lockless page table walk must run with interrupts\n+\t\t * disabled: page table freeing (munmap or THP collapse, which\n+\t\t * IPI via tlb_remove_table_sync_one() and wait) then cannot free\n+\t\t * a table mid-walk -- the same contract gup_fast relies on. IRQs\n+\t\t * are restored once the folio is pinned; the copy below holds only\n+\t\t * the folio reference.\n+\t\t */\n+\t\tlocal_irq_save(irq_flags);\n+\t\tfolio = folio_walk_start(\u0026fw, vma, addr, FW_VMA_LOCKED);\n+\t\tif (!folio) {\n+\t\t\tlocal_irq_restore(irq_flags);\n+\t\t\tgoto out_unlock;\t/* not present: let the slow path fault it in */\n+\t\t}\n+\t\tpage = fw.page;\n+\t\tif (!page) {\n+\t\t\t/* No struct page to copy (e.g. a special PTE). */\n+\t\t\tfolio_walk_end(\u0026fw, vma);\n+\t\t\tlocal_irq_restore(irq_flags);\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\t\tentry_size = fw_entry_size(fw.level);\n+\t\tfolio_get(folio);\n+\t\tfolio_walk_end(\u0026fw, vma);\n+\t\tlocal_irq_restore(irq_flags);\n+\n+\t\t/*\n+\t\t * folio_walk_start() validated one present mapping entry\n+\t\t * (PAGE/PMD/PUD_SIZE). Copy to the end of that entry, bounded by\n+\t\t * the folio and the remaining length (already within the VMA), so\n+\t\t * a huge mapping is handled in a single walk.\n+\t\t */\n+\t\tfolio_off = (folio_page_idx(folio, page) \u003c\u003c PAGE_SHIFT) +\n+\t\t\t offset_in_page(addr);\n+\t\tspan = min3((unsigned long)len,\n+\t\t\t entry_size - (addr \u0026 (entry_size - 1)),\n+\t\t\t (folio_nr_pages(folio) \u003c\u003c PAGE_SHIFT) - folio_off);\n+\n+\t\tcopy_folio_pages(vma, folio, folio_off, addr, buf, span);\n+\n+\t\t/* Match the FOLL_TOUCH behaviour of the slow (GUP) path. */\n+\t\tfolio_mark_accessed(folio);\n+\t\tfolio_put(folio);\n+\t\tlen -= span;\n+\t\tbuf += span;\n+\t\taddr += span;\n+\t}\n+\n+out_unlock:\n+\tvma_end_read(vma);\n+\treturn buf - old_buf;\n+}\n+#else\n+static int access_remote_vm_fast(struct mm_struct *mm, unsigned long addr,\n+\t\t\t\t void *buf, int len, unsigned int gup_flags)\n+{\n+\treturn 0;\n+}\n+#endif /* CONFIG_PER_VMA_LOCK \u0026\u0026 CONFIG_MMU_GATHER_RCU_TABLE_FREE */\n+\n /*\n * Access another process' address space as given in mm.\n */\n@@ -7071,15 +7247,30 @@ static int __access_remote_vm(struct mm_struct *mm, unsigned long addr,\n \tvoid *old_buf = buf;\n \tint write = gup_flags \u0026 FOLL_WRITE;\n \n+\t/*\n+\t * Try the lockless fast path for reads first; it transfers what it can\n+\t * from resident memory without taking mmap_lock, and leaves the\n+\t * remainder (if any) to the slow path below.\n+\t */\n+\tif (!write) {\n+\t\tint done = access_remote_vm_fast(mm, addr, buf, len, gup_flags);\n+\n+\t\taddr += done;\n+\t\tbuf += done;\n+\t\tlen -= done;\n+\t\tif (!len)\n+\t\t\treturn buf - old_buf;\n+\t}\n+\n \tif (mmap_read_lock_killable(mm))\n-\t\treturn 0;\n+\t\treturn buf - old_buf;\n \n \t/* Untag the address before looking up the VMA */\n \taddr = untagged_addr_remote(mm, addr);\n \n \t/* Avoid triggering the temporary warning in __get_user_pages */\n \tif (!vma_lookup(mm, addr) \u0026\u0026 !expand_stack(mm, addr))\n-\t\treturn 0;\n+\t\treturn buf - old_buf;\n \n \t/* ignore errors, just check how much was successfully transferred */\n \twhile (len) {\ndiff --git a/mm/pagewalk.c b/mm/pagewalk.c\nindex 3ae2586ff45b44..ab1e81983cb8c7 100644\n--- a/mm/pagewalk.c\n+++ b/mm/pagewalk.c\n@@ -890,7 +890,10 @@ int walk_page_mapping(struct address_space *mapping, pgoff_t first_index,\n * huge_ptep_set_*, ...). Note that the page table entry stored in @fw might\n * not correspond to the first physical entry of a logical hugetlb entry.\n *\n- * The mmap lock must be held in read mode.\n+ * The mmap lock must be held in read mode. Alternatively, if @FW_VMA_LOCKED is\n+ * passed, the VMA's per-VMA lock must be held and interrupts must be disabled\n+ * across the walk and until folio_walk_end() (only supported with RCU-freed page\n+ * tables, i.e. CONFIG_MMU_GATHER_RCU_TABLE_FREE, and not for hugetlb).\n *\n * Return: folio pointer on success, otherwise NULL.\n */\n@@ -908,7 +911,29 @@ struct folio *folio_walk_start(struct folio_walk *fw,\n \tpgd_t *pgdp;\n \tp4d_t *p4dp;\n \n-\tmmap_assert_locked(vma-\u003evm_mm);\n+\tif (flags \u0026 FW_VMA_LOCKED) {\n+\t\t/*\n+\t\t * Lockless walk under the per-VMA lock instead of the mmap\n+\t\t * lock. The VMA lock keeps the VMA stable, but the page tables\n+\t\t * walked below it can still be freed concurrently: a munmap() or\n+\t\t * THP collapse of an adjacent region in the same mm can free a\n+\t\t * shared upper-level table, and collapse_huge_page() -\u003e\n+\t\t * retract_page_tables() frees page tables of VMAs whose lock it\n+\t\t * does not hold. Page table freeing serializes against lockless\n+\t\t * walkers via tlb_remove_table_sync_one(), which IPIs and waits\n+\t\t * for every CPU to enable interrupts; an RCU read-side critical\n+\t\t * section does not block that IPI, so the caller must keep\n+\t\t * interrupts disabled across the whole walk, like gup_fast.\n+\t\t * Hugetlb (PMD sharing) maps page tables not covered by this\n+\t\t * VMA's lock and is not supported.\n+\t\t */\n+\t\tVM_WARN_ON_ONCE(!IS_ENABLED(CONFIG_MMU_GATHER_RCU_TABLE_FREE));\n+\t\tVM_WARN_ON_ONCE(is_vm_hugetlb_page(vma));\n+\t\tlockdep_assert_irqs_disabled();\n+\t\tvma_assert_locked(vma);\n+\t} else {\n+\t\tmmap_assert_locked(vma-\u003evm_mm);\n+\t}\n \tvma_pgtable_walk_begin(vma);\n \n \tif (WARN_ON_ONCE(addr \u003c vma-\u003evm_start || addr \u003e= vma-\u003evm_end))\n"
} |
| 2/1 | 2026/06/25 02:10 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"PER_VMA_LOCK",
"MMU_GATHER_RCU_TABLE_FREE"
],
"FocusSymbols": [
"access_remote_vm_fast",
"__access_remote_vm",
"folio_walk_start",
"copy_folio_pages",
"vma_permits_fast_access"
],
"Reasoning": "The patch introduces a lockless fast path for remote memory access (`__access_remote_vm`), which is reachable via syscalls like `process_vm_readv` and `ptrace`. The fast path relies on per-VMA locks and RCU-freed page tables, making it highly functional and worth fuzzing.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 96017442623ea4e6ed50d9b6003bfbe0f4c94389
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Jun 25 02:10:13 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index ef5b507de34e2e..cee710f64658aa 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -100,18 +100,18 @@ static inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm)
static inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm)
{
mm->context.lam_cr3_mask = oldmm->context.lam_cr3_mask;
- mm->context.untag_mask = oldmm->context.untag_mask;
+ WRITE_ONCE(mm->context.untag_mask, READ_ONCE(oldmm->context.untag_mask));
}
#define mm_untag_mask mm_untag_mask
static inline unsigned long mm_untag_mask(struct mm_struct *mm)
{
- return mm->context.untag_mask;
+ return READ_ONCE(mm->context.untag_mask);
}
static inline void mm_reset_untag_mask(struct mm_struct *mm)
{
- mm->context.untag_mask = -1UL;
+ WRITE_ONCE(mm->context.untag_mask, -1UL);
}
#define arch_pgtable_dma_compat arch_pgtable_dma_compat
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 20de34cc9aa6e7..933b0b8b4d6047 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -39,11 +39,23 @@ static inline unsigned long __untagged_addr(unsigned long addr)
(__force __typeof__(addr))__untagged_addr(__addr); \
})
+/* Strip the tag bits from a remote mm's address; usable without the mmap lock. */
+static inline unsigned long __untagged_addr_remote_unlocked(struct mm_struct *mm,
+ unsigned long addr)
+{
+ return addr & READ_ONCE(mm->context.untag_mask);
+}
+
+#define untagged_addr_remote_unlocked(mm, addr) ({ \
+ unsigned long __addr = (__force unsigned long)(addr); \
+ (__force __typeof__(addr))__untagged_addr_remote_unlocked(mm, __addr); \
+})
+
static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
unsigned long addr)
{
mmap_assert_locked(mm);
- return addr & (mm)->context.untag_mask;
+ return __untagged_addr_remote_unlocked(mm, addr);
}
#define untagged_addr_remote(mm, addr) ({ \
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index d44afbe005bb51..55096136de5313 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -814,7 +814,7 @@ static void enable_lam_func(void *__mm)
static void mm_enable_lam(struct mm_struct *mm)
{
mm->context.lam_cr3_mask = X86_CR3_LAM_U57;
- mm->context.untag_mask = ~GENMASK(62, 57);
+ WRITE_ONCE(mm->context.untag_mask, ~GENMASK(62, 57));
/*
* Even though the process must still be single-threaded at this
diff --git a/include/linux/pagewalk.h b/include/linux/pagewalk.h
index b41d7265c01bc2..d0387470d7322b 100644
--- a/include/linux/pagewalk.h
+++ b/include/linux/pagewalk.h
@@ -150,6 +150,13 @@ typedef int __bitwise folio_walk_flags_t;
/* Walk shared zeropages (small + huge) as well. */
#define FW_ZEROPAGE ((__force folio_walk_flags_t)BIT(0))
+/*
+ * The caller holds the per-VMA lock instead of the mmap lock, with interrupts
+ * disabled across the walk (until folio_walk_end()) to serialize against page
+ * table freeing, the same way gup_fast does. Only valid with RCU-freed page
+ * tables (CONFIG_MMU_GATHER_RCU_TABLE_FREE) and not for hugetlb.
+ */
+#define FW_VMA_LOCKED ((__force folio_walk_flags_t)BIT(1))
enum folio_walk_level {
FW_LEVEL_PTE,
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 8a264662b242c8..c8c83372c9d878 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -34,6 +34,17 @@
})
#endif
+/*
+ * Like untagged_addr_remote(), but for callers that stabilize @mm by other
+ * means (e.g. a per-VMA lock) and must not assert the mmap lock.
+ */
+#ifndef untagged_addr_remote_unlocked
+#define untagged_addr_remote_unlocked(mm, addr) ({ \
+ (void)(mm); \
+ untagged_addr(addr); \
+})
+#endif
+
#ifdef masked_user_access_begin
#define can_do_masked_user_access() 1
# ifndef masked_user_write_access_begin
diff --git a/mm/memory.c b/mm/memory.c
index 86a973119bd46c..d2b2f0014a0c66 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -42,6 +42,8 @@
#include <linux/kernel_stat.h>
#include <linux/mm.h>
#include <linux/mm_inline.h>
+#include <linux/secretmem.h>
+#include <linux/pagewalk.h>
#include <linux/sched/mm.h>
#include <linux/sched/numa_balancing.h>
#include <linux/sched/task.h>
@@ -7062,6 +7064,180 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
EXPORT_SYMBOL_GPL(generic_access_phys);
#endif
+/*
+ * The fast path uses folio_walk_start(FW_VMA_LOCKED), which needs the per-VMA
+ * lock and RCU-freed page tables to walk page tables without the mmap lock.
+ */
+#if defined(CONFIG_PER_VMA_LOCK) && defined(CONFIG_MMU_GATHER_RCU_TABLE_FREE)
+/*
+ * Read-side VMA checks for the lockless fast path, mirroring the read side of
+ * check_vma_flags(): reject what FW_VMA_LOCKED cannot handle (hugetlb), what
+ * needs the ->access() handler (VM_IO/VM_PFNMAP), or what has no struct page to
+ * copy (secretmem); enforce the FOLL_ANON restriction that
+ * /proc/PID/{cmdline,environ} rely on (CVE-2018-1120); and require read access
+ * (honoring FOLL_FORCE). Anything not positively allowed falls back to the slow
+ * path, which re-validates everything.
+ */
+static bool vma_permits_fast_access(struct vm_area_struct *vma,
+ unsigned int gup_flags)
+{
+ if (vma->vm_flags & (VM_IO | VM_PFNMAP))
+ return false;
+ if (is_vm_hugetlb_page(vma) || vma_is_secretmem(vma))
+ return false;
+ if ((gup_flags & FOLL_ANON) && !vma_is_anonymous(vma))
+ return false;
+ if (!(vma->vm_flags & VM_READ) &&
+ (!(gup_flags & FOLL_FORCE) || !(vma->vm_flags & VM_MAYREAD)))
+ return false;
+ return true;
+}
+
+/* Size of the single mapping entry folio_walk_start() landed on. */
+static unsigned long fw_entry_size(enum folio_walk_level level)
+{
+ switch (level) {
+ case FW_LEVEL_PUD:
+ return PUD_SIZE;
+ case FW_LEVEL_PMD:
+ return PMD_SIZE;
+ default:
+ return PAGE_SIZE;
+ }
+}
+
+/*
+ * Copy @len bytes of the pinned @folio out to @buf, starting at byte offset
+ * @folio_off within the folio (the position of @addr). Maps and copies one
+ * page at a time -- kmap_local_folio() for HIGHMEM, copy_from_user_page() for
+ * the per-page flush on aliasing caches -- without re-walking page tables.
+ * Each page borrows the caller's single folio reference, so the mapping is
+ * dropped with kunmap_local() rather than folio_release_kmap().
+ */
+static void copy_folio_pages(struct vm_area_struct *vma, struct folio *folio,
+ unsigned long folio_off, unsigned long addr,
+ void *buf, unsigned long len)
+{
+ unsigned long done = 0;
+
+ while (done < len) {
+ unsigned long pos = folio_off + done;
+ unsigned long page_idx = pos >> PAGE_SHIFT;
+ unsigned int page_off = pos & ~PAGE_MASK;
+ unsigned int chunk = min_t(unsigned long, len - done,
+ PAGE_SIZE - page_off);
+ void *kaddr = kmap_local_folio(folio, page_idx << PAGE_SHIFT);
+
+ copy_from_user_page(vma, folio_page(folio, page_idx),
+ addr + done, buf + done, kaddr + page_off,
+ chunk);
+ kunmap_local(kaddr);
+ done += chunk;
+ }
+}
+
+/*
+ * Opportunistic lockless fast path for __access_remote_vm() reads.
+ *
+ * Memory already resident in @mm can be read without taking the frequently
+ * contended mmap_lock: a per-VMA lock stabilizes the VMA, and folio_walk_start()
+ * with FW_VMA_LOCKED grabs a short-lived reference to a present page from a page
+ * table walk run with interrupts disabled, which serializes against concurrent
+ * page table freeing the same way gup_fast does (relying on
+ * MMU_GATHER_RCU_TABLE_FREE).
+ *
+ * Only a request that lies entirely within a single VMA is handled here,
+ * which should not be an issue in practice since every caller has a
+ * buffer of PAGE_SIZE or smaller. Loop iteration inside this function
+ * should be rare, too.
+ *
+ * Returns the number of bytes transferred via the fast path.
+ */
+static int access_remote_vm_fast(struct mm_struct *mm, unsigned long addr,
+ void *buf, int len, unsigned int gup_flags)
+{
+ void *old_buf = buf;
+ struct vm_area_struct *vma;
+
+ addr = untagged_addr_remote_unlocked(mm, addr);
+
+ vma = lock_vma_under_rcu(mm, addr);
+ if (!vma)
+ return 0;
+
+ /* Only handle a request contained entirely within this one VMA. */
+ if (len > vma->vm_end - addr)
+ goto out_unlock;
+
+ if (!vma_permits_fast_access(vma, gup_flags))
+ goto out_unlock;
+
+ while (len) {
+ struct folio_walk fw;
+ struct folio *folio;
+ struct page *page;
+ unsigned long entry_size, folio_off, span, irq_flags;
+
+ /*
+ * The lockless page table walk must run with interrupts
+ * disabled: page table freeing (munmap or THP collapse, which
+ * IPI via tlb_remove_table_sync_one() and wait) then cannot free
+ * a table mid-walk -- the same contract gup_fast relies on. IRQs
+ * are restored once the folio is pinned; the copy below holds only
+ * the folio reference.
+ */
+ local_irq_save(irq_flags);
+ folio = folio_walk_start(&fw, vma, addr, FW_VMA_LOCKED);
+ if (!folio) {
+ local_irq_restore(irq_flags);
+ goto out_unlock; /* not present: let the slow path fault it in */
+ }
+ page = fw.page;
+ if (!page) {
+ /* No struct page to copy (e.g. a special PTE). */
+ folio_walk_end(&fw, vma);
+ local_irq_restore(irq_flags);
+ goto out_unlock;
+ }
+ entry_size = fw_entry_size(fw.level);
+ folio_get(folio);
+ folio_walk_end(&fw, vma);
+ local_irq_restore(irq_flags);
+
+ /*
+ * folio_walk_start() validated one present mapping entry
+ * (PAGE/PMD/PUD_SIZE). Copy to the end of that entry, bounded by
+ * the folio and the remaining length (already within the VMA), so
+ * a huge mapping is handled in a single walk.
+ */
+ folio_off = (folio_page_idx(folio, page) << PAGE_SHIFT) +
+ offset_in_page(addr);
+ span = min3((unsigned long)len,
+ entry_size - (addr & (entry_size - 1)),
+ (folio_nr_pages(folio) << PAGE_SHIFT) - folio_off);
+
+ copy_folio_pages(vma, folio, folio_off, addr, buf, span);
+
+ /* Match the FOLL_TOUCH behaviour of the slow (GUP) path. */
+ folio_mark_accessed(folio);
+ folio_put(folio);
+ len -= span;
+ buf += span;
+ addr += span;
+ }
+
+out_unlock:
+ vma_end_read(vma);
+ return buf - old_buf;
+}
+#else
+static int access_remote_vm_fast(struct mm_struct *mm, unsigned long addr,
+ void *buf, int len, unsigned int gup_flags)
+{
+ return 0;
+}
+#endif /* CONFIG_PER_VMA_LOCK && CONFIG_MMU_GATHER_RCU_TABLE_FREE */
+
/*
* Access another process' address space as given in mm.
*/
@@ -7071,15 +7247,30 @@ static int __access_remote_vm(struct mm_struct *mm, unsigned long addr,
void *old_buf = buf;
int write = gup_flags & FOLL_WRITE;
+ /*
+ * Try the lockless fast path for reads first; it transfers what it can
+ * from resident memory without taking mmap_lock, and leaves the
+ * remainder (if any) to the slow path below.
+ */
+ if (!write) {
+ int done = access_remote_vm_fast(mm, addr, buf, len, gup_flags);
+
+ addr += done;
+ buf += done;
+ len -= done;
+ if (!len)
+ return buf - old_buf;
+ }
+
if (mmap_read_lock_killable(mm))
- return 0;
+ return buf - old_buf;
/* Untag the address before looking up the VMA */
addr = untagged_addr_remote(mm, addr);
/* Avoid triggering the temporary warning in __get_user_pages */
if (!vma_lookup(mm, addr) && !expand_stack(mm, addr))
- return 0;
+ return buf - old_buf;
/* ignore errors, just check how much was successfully transferred */
while (len) {
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 3ae2586ff45b44..ab1e81983cb8c7 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -890,7 +890,10 @@ int walk_page_mapping(struct address_space *mapping, pgoff_t first_index,
* huge_ptep_set_*, ...). Note that the page table entry stored in @fw might
* not correspond to the first physical entry of a logical hugetlb entry.
*
- * The mmap lock must be held in read mode.
+ * The mmap lock must be held in read mode. Alternatively, if @FW_VMA_LOCKED is
+ * passed, the VMA's per-VMA lock must be held and interrupts must be disabled
+ * across the walk and until folio_walk_end() (only supported with RCU-freed page
+ * tables, i.e. CONFIG_MMU_GATHER_RCU_TABLE_FREE, and not for hugetlb).
*
* Return: folio pointer on success, otherwise NULL.
*/
@@ -908,7 +911,29 @@ struct folio *folio_walk_start(struct folio_walk *fw,
pgd_t *pgdp;
p4d_t *p4dp;
- mmap_assert_locked(vma->vm_mm);
+ if (flags & FW_VMA_LOCKED) {
+ /*
+ * Lockless walk under the per-VMA lock instead of the mmap
+ * lock. The VMA lock keeps the VMA stable, but the page tables
+ * walked below it can still be freed concurrently: a munmap() or
+ * THP collapse of an adjacent region in the same mm can free a
+ * shared upper-level table, and collapse_huge_page() ->
+ * retract_page_tables() frees page tables of VMAs whose lock it
+ * does not hold. Page table freeing serializes against lockless
+ * walkers via tlb_remove_table_sync_one(), which IPIs and waits
+ * for every CPU to enable interrupts; an RCU read-side critical
+ * section does not block that IPI, so the caller must keep
+ * interrupts disabled across the whole walk, like gup_fast.
+ * Hugetlb (PMD sharing) maps page tables not covered by this
+ * VMA's lock and is not supported.
+ */
+ VM_WARN_ON_ONCE(!IS_ENABLED(CONFIG_MMU_GATHER_RCU_TABLE_FREE));
+ VM_WARN_ON_ONCE(is_vm_hugetlb_page(vma));
+ lockdep_assert_irqs_disabled();
+ vma_assert_locked(vma);
+ } else {
+ mmap_assert_locked(vma->vm_mm);
+ }
vma_pgtable_walk_begin(vma);
if (WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end))
|
| 3/2 | 2026/06/25 02:10 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6837 output: 21 thoughts: 274 Thoughts: **Analyzing the Potential Impact of a New Kernel Memory Access Optimization** Okay, so I've got this patch here that's making changes to the kernel's memory access routines. Specifically, it's adding a lockless fast path for `__access_remote_vm()` reads. Interesting... they're calling this new function `access_remote_vm_fast()` and it's utilizing `folio_walk_start()` with a new flag, `FW_VMA_LOCKED`. It looks like there's also some modification of `untagged_addr_remote()`, allowing for unlocked usage via `untagged_addr_remote_unlocked()`. My immediate thought is, is this actually going to be worth fuzzing? I need to check how reachable this code is and if it's even functional. The patch modifies `mm/memory.c` and `mm/pagewalk.c`. A quick scan tells me `__access_remote_vm()` is used by `access_remote_vm()`, which in turn is used by some pretty core functionality: `ptrace` calls (like `PTRACE_PEEKDATA`), `/proc/pid/mem`, `/proc/pid/cmdline`, and `/proc/pid/environ`. Yep, that's definitely reachable and definitely functional. This is a good target. Now, let's nail down those configurations. The fast path is guarded by `#if defined(CONFIG_PER_VMA_LOCK) && defined(CONFIG_MMU_GATHER_RCU_TABLE_FREE)`. So I need to dig into these configs and see what their dependencies are, and whether or not they're likely to be present in any of our typical fuzzing targets. Gotta make sure we're actually testing the code that's being introduced here. |
| 4/2 | 2026/06/25 02:10 | tool | grepper |
0mArgs:{
"Expression": "config PER_VMA_LOCK"
}Results: {
"Output": "mm/Kconfig=1452=config ARCH_SUPPORTS_PER_VMA_LOCK\n--\nmm/Kconfig-1454-\nmm/Kconfig:1455:config PER_VMA_LOCK\nmm/Kconfig-1456-\tdef_bool y\n--\nmm/Kconfig.debug=300=config DEBUG_KMEMLEAK_VERBOSE\n--\nmm/Kconfig.debug-310-\nmm/Kconfig.debug:311:config PER_VMA_LOCK_STATS\nmm/Kconfig.debug-312-\tbool \"Statistics for per-vma locks\"\n"
} |
| 5/2 | 2026/06/25 02:10 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7681 output: 27 thoughts: 48 Thoughts: **Examining the Kernel's Memory Management Configuration** Okay, so I'm looking at this definition, `PER_VMA_LOCK`. It's set to "yes" by default, but only if the architecture supports this "PER_VMA_LOCK" feature. That makes sense, a performance optimization that is architecture-dependent. Now, what's interesting is how it's being conditioned. I need to understand the implications of this feature, so my next step is to examine the `CONFIG_MMU_GATHER_RCU_TABLE_FREE` configuration option. I need to understand if it is linked. This will give a deeper insight. |
| 6/2 | 2026/06/25 02:10 | tool | grepper |
0mArgs:{
"Expression": "config MMU_GATHER_RCU_TABLE_FREE"
}Results: {
"Output": "arch/Kconfig=512=config MMU_GATHER_TABLE_FREE\n--\narch/Kconfig-514-\narch/Kconfig:515:config MMU_GATHER_RCU_TABLE_FREE\narch/Kconfig-516-\tbool\n"
} |
| 7/2 | 2026/06/25 02:10 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7975 output: 27 thoughts: 24 Thoughts: Okay, here's my interpretation of those thoughts, crafted with the understanding that I'm discussing this with a fellow expert: **Investigating a System Architecture Parameter** Right, so this feels like a flag, a hidden boolean. It's probably an architecture-specific setting, something the hardware or firmware configures. My initial instinct is to dig into the x86 architecture and see if this setting is relevant there. Let's start with x86, see if it's even exposed, and if so, how it affects behavior. I'm assuming that it's architecture-specific because the boolean is hidden, likely in the system/architecture definition. From there, we can expand our research. |
| 8/2 | 2026/06/25 02:10 | tool | grepper |
0mArgs:{
"Expression": "select MMU_GATHER_RCU_TABLE_FREE"
}Results: {
"Output": "arch/alpha/Kconfig=2=config ALPHA\n--\narch/alpha/Kconfig-42-\tselect MMU_GATHER_NO_RANGE\narch/alpha/Kconfig:43:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/alpha/Kconfig-44-\tselect SPARSEMEM_EXTREME if SPARSEMEM\n--\narch/arm/Kconfig=2=config ARM\n--\narch/arm/Kconfig-135-\tselect HAVE_PERF_USER_STACK_DUMP\narch/arm/Kconfig:136:\tselect MMU_GATHER_RCU_TABLE_FREE if SMP \u0026\u0026 ARM_LPAE\narch/arm/Kconfig-137-\tselect HAVE_REGS_AND_STACK_ACCESS_API\n--\narch/arm64/Kconfig=2=config ARM64\n--\narch/arm64/Kconfig-223-\tselect HAVE_FUNCTION_ARG_ACCESS_API\narch/arm64/Kconfig:224:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/arm64/Kconfig-225-\tselect HAVE_RSEQ\n--\narch/loongarch/Kconfig=2=config LOONGARCH\n--\narch/loongarch/Kconfig-191-\tselect MMU_GATHER_MERGE_VMAS if MMU\narch/loongarch/Kconfig:192:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/loongarch/Kconfig-193-\tselect MODULES_USE_ELF_RELA if MODULES\n--\narch/mips/Kconfig=2=config MIPS\n--\narch/mips/Kconfig-99-\tselect LOCK_MM_AND_FIND_VMA\narch/mips/Kconfig:100:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/mips/Kconfig-101-\tselect MODULES_USE_ELF_REL if MODULES\n--\narch/parisc/Kconfig=2=config PARISC\n--\narch/parisc/Kconfig-82-\tselect THREAD_INFO_IN_TASK\narch/parisc/Kconfig:83:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/parisc/Kconfig-84-\tselect NEED_DMA_MAP_STATE\n--\narch/powerpc/Kconfig=118=config PPC\n--\narch/powerpc/Kconfig-306-\tselect MMU_GATHER_PAGE_SIZE\narch/powerpc/Kconfig:307:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/powerpc/Kconfig-308-\tselect HAVE_ARCH_TLB_REMOVE_TABLE\n--\narch/riscv/Kconfig=13=config RISCV\n--\narch/riscv/Kconfig-207-\tselect LOCK_MM_AND_FIND_VMA\narch/riscv/Kconfig:208:\tselect MMU_GATHER_RCU_TABLE_FREE if SMP \u0026\u0026 MMU\narch/riscv/Kconfig-209-\tselect MODULES_USE_ELF_RELA if MODULES\n--\narch/s390/Kconfig=75=config S390\n--\narch/s390/Kconfig-263-\tselect MMU_GATHER_NO_GATHER\narch/s390/Kconfig:264:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/s390/Kconfig-265-\tselect MODULES_USE_ELF_RELA\n--\narch/sparc/Kconfig=70=config SPARC64\n--\narch/sparc/Kconfig-76-\tselect HAVE_KPROBES\narch/sparc/Kconfig:77:\tselect MMU_GATHER_RCU_TABLE_FREE if SMP\narch/sparc/Kconfig-78-\tselect HAVE_ARCH_TLB_REMOVE_TABLE if SMP\n--\narch/um/Kconfig=5=config UML\n--\narch/um/Kconfig-46-\tselect SPARSE_IRQ\narch/um/Kconfig:47:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/um/Kconfig-48-\n--\narch/x86/Kconfig=58=config X86\n--\narch/x86/Kconfig-284-\tselect ASYNC_KERNEL_PGTABLE_FREE\tif IOMMU_SVA\narch/x86/Kconfig:285:\tselect MMU_GATHER_RCU_TABLE_FREE\narch/x86/Kconfig-286-\tselect MMU_GATHER_MERGE_VMAS\n"
} |
| 9/2 | 2026/06/25 02:10 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9328 output: 20 thoughts: 271 Thoughts: **My Configuration Conundrum** Okay, so I'm taking a look at these default x86 configurations, specifically `PER_VMA_LOCK` and `MMU_GATHER_RCU_TABLE_FREE`. They're already enabled by default, which is good, but I need to decide what to list given the prompt's instruction to only list those configs that specifically cover the modified code. Should I include `PER_VMA_LOCK` anyway, just for clarity? Hmmm... the patch *does* have that `#if` condition using both that and the other one, so it's directly relevant here. Okay, I'll put it in. Now for focus symbols. That's where things get interesting. The patch introduces `access_remote_vm_fast`, `vma_permits_fast_access`, and `copy_folio_pages`, and it modifies `__access_remote_vm`, and `folio_walk_start`. `access_remote_vm_fast` is definitely a key focus point. And `__access_remote_vm` is also a good choice. Even though `folio_walk_start` seems a bit generic, it is modified, so I'll keep that one. Alright, let's just make sure I understand the use of `__access_remote_vm` and I should have it. |
| 10/2 | 2026/06/25 02:10 | tool | grepper |
0mArgs:{
"Expression": "__access_remote_vm"
}Results: {
"Output": "arch/arm64/kernel/mte.c=418=long get_mte_ctrl(struct task_struct *task)\n--\narch/arm64/kernel/mte.c-441- * the number of tags copied. Return 0 if any tags copied, error otherwise.\narch/arm64/kernel/mte.c:442: * Inspired by __access_remote_vm().\narch/arm64/kernel/mte.c-443- */\n--\nkernel/time/namespace_vdso.c=71=struct page *find_timens_vvar_page(struct vm_area_struct *vma)\n--\nkernel/time/namespace_vdso.c-80-\t * in special_mapping_vmops().\nkernel/time/namespace_vdso.c:81:\t * For more details check_vma_flags() and __access_remote_vm()\nkernel/time/namespace_vdso.c-82-\t */\n--\nmm/memory.c=7117=static void copy_folio_pages(struct vm_area_struct *vma, struct folio *folio,\n--\nmm/memory.c-7139-/*\nmm/memory.c:7140: * Opportunistic lockless fast path for __access_remote_vm() reads.\nmm/memory.c-7141- *\n--\nmm/memory.c=7234=static int access_remote_vm_fast(struct mm_struct *mm, unsigned long addr,\n--\nmm/memory.c-7243- */\nmm/memory.c:7244:static int __access_remote_vm(struct mm_struct *mm, unsigned long addr,\nmm/memory.c-7245-\t\t\t void *buf, int len, unsigned int gup_flags)\n--\nmm/memory.c=7349=int access_remote_vm(struct mm_struct *mm, unsigned long addr,\n--\nmm/memory.c-7351-{\nmm/memory.c:7352:\treturn __access_remote_vm(mm, addr, buf, len, gup_flags);\nmm/memory.c-7353-}\n--\nmm/memory.c=7360=int access_process_vm(struct task_struct *tsk, unsigned long addr,\n--\nmm/memory.c-7369-\nmm/memory.c:7370:\tret = __access_remote_vm(mm, addr, buf, len, gup_flags);\nmm/memory.c-7371-\n--\nmm/nommu.c=1639=EXPORT_SYMBOL(filemap_map_pages);\nmm/nommu.c-1640-\nmm/nommu.c:1641:static int __access_remote_vm(struct mm_struct *mm, unsigned long addr,\nmm/nommu.c-1642-\t\t\t void *buf, int len, unsigned int gup_flags)\n--\nmm/nommu.c=1685=int access_remote_vm(struct mm_struct *mm, unsigned long addr,\n--\nmm/nommu.c-1687-{\nmm/nommu.c:1688:\treturn __access_remote_vm(mm, addr, buf, len, gup_flags);\nmm/nommu.c-1689-}\n--\nmm/nommu.c=1695=int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len,\n--\nmm/nommu.c-1706-\nmm/nommu.c:1707:\tlen = __access_remote_vm(mm, addr, buf, len, gup_flags);\nmm/nommu.c-1708-\n"
} |
| 11/2 | 2026/06/25 02:10 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10850 output: 168 thoughts: 477 Thoughts: **Fuzzing Target Identification: Remote VM Access Fast Path** Okay, so I've zeroed in on the lockless fast path for remote memory access. `__access_remote_vm` and `access_remote_vm_fast` are definitely the key focus symbols here. Even though `access_remote_vm_fast` is static, syzkaller should still be able to target it. I'll also add `folio_walk_start` to the list because it's relevant to the operation. And since the code mentions it, I should also add `copy_folio_pages`, and `vma_permits_fast_access`. Now, regarding configurations, I need to check which ones are relevant. `CONFIG_PER_VMA_LOCK` and `CONFIG_MMU_GATHER_RCU_TABLE_FREE` are the guards for the fast path. They appear to be enabled by default on x86, but I'll include them in the configuration just to be safe. Next, I need to confirm reachability. I see that the `process_vm_readv` syscall uses `access_process_vm`, which calls `__access_remote_vm`, and `ptrace` uses it as well. That confirms it's a functional path we can hit. So, here's the summary I've got: * **WorthFuzzing:** True * **FocusSymbols:** `access_remote_vm_fast`, `__access_remote_vm`, `folio_walk_start`, `copy_folio_pages`, `vma_permits_fast_access` * **EnableConfigs:** `PER_VMA_LOCK`, `MMU_GATHER_RCU_TABLE_FREE` * **Reasoning:** The patch introduces a lockless fast path for remote memory access (`__access_remote_vm`). This is reachable via `ptrace` and `process_vm_readv` syscalls. The fast path relies on per-VMA locks and RCU-freed page tables. Let me just double-check those configs again. Both seem to be standard defaults, so I'll keep them in the list. Okay, let's see if there are any other related functions. Let me check...yes, there's `vma_permits_fast_access`, `copy_folio_pages` and `fw_entry_size`. They all look relevant, so I'll be sure to include those. Alright, I'm confident with this. I'll call set-results. |
| 12/2 | 2026/06/25 02:10 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"PER_VMA_LOCK",
"MMU_GATHER_RCU_TABLE_FREE"
],
"FocusSymbols": [
"access_remote_vm_fast",
"__access_remote_vm",
"folio_walk_start",
"copy_folio_pages",
"vma_permits_fast_access"
],
"Reasoning": "The patch introduces a lockless fast path for remote memory access (`__access_remote_vm`), which is reachable via syscalls like `process_vm_readv` and `ptrace`. The fast path relies on per-VMA locks and RCU-freed page tables, making it highly functional and worth fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"PER_VMA_LOCK",
"MMU_GATHER_RCU_TABLE_FREE"
],
"FocusSymbols": [
"access_remote_vm_fast",
"__access_remote_vm",
"folio_walk_start",
"copy_folio_pages",
"vma_permits_fast_access"
],
"Reasoning": "The patch introduces a lockless fast path for remote memory access (`__access_remote_vm`), which is reachable via syscalls like `process_vm_readv` and `ptrace`. The fast path relies on per-VMA locks and RCU-freed page tables, making it highly functional and worth fuzzing.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|