All of lore.kernel.org
 help / color / mirror / Atom feed
From: cp0613@linux.alibaba.com
To: wangruikang@iscas.ac.cn
Cc: pjw@kernel.org, alex@ghiti.fr, cleger@rivosinc.com,
	alexghiti@rivosinc.com, guoren@kernel.org,
	linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] riscv: mm: Implement arch_within_stack_frames() for HARDENED_USERCOPY
Date: Fri, 10 Apr 2026 20:26:07 +0800	[thread overview]
Message-ID: <20260410122607.118282-1-cp0613@linux.alibaba.com> (raw)
In-Reply-To: <c95d9003-58e5-46d2-ba5b-5d32a8743f1d@iscas.ac.cn>

Hi Vivian,

Thank you very much for your review and suggestions.

On Fri, 10 Apr 2026 15:25:54 +0800, wangruikang@iscas.ac.cn wrote:

> On 4/10/26 09:50, cp0613@linux.alibaba.com wrote:
> > From: Chen Pei <cp0613@linux.alibaba.com>
> >
> > Implement arch_within_stack_frames() to enable precise per-frame stack
> > object validation for CONFIG_HARDENED_USERCOPY on RISC-V.
> >
> > == Background ==
> >
> > [...]
> >
> > Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
> 
> Patch message is probably too long. You can put additional information
> like testing under a --- line to cut those out of the eventual actual
> commit message.
> 
> Make sure that Signed-off-by is above the cut if you do that.

Okay, that's really helpful advice, I've learned a lot.

> > ---
> >  arch/riscv/Kconfig                   |  1 +
> >  arch/riscv/include/asm/thread_info.h | 66 ++++++++++++++++++++++++++++
> >  2 files changed, 67 insertions(+)
> >
> > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> > index 6fe90591a274..4f765ff608d9 100644
> > --- a/arch/riscv/Kconfig
> > +++ b/arch/riscv/Kconfig
> > @@ -150,6 +150,7 @@ config RISCV
> >  	select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD
> >  	select HAVE_ARCH_USERFAULTFD_WP if 64BIT && MMU && USERFAULTFD && RISCV_ISA_SVRSW60T59B
> >  	select HAVE_ARCH_VMAP_STACK if MMU && 64BIT
> > +	select HAVE_ARCH_WITHIN_STACK_FRAMES
> >  	select HAVE_ASM_MODVERSIONS
> >  	select HAVE_BUILDTIME_MCOUNT_SORT
> >  	select HAVE_CONTEXT_TRACKING_USER
> > diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
> > index 36918c9200c9..616a41eb7416 100644
> > --- a/arch/riscv/include/asm/thread_info.h
> > +++ b/arch/riscv/include/asm/thread_info.h
> > @@ -101,6 +101,72 @@ struct thread_info {
> >  void arch_release_task_struct(struct task_struct *tsk);
> >  int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
> >  
> > +#ifdef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
> 
> Not needed since you've selected it above.

Okay, it seems that it's indeed not necessary.

> > +/*
> > + * RISC-V stack frame layout (with frame pointer enabled):
> > + *
> > + * high addr
> > + *   +------------------+  <--- fp (s0) points here
> > + *   |   saved ra       |  fp - 8  (return address)
> > + *   |   saved fp       |  fp - 16 (previous frame pointer)

> fp - 2*sizeof(void*) probably, to account for RV32?

Yes, You are right. The implementation already uses 2 * sizeof(void *) to
be RV32-compatible. However, the comments still hardcode. I'll update the
comments to use fp - 2*sizeof(void*) to be architecture-neutral.

> > + *   +------------------+
> > + *   |   local vars     |
> > + *   |   arguments      |
> > + *   +------------------+  <--- sp
> > + * low addr
> > + *
> > + * The struct stackframe { fp, ra } lives at (fp - sizeof(stackframe)),
> > + * i.e. fp[-2]=saved_fp and fp[-1]=saved_ra.
> > + *
> 
> Maybe link to the authoritative source:
> 
  > https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#frame-pointer-convention

Okay, I will add this link.

> > + * For usercopy safety, we allow copies within [prev_fp, fp - 2*sizeof(void*))
> > + * for each frame in the chain, where prev_fp is the fp of the previous
> > + * (lower) frame.  This covers local variables and arguments but excludes
> > + * the saved ra/fp slots at the top of the frame.
> > + *
> > + * We walk the frame chain starting from __builtin_frame_address(0) (the
> > + * current frame), with prev_fp initialized to current_stack_pointer.
> > + * Using current_stack_pointer -- rather than the 'stack' argument (which is
> > + * the thread's entire stack base) -- ensures that objects in already-returned
> > + * frames (address below current sp) are correctly detected as BAD_STACK,
> > + * because no live frame in the chain will claim that region.
> > + */
> > +__no_kmsan_checks
> > +static inline int arch_within_stack_frames(const void * const stack,
> > +					   const void * const stackend,
> > +					   const void *obj, unsigned long len)
> > +{
> > +#if defined(CONFIG_FRAME_POINTER)
> > +	const void *fp = (const void *)__builtin_frame_address(0);
> > +	const void *prev_fp = (const void *)current_stack_pointer;
> > +
> > +	/*
> > +	 * Walk the frame chain. Each iteration checks whether [obj, obj+len)
> > +	 * falls within the local-variable area of the current frame:
> > +	 *
> > +	 *   [prev_fp, fp - 2*sizeof(void*))
> > +	 *
> > +	 * i.e. from the base of this frame (sp of this frame, which equals
> > +	 * the fp of the frame below) up to (but not including) the saved
> > +	 * fp/ra area at the top of this frame.
> > +	 */
> > +	while (stack <= fp && fp < stackend) {
> 
> Since we access fp - 2 * sizeof(void *) below, this probably should be
> something like this:
> 
    > while (stack + 2 * sizeof(void *) <= fp && fp < stackend) {
> 
> (Possibly with some casts added.)

Thank you for pointing it out; I hadn't considered the potential for
boundary violations here.

> > +		const void *frame_vars_end = (const char *)fp - 2 * sizeof(void *);
> > +
> > +		if (obj + len <= frame_vars_end) {
> > +			if (obj >= prev_fp)
> > +				return GOOD_FRAME;
> > +			return BAD_STACK;
> > +		}
> > +		prev_fp = fp;
> > +		fp = *(const void * const *)((const char *)fp - 2 * sizeof(void *));
> 
> Maybe: fp = *(const void * const *)frame_vars_end;

Yes, direct reuse.

> > +	}
> > +	return BAD_STACK;
> > +#else
> > +	return NOT_STACK;
> > +#endif
> > +}
> > +#endif /* CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES */
> > +
> >  #endif /* !__ASSEMBLER__ */
> >  
> >  /*

> Thanks,
> Vivian "dramforever" Wang

Thanks,
Pei

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

      reply	other threads:[~2026-04-10 12:26 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-10  1:50 [PATCH] riscv: mm: Implement arch_within_stack_frames() for HARDENED_USERCOPY cp0613
2026-04-10  7:25 ` Vivian Wang
2026-04-10 12:26   ` cp0613 [this message]

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=20260410122607.118282-1-cp0613@linux.alibaba.com \
    --to=cp0613@linux.alibaba.com \
    --cc=alex@ghiti.fr \
    --cc=alexghiti@rivosinc.com \
    --cc=cleger@rivosinc.com \
    --cc=guoren@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=pjw@kernel.org \
    --cc=wangruikang@iscas.ac.cn \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.