mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: James Houghton <jthoughton@google.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Thomas Gleixner <tglx@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Kees Cook <kees@kernel.org>,  Arnd Bergmann <arnd@arndb.de>,
	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>,
	 Sean Christopherson <seanjc@google.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	 Jim Mattson <jmattson@google.com>, Jens Axboe <axboe@kernel.dk>,
	 Pavel Begunkov <asml.silence@gmail.com>,
	 "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
	 "Martin K. Petersen" <mkp@kernel.org>,
	David Sterba <dsterba@suse.com>, Chris Mason <mason@kernel.org>,
	 Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	 John Fastabend <john.fastabend@gmail.com>,
	Josh Poimboeuf <jpoimboe@kernel.org>,
	 Steven Rostedt <rostedt@goodmis.org>,
	Masami Hiramatsu <mhiramat@kernel.org>,
	 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Ingo Molnar <mingo@redhat.com>,
	 Arnaldo Carvalho de Melo <acme@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>,
	linux-mm@kvack.org,  linux-fsdevel@vger.kernel.org,
	kvm@vger.kernel.org, io-uring@vger.kernel.org,
	 linux-scsi@vger.kernel.org, linux-btrfs@vger.kernel.org,
	bpf@vger.kernel.org,  linux-trace-kernel@vger.kernel.org,
	linux-perf-users@vger.kernel.org,  linux-kernel@vger.kernel.org,
	James Houghton <jthoughton@google.com>
Subject: [RFC PATCH 06/10] uaccess: Refuse and warn on user copies when current->mm is NULL
Date: Mon, 26 Oct 2026 21:52:22 +0000	[thread overview]
Message-ID: <20261026215226.3713941-7-jthoughton@google.com> (raw)
In-Reply-To: <20261026215226.3713941-1-jthoughton@google.com>

Accessing user memory from a task that has no mm is always a bug. This
can happen from a kernel thread that is not using kthread_use_mm(), or
from a task that has already gone through exit_mm() (e.g. when the last
reference to a file is dropped from task_work at exit). KVM has had
bugs of exactly this kind, and other drivers may have them too.

Such an access does not reliably fail. The user portion of the address
space belongs to whatever mm happens to be lazily loaded, if any. If
the access faults, the fault handler refuses to handle it and the copy
fails, but if the page is already mapped, the copy silently reads or
writes another task's memory.

Add uaccess_should_fail(), which combines the existing
should_fail_usercopy() fault injection check with a
WARN_ON_ONCE(!current->mm), and use it in place of every
should_fail_usercopy() call. The user copy is then refused as if it had
failed, so no access to user memory takes place.

This covers copy_{to,from}_user() on all architectures, including the
masked user access paths that never call access_ok(), and the
__copy_{to,from}_user() variants used by KVM's guest memory accessors.
It also covers __copy_to_user_inatomic() (and so copy_to_user_nofault()),
the user-backed iov_iter copy routines and strncpy_from_user().

Paths that never called should_fail_usercopy() are not covered, e.g.
__copy_from_user_inatomic(), copy_from_user_nofault(), strnlen_user(),
get_user()/put_user(), clear_user() and unsafe_*() accesses within
user_access_begin() sections.

Signed-off-by: James Houghton <jthoughton@google.com>
---
 include/linux/uaccess.h | 27 ++++++++++++++++++++++-----
 lib/iov_iter.c          |  6 +++---
 lib/strncpy_from_user.c |  2 +-
 3 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index eddbbb65ccc4..8ab24e706a22 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -50,6 +50,23 @@
  #define mask_user_address(src) (src)
 #endif
 
+/*
+ * Return true if a user copy must not be attempted, either because a failure
+ * is being injected, or because the current task has no mm.
+ *
+ * Accessing user memory without an mm (e.g. from a kernel thread that is not
+ * using kthread_use_mm(), or from a task that has already gone through
+ * exit_mm()) is always a bug: the user portion of the address space belongs to
+ * whatever mm happens to be lazily loaded, if any, so the access could
+ * silently hit another task's memory.
+ */
+static __always_inline bool uaccess_should_fail(void)
+{
+	if (WARN_ON_ONCE(!current->mm))
+		return true;
+	return should_fail_usercopy();
+}
+
 /*
  * Architectures should provide two primitives (raw_copy_{to,from}_user())
  * and get rid of their private instances of copy_{to,from}_user() and
@@ -114,7 +131,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 
 	might_fault();
 	instrument_copy_from_user_before(to, from, n);
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return n;
 	check_object_size(to, n, false);
 	res = raw_copy_from_user(to, from, n);
@@ -138,7 +155,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 static __always_inline __must_check unsigned long
 __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return n;
 	instrument_copy_to_user(to, from, n);
 	check_object_size(from, n, true);
@@ -149,7 +166,7 @@ static __always_inline __must_check unsigned long
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	might_fault();
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return n;
 	instrument_copy_to_user(to, from, n);
 	check_object_size(from, n, true);
@@ -167,7 +184,7 @@ _inline_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	unsigned long res = n;
 	might_fault();
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		goto fail;
 	if (can_do_masked_user_access())
 		from = mask_user_address(from);
@@ -195,7 +212,7 @@ static inline __must_check unsigned long
 _inline_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	might_fault();
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return n;
 	if (access_ok(to, n)) {
 		instrument_copy_to_user(to, from, n);
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 2072c04e99d0..3d6ecb50d778 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -17,7 +17,7 @@ static __always_inline
 size_t copy_to_user_iter(void __user *iter_to, size_t progress,
 			 size_t len, void *from, void *priv2)
 {
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return len;
 	if (access_ok(iter_to, len)) {
 		from += progress;
@@ -33,7 +33,7 @@ size_t copy_to_user_iter_nofault(void __user *iter_to, size_t progress,
 {
 	ssize_t res;
 
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return len;
 
 	from += progress;
@@ -47,7 +47,7 @@ size_t copy_from_user_iter(void __user *iter_from, size_t progress,
 {
 	size_t res = len;
 
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return len;
 	if (can_do_masked_user_access()) {
 		iter_from = mask_user_address(iter_from);
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index 5bb752ff7c61..565b3125e752 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -115,7 +115,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
 	unsigned long max_addr, src_addr;
 
 	might_fault();
-	if (should_fail_usercopy())
+	if (uaccess_should_fail())
 		return -EFAULT;
 	if (unlikely(count <= 0))
 		return 0;
-- 
2.56.0.307.g5fe7bd680c-goog


  parent reply	other threads:[~2026-10-26 21:52 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26 21:52 [RFC PATCH 00/10] uaccess: Refuse and warn on user accesses " James Houghton
2026-10-26 21:52 ` [RFC PATCH 01/10] scsi: bsg: Don't copy sense data to user memory when canceled James Houghton
2026-10-27  2:41   ` Jens Axboe
2026-10-26 21:52 ` [RFC PATCH 02/10] btrfs: Don't copy encoded read " James Houghton
2026-10-27  2:42   ` Jens Axboe
2026-10-26 21:52 ` [RFC PATCH 03/10] bpf: Fail sleepable user copy helpers when current->mm is NULL James Houghton
2026-10-26 22:30   ` bot+bpf-ci
2026-10-26 21:52 ` [RFC PATCH 04/10] stacktrace: Don't unwind the user stack without an mm James Houghton
2026-10-26 22:30   ` bot+bpf-ci
2026-10-26 22:55     ` James Houghton
2026-10-26 21:52 ` [RFC PATCH 05/10] perf/core: " James Houghton
2026-10-26 21:52 ` James Houghton [this message]
2026-10-26 22:42   ` [RFC PATCH 06/10] uaccess: Refuse and warn on user copies when current->mm is NULL bot+bpf-ci
2026-10-26 23:41     ` James Houghton
2026-10-26 21:52 ` [RFC PATCH 07/10] uaccess: Fail user nofault helpers quietly " James Houghton
2026-10-26 21:52 ` [RFC PATCH 08/10] uaccess: Refuse and warn on __copy_from_user_inatomic() without an mm James Houghton
2026-10-26 22:30   ` bot+bpf-ci
2026-10-26 22:41     ` James Houghton
2026-10-26 21:52 ` [RFC PATCH 09/10] uaccess: Refuse and warn on more user accesses " James Houghton
2026-10-26 21:52 ` [RFC PATCH 10/10] uaccess: Move the NULL mm warning out of line James Houghton
2026-10-26 23:02   ` Arnd Bergmann
2026-10-26 23:51     ` James Houghton
2026-10-27  0:12 ` [RFC PATCH 00/10] uaccess: Refuse and warn on user accesses when current->mm is NULL Arnd Bergmann
2026-10-27 10:33   ` Arnd Bergmann

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=20261026215226.3713941-7-jthoughton@google.com \
    --to=jthoughton@google.com \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=acme@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=asml.silence@gmail.com \
    --cc=ast@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=david@kernel.org \
    --cc=dsterba@suse.com \
    --cc=io-uring@vger.kernel.org \
    --cc=jmattson@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=jpoimboe@kernel.org \
    --cc=kees@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=liam@infradead.org \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=ljs@kernel.org \
    --cc=mason@kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=mhocko@suse.com \
    --cc=mingo@redhat.com \
    --cc=mkp@kernel.org \
    --cc=namhyung@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=rppt@kernel.org \
    --cc=seanjc@google.com \
    --cc=surenb@google.com \
    --cc=tglx@kernel.org \
    --cc=vbabka@kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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

all inboxes | Powered by JetHome®