[PATCH 2/3] riscv: Deprecate vector state prctl/sysctl

From: Samuel Holland

Date: Wed Oct 07 2026 - 04:54:44 EST


The ability to prevent userspace from executing vector instructions was
provided as a escape hatch for software that was broken by adding vector
state to the signal context. This appears to be unused in practice, and
creates confusion in the extension support returned by hwprobe(), as in
this one special case an extension reported as present by hwprobe() is
unusable.

Since we believe it is safe to always allow vector usage, hide the prctl
and sysctl behind a Kconfig option and mark them as deprecated, so they
can be removed in the future. Note that significant userspace software
like glibc already considers these controls explicitly unsupported.

Signed-off-by: Samuel Holland <samuel.holland@xxxxxxxxxx>
---

arch/riscv/Kconfig | 10 ++++++++++
arch/riscv/include/asm/processor.h | 4 +++-
arch/riscv/include/asm/vector.h | 16 ++++++++++++----
arch/riscv/kernel/vector.c | 10 ++++++++++
4 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index e26450f0d38fb..83e52a0a85ba7 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -650,6 +650,16 @@ config RISCV_ISA_V

If you don't know what to do here, say Y.

+config RISCV_ISA_V_VSTATE_CTRL
+ bool "Deprecated prctl/sysctl for disallowing userspace vector access"
+ depends on RISCV_ISA_V
+ help
+ Add prctl and sysctl interfaces to disallow userspace to execute
+ vector instructions. These controls are deprecated because they create
+ ambiguity in the ISA extension availability reported by hwprobe.
+
+ If you don't know what to do here, say N.
+
config RISCV_ISA_V_UCOPY_THRESHOLD
int "Threshold size for vectorized user copies"
depends on RISCV_ISA_V
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 815715c67f940..ad64df01417a2 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -121,7 +121,9 @@ struct thread_struct {
unsigned long envcfg;
unsigned long sum;
u32 riscv_v_flags;
+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
u32 vstate_ctrl;
+#endif
struct __riscv_v_ext_state vstate;
unsigned long align_ctl;
struct __riscv_v_ext_state kernel_vstate;
@@ -202,7 +204,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src

extern unsigned long signal_minsigstksz __ro_after_init;

-#ifdef CONFIG_RISCV_ISA_V
+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
/* Userspace interface for PR_RISCV_V_{SET,GET}_VS prctl()s: */
#define RISCV_V_SET_CONTROL(arg) riscv_v_vstate_ctrl_set_current(arg)
#define RISCV_V_GET_CONTROL() riscv_v_vstate_ctrl_get_current()
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index fffe72a772080..5425a25f8a196 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -404,9 +404,6 @@ static inline void __switch_to_vector(struct task_struct *prev,
}
}

-void riscv_v_vstate_ctrl_init(struct task_struct *tsk);
-bool riscv_v_vstate_ctrl_user_allowed(void);
-
#else /* ! CONFIG_RISCV_ISA_V */

struct pt_regs;
@@ -418,7 +415,6 @@ static __always_inline bool has_xtheadvector_no_alternatives(void) { return fals
static __always_inline bool has_xtheadvector(void) { return false; }
static inline bool riscv_v_first_use_handler(struct pt_regs *regs) { return false; }
static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; }
-static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
#define riscv_v_vsize (0)
#define riscv_v_vstate_discard(regs) do {} while (0)
#define riscv_v_vstate_save(vstate, regs) do {} while (0)
@@ -435,6 +431,18 @@ static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }

#endif /* CONFIG_RISCV_ISA_V */

+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
+
+void riscv_v_vstate_ctrl_init(struct task_struct *tsk);
+bool riscv_v_vstate_ctrl_user_allowed(void);
+
+#else
+
+static inline void riscv_v_vstate_ctrl_init(struct task_struct *tsk) {}
+static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return true; }
+
+#endif /* CONFIG_RISCV_ISA_V_VSTATE_CTRL */
+
/*
* Return the implementation's vlen value.
*
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 9641343732782..b35d11ff3cc89 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -20,7 +20,9 @@
#include <asm/ptrace.h>
#include <asm/bug.h>

+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
static bool riscv_v_implicit_uacc = true;
+#endif
static struct kmem_cache *riscv_v_user_cachep;
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
static struct kmem_cache *riscv_v_kernel_cachep;
@@ -144,6 +146,8 @@ void riscv_v_thread_free(struct task_struct *tsk)
#endif
}

+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
+
#define VSTATE_CTRL_GET_CUR(x) ((x) & PR_RISCV_V_VSTATE_CTRL_CUR_MASK)
#define VSTATE_CTRL_GET_NEXT(x) (((x) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2)
#define VSTATE_CTRL_MAKE_NEXT(x) (((x) << 2) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK)
@@ -182,6 +186,8 @@ bool riscv_v_vstate_ctrl_user_allowed(void)
}
EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed);

+#endif
+
bool riscv_v_first_use_handler(struct pt_regs *regs)
{
u32 __user *epc = (u32 __user *)regs->epc;
@@ -227,6 +233,8 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
return true;
}

+#ifdef CONFIG_RISCV_ISA_V_VSTATE_CTRL
+
void riscv_v_vstate_ctrl_init(struct task_struct *tsk)
{
bool inherit;
@@ -330,3 +338,5 @@ static int __init riscv_v_init(void)
return riscv_v_sysctl_init();
}
core_initcall(riscv_v_init);
+
+#endif
--
2.52.0