public inbox for linux-riscv@lists.infradead.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox