[PATCH v5 2/9] riscv: vector: init vector context with proper vlenb

Sergey Matyukevich posted 9 patches 1 month, 3 weeks ago
[PATCH v5 2/9] riscv: vector: init vector context with proper vlenb
Posted by Sergey Matyukevich 1 month, 3 weeks ago
The vstate in thread_struct is zeroed when the vector context is
initialized. That includes read-only register vlenb, which holds
the vector register length in bytes. Zeroed state persists until
mstatus.VS becomes 'dirty' and a context switch saves the actual
hardware values.

This can expose the zero vlenb value to the user-space in early
debug scenarios, e.g. when ptrace attaches to a traced process
early, before any vector instruction except the first one was
executed.

Fix this by specifying proper vlenb on vector context init.

Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
---
 arch/riscv/kernel/vector.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 3ed071dab9d8..b112166d51e9 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -111,8 +111,8 @@ bool insn_is_vector(u32 insn_buf)
 	return false;
 }
 
-static int riscv_v_thread_zalloc(struct kmem_cache *cache,
-				 struct __riscv_v_ext_state *ctx)
+static int riscv_v_thread_ctx_alloc(struct kmem_cache *cache,
+				    struct __riscv_v_ext_state *ctx)
 {
 	void *datap;
 
@@ -122,13 +122,15 @@ static int riscv_v_thread_zalloc(struct kmem_cache *cache,
 
 	ctx->datap = datap;
 	memset(ctx, 0, offsetof(struct __riscv_v_ext_state, datap));
+	ctx->vlenb = riscv_v_vsize / 32;
+
 	return 0;
 }
 
 void riscv_v_thread_alloc(struct task_struct *tsk)
 {
 #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
-	riscv_v_thread_zalloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate);
+	riscv_v_thread_ctx_alloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate);
 #endif
 }
 
@@ -214,12 +216,14 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
 	 * context where VS has been off. So, try to allocate the user's V
 	 * context and resume execution.
 	 */
-	if (riscv_v_thread_zalloc(riscv_v_user_cachep, &current->thread.vstate)) {
+	if (riscv_v_thread_ctx_alloc(riscv_v_user_cachep, &current->thread.vstate)) {
 		force_sig(SIGBUS);
 		return true;
 	}
+
 	riscv_v_vstate_on(regs);
 	riscv_v_vstate_set_restore(current, regs);
+
 	return true;
 }
 
-- 
2.52.0
Re: [PATCH v5 2/9] riscv: vector: init vector context with proper vlenb
Posted by Andy Chiu 1 month ago
On Sun, Dec 14, 2025 at 10:35 AM Sergey Matyukevich <geomatsi@gmail.com> wrote:
>
> The vstate in thread_struct is zeroed when the vector context is
> initialized. That includes read-only register vlenb, which holds
> the vector register length in bytes. Zeroed state persists until
> mstatus.VS becomes 'dirty' and a context switch saves the actual
> hardware values.
>
> This can expose the zero vlenb value to the user-space in early
> debug scenarios, e.g. when ptrace attaches to a traced process
> early, before any vector instruction except the first one was
> executed.
>
> Fix this by specifying proper vlenb on vector context init.
>
> Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>

Reviewed-by: Andy Chiu <andybnac@gmail.com>

> ---
>  arch/riscv/kernel/vector.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 3ed071dab9d8..b112166d51e9 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -111,8 +111,8 @@ bool insn_is_vector(u32 insn_buf)
>         return false;
>  }
>
> -static int riscv_v_thread_zalloc(struct kmem_cache *cache,
> -                                struct __riscv_v_ext_state *ctx)
> +static int riscv_v_thread_ctx_alloc(struct kmem_cache *cache,
> +                                   struct __riscv_v_ext_state *ctx)
>  {
>         void *datap;
>
> @@ -122,13 +122,15 @@ static int riscv_v_thread_zalloc(struct kmem_cache *cache,
>
>         ctx->datap = datap;
>         memset(ctx, 0, offsetof(struct __riscv_v_ext_state, datap));
> +       ctx->vlenb = riscv_v_vsize / 32;
> +
>         return 0;
>  }
>
>  void riscv_v_thread_alloc(struct task_struct *tsk)
>  {
>  #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
> -       riscv_v_thread_zalloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate);
> +       riscv_v_thread_ctx_alloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate);
>  #endif
>  }
>
> @@ -214,12 +216,14 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
>          * context where VS has been off. So, try to allocate the user's V
>          * context and resume execution.
>          */
> -       if (riscv_v_thread_zalloc(riscv_v_user_cachep, &current->thread.vstate)) {
> +       if (riscv_v_thread_ctx_alloc(riscv_v_user_cachep, &current->thread.vstate)) {
>                 force_sig(SIGBUS);
>                 return true;
>         }
> +
>         riscv_v_vstate_on(regs);
>         riscv_v_vstate_set_restore(current, regs);
> +
>         return true;
>  }
>
> --
> 2.52.0
>
Re: [PATCH v5 2/9] riscv: vector: init vector context with proper vlenb
Posted by Sergey Matyukevich 2 weeks, 4 days ago
Hi,

On Wed, Jan 07, 2026 at 12:49:31AM -0600, Andy Chiu wrote:
> On Sun, Dec 14, 2025 at 10:35 AM Sergey Matyukevich <geomatsi@gmail.com> wrote:
> >
> > The vstate in thread_struct is zeroed when the vector context is
> > initialized. That includes read-only register vlenb, which holds
> > the vector register length in bytes. Zeroed state persists until
> > mstatus.VS becomes 'dirty' and a context switch saves the actual
> > hardware values.
> >
> > This can expose the zero vlenb value to the user-space in early
> > debug scenarios, e.g. when ptrace attaches to a traced process
> > early, before any vector instruction except the first one was
> > executed.
> >
> > Fix this by specifying proper vlenb on vector context init.
> >
> > Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
> 
> Reviewed-by: Andy Chiu <andybnac@gmail.com>
> 

Thanks for reviews !

What would be the recommended way to proceed with these patches ?
I have reviews from Andy for the patches 1,2 and 5 (selftest for 2).
They can be used independently of the remainig ptrace v-state
validation changes and their tests.

Would it make sense to split the series into two parts, so that
the v-state validation can continue evolve independently ?

Regards,
Sergey