From: Rik van Riel <riel@surriel.com>
To: linux-kernel@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>
Cc: kernel-team@meta.com, Rik van Riel <riel@surriel.com>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>,
linux-mm@kvack.org, Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Usama Arif <usamaarif642@gmail.com>
Subject: [PATCH RFC v3 1/6] x86/mm: add untagged_addr_remote_unlocked()
Date: Fri, 17 Jul 2026 13:00:31 -0400 [thread overview]
Message-ID: <20260717170036.743149-2-riel@surriel.com> (raw)
In-Reply-To: <20260717170036.743149-1-riel@surriel.com>
__access_remote_vm() reads another process's memory under the mmap lock. On
large machines that lock is contended by tasks polling /proc/PID/cmdline,
/proc/PID/environ, or calling process_vm_readv(), even though the memory
they read is almost always resident and could be reached under the per-VMA
lock instead.
Looking up the VMA first requires untagging the address.
untagged_addr_remote() asserts the mmap lock only because it reads
mm->context.untag_mask, which can race with the write in mm_enable_lam().
That mask is set once, when LAM is enabled, and never changes afterwards,
so the read itself does not need the lock. It is already read without it,
from the context switch path and /proc/PID/status.
Add untagged_addr_remote_unlocked() for callers that have not taken the
mmap lock, and annotate access to mm->context.untag_mask with READ_ONCE()
and WRITE_ONCE() so the existing lockless reads are explicit and
KCSAN-clean. untagged_addr_remote() keeps its assertion and shares the same
code.
Assisted-by: Claude:claude-opus-4.8
Acked-by: Usama Arif <usamaarif642@gmail.com>
Signed-off-by: Rik van Riel <riel@surriel.com>
---
arch/x86/include/asm/mmu_context.h | 6 +++---
arch/x86/include/asm/uaccess_64.h | 14 +++++++++++---
arch/x86/kernel/process_64.c | 4 ++--
include/linux/uaccess.h | 7 +++++++
4 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index ef5b507de34e..cee710f64658 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 20de34cc9aa6..05377ad804d1 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -39,18 +39,26 @@ static inline unsigned long __untagged_addr(unsigned long addr)
(__force __typeof__(addr))__untagged_addr(__addr); \
})
+/*
+ * mm->context.untag_mask is set once, when LAM is enabled, and never
+ * changes afterwards, so it can be read without holding the mmap lock.
+ */
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 addr & READ_ONCE(mm->context.untag_mask);
}
-#define untagged_addr_remote(mm, addr) ({ \
+#define untagged_addr_remote_unlocked(mm, addr) ({ \
unsigned long __addr = (__force unsigned long)(addr); \
(__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
})
+#define untagged_addr_remote(mm, addr) ({ \
+ mmap_assert_locked(mm); \
+ untagged_addr_remote_unlocked(mm, addr); \
+})
+
#endif
#define valid_user_address(x) \
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index d44afbe005bb..9fa659117f38 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
@@ -952,7 +952,7 @@ long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2)
#endif
#ifdef CONFIG_ADDRESS_MASKING
case ARCH_GET_UNTAG_MASK:
- return put_user(task->mm->context.untag_mask,
+ return put_user(mm_untag_mask(task->mm),
(unsigned long __user *)arg2);
case ARCH_ENABLE_TAGGED_ADDR:
return prctl_enable_tagged_addr(task->mm, arg2);
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index eddbbb65ccc4..7e6e4c89184c 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -34,6 +34,13 @@
})
#endif
+#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
--
2.53.0-Meta
next prev parent reply other threads:[~2026-07-17 17:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 17:00 [PATCH v3 0/6] mm: access remote process memory under the per-VMA lock Rik van Riel
2026-07-17 17:00 ` Rik van Riel [this message]
2026-07-17 17:00 ` [PATCH RFC v3 2/6] riscv/mm: add untagged_addr_remote_unlocked() Rik van Riel
2026-07-17 17:00 ` [PATCH RFC v3 3/6] mm: rename get_user_page_vma_remote() to get_user_page_lookup_vma() Rik van Riel
2026-07-17 17:00 ` [PATCH RFC v3 4/6] mm/gup: add get_user_page_vma() to fault in a page under a held lock Rik van Riel
2026-07-17 17:00 ` [PATCH RFC v3 5/6] mm: use per-VMA lock in __access_remote_vm() for single-VMA accesses Rik van Riel
2026-07-17 17:00 ` [PATCH RFC v3 6/6] selftests/mm: cover /proc/pid/mem access to VM_PFNMAP memory Rik van Riel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260717170036.743149-2-riel@surriel.com \
--to=riel@surriel.com \
--cc=akpm@linux-foundation.org \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=david@kernel.org \
--cc=hpa@zytor.com \
--cc=kernel-team@meta.com \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=mingo@redhat.com \
--cc=rppt@kernel.org \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=usamaarif642@gmail.com \
--cc=vbabka@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome