public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
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 {						\

  reply	other threads:[~2026-10-26 23:41 UTC|newest]

Thread overview: 23+ 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 when current->mm is NULL 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 ` [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

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