From: James Houghton <jthoughton@google.com>
To: bot+bpf-ci@kernel.org
Cc: James.Bottomley@HansenPartnership.com, acme@kernel.org,
akpm@linux-foundation.org, andrii@kernel.org, arnd@arndb.de,
asml.silence@gmail.com, ast@kernel.org, axboe@kernel.dk,
bpf@vger.kernel.org, daniel@iogearbox.net, david@kernel.org,
dsterba@suse.com, eddyz87@gmail.com, ihor.solodrai@linux.dev,
io-uring@vger.kernel.org, jmattson@google.com,
john.fastabend@gmail.com, jpoimboe@kernel.org,
jthoughton@google.com, kees@kernel.org, kvm@vger.kernel.org,
liam@infradead.org, linux-btrfs@vger.kernel.org,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, linux-perf-users@vger.kernel.org,
linux-scsi@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
ljs@kernel.org, martin.lau@kernel.org, mason@kernel.org,
mathieu.desnoyers@efficios.com, mhiramat@kernel.org,
mhocko@suse.com, mingo@redhat.com, mkp@kernel.org,
namhyung@kernel.org, pbonzini@redhat.com, peterz@infradead.org,
rostedt@goodmis.org, rppt@kernel.org, seanjc@google.com,
surenb@google.com, tglx@kernel.org, vbabka@kernel.org,
viro@zeniv.linux.org.uk, yonghong.song@linux.dev
Subject: Re: [RFC PATCH 06/10] uaccess: Refuse and warn on user copies when current->mm is NULL
Date: Mon, 26 Oct 2026 23:41:54 +0000 [thread overview]
Message-ID: <20261026234155.4028467-1-jthoughton@google.com> (raw)
In-Reply-To: <b9959bd7711dee7a83a07b012b5967980d178c95eae90adeebebcb6040fc526f@mail.kernel.org>
On Mon, Oct 26, 2026 at 3:42 PM <bot+bpf-ci@kernel.org> wrote:
>
> > uaccess: Refuse and warn on user copies when current->mm is NULL
>
> TL;DR:
> - Possible spurious -EFAULT on valid kernel addresses on xtensa/nios2 from
> mm-less tasks (kworkers), e.g. d_path
> - nofault helpers may hit the new WARN_ON_ONCE (BPF/tracing); fix is later in
> series, breaking bisection
>
> > diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
> > index eddbbb65ccc4..e54a6d804bf9 100644
> > --- a/include/linux/uaccess.h
> > +++ b/include/linux/uaccess.h
> > @@ -50,6 +50,23 @@
>
> [ ... ]
>
> > +static __always_inline bool uaccess_should_fail(void)
> > +{
> > + if (WARN_ON_ONCE(!current->mm))
> > + return true;
> > + return should_fail_usercopy();
> > +}
>
> [ ... ]
>
> > @@ -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);
>
> Can this refuse legitimate kernel address copies on xtensa and nios2?
>
> On both architectures __copy_from_user() and __copy_to_user() also sit under
> the generic kernel nofault accessors. Neither architecture defines
> __get_kernel_nofault or arch_get_kernel_nofault, so both use the fallback in
> include/linux/uaccess.h, which goes through __get_user()/__put_user() on the
> kernel address:
>
> #define __get_kernel_nofault(dst, src, type, label) \
> ...
> if (__get_user(data, p)) \
> goto label; \
>
> On xtensa, 8-byte __get_user()/__put_user() are implemented with
> __copy_from_user()/__copy_to_user() (arch/xtensa/include/asm/uaccess.h):
>
> case 8: {
> u64 __x;
> if (unlikely(__copy_from_user(&__x, ptr, 8))) {
> ...
> retval = __copy_to_user(ptr, &__v64, 8) ? -EFAULT : 0;
>
> On nios2, __put_user_common() sends any size other than 1, 2 or 4 to
> __copy_to_user().
>
> Neither architecture selects HAVE_EFFICIENT_UNALIGNED_ACCESS, so
> copy_from_kernel_nofault() and copy_to_kernel_nofault() (mm/maccess.c) use
> the u64 loop whenever dst and src are both 8-byte aligned and at least 8
> bytes remain:
>
> if (!(align & 7))
> copy_from_kernel_nofault_loop(dst, src, size, u64, Efault);
>
> With this patch, every such access from a task with current->mm == NULL
> (kworkers, khungtaskd, kernel_init before exec, the idle task in IRQ, kgdb
> entered from idle) hits WARN_ON_ONCE(!current->mm), and __copy_from_user()
> returns n. copy_from_kernel_nofault() then returns -EFAULT on valid kernel
> memory.
>
> Concrete generic callers include:
>
> d_path() -> prepend() -> prepend_copy() (fs/d_path.c) fills the component
> with 'x' and stops the walk. This is reachable from LSM/IMA path hooks
> run by kworkers, for example async firmware loading.
>
> print_worker_info() (kernel/workqueue.c), called from
> dump_stack_print_info() and sched_show_task() for kworkers, which copies
> wq->name and worker->desc.
>
> copy_to_kernel_nofault() from kgdb_hex2mem()/kgdb_ebin2mem() on nios2,
> which selects HAVE_ARCH_KGDB.
>
> Before this patch these accesses worked on kernel addresses, since
> raw_copy_{from,to}_user() on these architectures is a plain fixup-protected
> copy and access_ok() is not involved. Only opt-in fault injection could
> make them fail.
>
> The commit message rationale ("Accessing user memory from a task that has no
> mm is always a bug") does not apply to kernel addresses. The commit message
> also says get_user()/put_user() are not covered, which does not hold for
> 8-byte accesses on these two architectures.
>
> No later commit in this series appears to touch these paths.
This analysis is correct. Implementing copy-from-kernel functions with calls to
uaccess functions is a little hard to make sense of. :/
I've included a patch at the front of my v2 for xtensa and nios2. I don't think
any other architecture has this problem. I've placed the patch at the bottom of
this reply. I've also adjusted the wording for patch 6.
>
> [ ... ]
>
> > 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;
>
> Can strncpy_from_user_nofault() now trip this WARN_ON_ONCE() from contexts
> where current->mm is NULL by design?
>
> In this tree strncpy_from_user_nofault() (mm/maccess.c) has no current->mm
> check and no nmi_uaccess_okay() check. It goes straight to
> strncpy_from_user():
>
> pagefault_disable();
> ret = strncpy_from_user(dst, unsafe_addr, count);
> pagefault_enable();
>
> and strncpy_from_user() now calls uaccess_should_fail(), which does:
>
> if (WARN_ON_ONCE(!current->mm))
> return true;
>
> The callers of strncpy_from_user_nofault() are tracing helpers that run in
> whatever context the probe fires in, including kernel threads and IRQs taken
> while the idle task runs:
>
> bpf_probe_read_user_str() via bpf_probe_read_user_str_common()
> (kernel/trace/bpf_trace.c), and bpf_probe_read_str() for addresses below
> TASK_SIZE.
>
> bpf_trace_printk()/bpf_snprintf() through bpf_trace_copy_string()
> (kernel/bpf/helpers.c). With CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
> (x86, arm64, ...), any '%s' argument below TASK_SIZE takes this path,
> including a NULL pointer. So bpf_printk("%s", ptr) with ptr == NULL in a
> kprobe that fires in a kworker now triggers the warning.
>
> kprobe/fprobe/eprobe ustring fetch args (fetch_store_string_user() in
> kernel/trace/trace_probe_kernel.h).
>
> The .ustring event filters (test_ustring() in
> kernel/trace/trace_events_filter.c).
>
> Synthetic event string fields (trace_string() in
> kernel/trace/trace_events_synth.c).
>
> The bpf_copy_from_user_str_dynptr family (copy_user_str_nofault()).
>
> Before this patch these calls either failed quietly with -EFAULT or read the
> lazily loaded mm. Now a tracing user (CAP_BPF plus CAP_PERFMON, or tracefs
> access) can trigger a warning splat, and a panic with panic_on_warn, just by
> tracing a function that kernel threads run.
>
> The same applies to copy_to_user_iter_nofault() in lib/iov_iter.c, which this
> patch also switches to uaccess_should_fail(). The commit message lists
> copy_to_user_nofault() as intentionally covered, but it does not account for
> the nofault helpers being used from mm-less contexts by design.
>
> A fix appears later in the series, e8bf23b5b30d ("uaccess: Fail user nofault
> helpers quietly when current->mm is NULL"). It adds an early !current->mm
> return to copy_{from,to}_user_nofault(), strncpy_from_user_nofault() and
> strnlen_user_nofault(), and switches copy_to_user_iter_nofault() back to
> should_fail_usercopy(). Its message describes this exact problem
> (bpf_probe_read_user_str() from a BPF program attached to a function called
> by a kernel thread would now trip the WARN_ON_ONCE() in
> strncpy_from_user()).
>
> This commit on its own still introduces the regression, which breaks
> bisection. Could that fix be folded into this patch, or ordered before it?
Ah, yes. I'll flip the order of patch 6 and 7 in the v2. Thanks.
Okay, the xtensa/nios2 patch is here:
-------
xtensa, nios2: Don't use __copy_{from,to}_user() in __{get,put}_user()
Architectures that don't define __get_kernel_nofault() or
arch_get_kernel_nofault() use the generic fallback in
include/linux/uaccess.h, which accesses *kernel* addresses with
__get_user() and __put_user(). That relies on __get_user() and
__put_user() being raw accessors, i.e. plain fixup-protected loads and
stores with no extra checks that only make sense for user memory.
xtensa and nios2 use this fallback, but don't quite meet that: on
xtensa, 8-byte __get_user() and __put_user() are implemented with
__copy_from_user() and __copy_to_user(), and on nios2, __put_user() of
any size other than 1, 2 or 4 bytes (i.e. 8-byte puts) uses
__copy_to_user(). __copy_{from,to}_user() do more than a plain copy: they
inject failures with CONFIG_FAULT_INJECTION_USERCOPY, check the kernel
object size with CONFIG_HARDENED_USERCOPY, and, with a later patch in
this series, refuse and warn on user accesses when current->mm is NULL.
As neither architecture selects HAVE_EFFICIENT_UNALIGNED_ACCESS,
copy_from_kernel_nofault() and copy_to_kernel_nofault() use 8-byte
accesses when both pointers are 8-byte aligned, so kernel nofault
accesses (used e.g. by d_path() and print_worker_info()) end up in
__copy_{from,to}_user() on kernel addresses. With the NULL mm check,
copy_from_kernel_nofault() would then fail on valid kernel memory when
called from kernel threads.
Use raw_copy_{from,to}_user() instead, as asm-generic's
__get_user_fn()/__put_user_fn() do, and as nios2 already does for 8-byte
gets (__get_user_8()). This only drops the extra checks and KASAN/KCSAN
instrumentation for 8-byte accesses, making them consistent with the 1,
2 and 4-byte cases, which are plain inline asm.
The fallback itself is fine and is still needed: it's used by alpha,
arc, csky, hexagon, microblaze, nios2, openrisc, sh, sparc and xtensa.
Of those, only xtensa and nios2 have __get_user()/__put_user() that
aren't raw. The others use either asm-generic's, which call
raw_copy_{from,to}_user(), or inline asm for all sizes. The remaining
architectures (arm, arm64, loongarch, m68k, mips, parisc, powerpc,
riscv, s390, um and x86) define their own __get_kernel_nofault() or
arch_get_kernel_nofault(), which don't use __get_user()/__put_user() or
__copy_{from,to}_user().
Signed-off-by: James Houghton <jthoughton@google.com>
diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h
index 5e6e05cc6efc..f20f11bd21dc 100644
--- a/arch/nios2/include/asm/uaccess.h
+++ b/arch/nios2/include/asm/uaccess.h
@@ -161,7 +161,7 @@ do { \
default: \
/* XXX: This looks wrong... */ \
__pu_err = 0; \
- if (__copy_to_user(__pu_ptr, &(__pu_val), \
+ if (raw_copy_to_user(__pu_ptr, &(__pu_val), \
sizeof(*__pu_ptr))) \
__pu_err = -EFAULT; \
break; \
diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h
index 6538a29a2bbd..30c8805d1c83 100644
--- a/arch/xtensa/include/asm/uaccess.h
+++ b/arch/xtensa/include/asm/uaccess.h
@@ -76,7 +76,7 @@ do { \
case 4: __put_user_asm(x, ptr, retval, 4, "s32i", __cb); break; \
case 8: { \
__typeof__(*ptr) __v64 = x; \
- retval = __copy_to_user(ptr, &__v64, 8) ? -EFAULT : 0; \
+ retval = raw_copy_to_user(ptr, &__v64, 8) ? -EFAULT : 0; \
break; \
} \
default: __put_user_bad(); \
@@ -176,7 +176,7 @@ do { \
case 4: __get_user_asm(x, ptr, retval, 4, "l32i", __cb); break;\
case 8: { \
u64 __x; \
- if (unlikely(__copy_from_user(&__x, ptr, 8))) { \
+ if (unlikely(raw_copy_from_user(&__x, ptr, 8))) { \
retval = -EFAULT; \
(x) = (__typeof__(*(ptr)))0; \
} else { \
next prev parent reply other threads:[~2026-10-26 23:41 UTC|newest]
Thread overview: 25+ 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-27 11:09 ` Peter Zijlstra
2026-10-26 21:52 ` [RFC PATCH 06/10] uaccess: Refuse and warn on user copies when current->mm is NULL James Houghton
2026-10-26 22:42 ` bot+bpf-ci
2026-10-26 23:41 ` James Houghton [this message]
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=20261026234155.4028467-1-jthoughton@google.com \
--to=jthoughton@google.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=acme@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=arnd@arndb.de \
--cc=asml.silence@gmail.com \
--cc=ast@kernel.org \
--cc=axboe@kernel.dk \
--cc=bot+bpf-ci@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=david@kernel.org \
--cc=dsterba@suse.com \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--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=martin.lau@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 \
--cc=yonghong.song@linux.dev \
/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®