Skip to content

Commit 1fd96a3

Browse files
AndybnACTpalmer-dabbelt
authored andcommitted
riscv: Add prctl controls for userspace vector management
This patch add two riscv-specific prctls, to allow usespace control the use of vector unit: * PR_RISCV_V_SET_CONTROL: control the permission to use Vector at next, or all following execve for a thread. Turning off a thread's Vector live is not possible since libraries may have registered ifunc that may execute Vector instructions. * PR_RISCV_V_GET_CONTROL: get the same permission setting for the current thread, and the setting for following execve(s). Signed-off-by: Andy Chiu <[email protected]> Reviewed-by: Greentime Hu <[email protected]> Reviewed-by: Vincent Chen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 50724ef commit 1fd96a3

File tree

8 files changed

+162
-1
lines changed

8 files changed

+162
-1
lines changed

arch/riscv/include/asm/processor.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct thread_struct {
4040
unsigned long s[12]; /* s[0]: frame pointer */
4141
struct __riscv_d_ext_state fstate;
4242
unsigned long bad_cause;
43+
unsigned long vstate_ctrl;
4344
struct __riscv_v_ext_state vstate;
4445
};
4546

@@ -83,6 +84,15 @@ extern void riscv_fill_hwcap(void);
8384
extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
8485

8586
extern unsigned long signal_minsigstksz __ro_after_init;
87+
88+
#ifdef CONFIG_RISCV_ISA_V
89+
/* Userspace interface for PR_RISCV_V_{SET,GET}_VS prctl()s: */
90+
#define RISCV_V_SET_CONTROL(arg) riscv_v_vstate_ctrl_set_current(arg)
91+
#define RISCV_V_GET_CONTROL() riscv_v_vstate_ctrl_get_current()
92+
extern long riscv_v_vstate_ctrl_set_current(unsigned long arg);
93+
extern long riscv_v_vstate_ctrl_get_current(void);
94+
#endif /* CONFIG_RISCV_ISA_V */
95+
8696
#endif /* __ASSEMBLY__ */
8797

8898
#endif /* _ASM_RISCV_PROCESSOR_H */

arch/riscv/include/asm/vector.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ static inline void __switch_to_vector(struct task_struct *prev,
160160
riscv_v_vstate_restore(next, task_pt_regs(next));
161161
}
162162

163+
void riscv_v_vstate_ctrl_init(struct task_struct *tsk);
164+
bool riscv_v_vstate_ctrl_user_allowed(void);
165+
163166
#else /* ! CONFIG_RISCV_ISA_V */
164167

165168
struct pt_regs;
@@ -168,6 +171,7 @@ static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
168171
static __always_inline bool has_vector(void) { return false; }
169172
static inline bool riscv_v_first_use_handler(struct pt_regs *regs) { return false; }
170173
static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; }
174+
static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
171175
#define riscv_v_vsize (0)
172176
#define riscv_v_vstate_save(task, regs) do {} while (0)
173177
#define riscv_v_vstate_restore(task, regs) do {} while (0)

arch/riscv/kernel/cpufeature.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,14 @@ void __init riscv_fill_hwcap(void)
295295

296296
unsigned long riscv_get_elf_hwcap(void)
297297
{
298-
return (elf_hwcap & ((1UL << RISCV_ISA_EXT_BASE) - 1));
298+
unsigned long hwcap;
299+
300+
hwcap = (elf_hwcap & ((1UL << RISCV_ISA_EXT_BASE) - 1));
301+
302+
if (!riscv_v_vstate_ctrl_user_allowed())
303+
hwcap &= ~COMPAT_HWCAP_ISA_V;
304+
305+
return hwcap;
299306
}
300307

301308
#ifdef CONFIG_RISCV_ALTERNATIVE

arch/riscv/kernel/process.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void flush_thread(void)
149149
#endif
150150
#ifdef CONFIG_RISCV_ISA_V
151151
/* Reset vector state */
152+
riscv_v_vstate_ctrl_init(current);
152153
riscv_v_vstate_off(task_pt_regs(current));
153154
kfree(current->thread.vstate.datap);
154155
memset(&current->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));

arch/riscv/kernel/vector.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/slab.h>
1010
#include <linux/sched.h>
1111
#include <linux/uaccess.h>
12+
#include <linux/prctl.h>
1213

1314
#include <asm/thread_info.h>
1415
#include <asm/processor.h>
@@ -19,6 +20,8 @@
1920
#include <asm/ptrace.h>
2021
#include <asm/bug.h>
2122

23+
static bool riscv_v_implicit_uacc = IS_ENABLED(CONFIG_RISCV_ISA_V_DEFAULT_ENABLE);
24+
2225
unsigned long riscv_v_vsize __read_mostly;
2326
EXPORT_SYMBOL_GPL(riscv_v_vsize);
2427

@@ -91,6 +94,43 @@ static int riscv_v_thread_zalloc(void)
9194
return 0;
9295
}
9396

97+
#define VSTATE_CTRL_GET_CUR(x) ((x) & PR_RISCV_V_VSTATE_CTRL_CUR_MASK)
98+
#define VSTATE_CTRL_GET_NEXT(x) (((x) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2)
99+
#define VSTATE_CTRL_MAKE_NEXT(x) (((x) << 2) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK)
100+
#define VSTATE_CTRL_GET_INHERIT(x) (!!((x) & PR_RISCV_V_VSTATE_CTRL_INHERIT))
101+
static inline int riscv_v_ctrl_get_cur(struct task_struct *tsk)
102+
{
103+
return VSTATE_CTRL_GET_CUR(tsk->thread.vstate_ctrl);
104+
}
105+
106+
static inline int riscv_v_ctrl_get_next(struct task_struct *tsk)
107+
{
108+
return VSTATE_CTRL_GET_NEXT(tsk->thread.vstate_ctrl);
109+
}
110+
111+
static inline bool riscv_v_ctrl_test_inherit(struct task_struct *tsk)
112+
{
113+
return VSTATE_CTRL_GET_INHERIT(tsk->thread.vstate_ctrl);
114+
}
115+
116+
static inline void riscv_v_ctrl_set(struct task_struct *tsk, int cur, int nxt,
117+
bool inherit)
118+
{
119+
unsigned long ctrl;
120+
121+
ctrl = cur & PR_RISCV_V_VSTATE_CTRL_CUR_MASK;
122+
ctrl |= VSTATE_CTRL_MAKE_NEXT(nxt);
123+
if (inherit)
124+
ctrl |= PR_RISCV_V_VSTATE_CTRL_INHERIT;
125+
tsk->thread.vstate_ctrl = ctrl;
126+
}
127+
128+
bool riscv_v_vstate_ctrl_user_allowed(void)
129+
{
130+
return riscv_v_ctrl_get_cur(current) == PR_RISCV_V_VSTATE_CTRL_ON;
131+
}
132+
EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed);
133+
94134
bool riscv_v_first_use_handler(struct pt_regs *regs)
95135
{
96136
u32 __user *epc = (u32 __user *)regs->epc;
@@ -129,3 +169,77 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
129169
riscv_v_vstate_on(regs);
130170
return true;
131171
}
172+
173+
void riscv_v_vstate_ctrl_init(struct task_struct *tsk)
174+
{
175+
bool inherit;
176+
int cur, next;
177+
178+
if (!has_vector())
179+
return;
180+
181+
next = riscv_v_ctrl_get_next(tsk);
182+
if (!next) {
183+
if (riscv_v_implicit_uacc)
184+
cur = PR_RISCV_V_VSTATE_CTRL_ON;
185+
else
186+
cur = PR_RISCV_V_VSTATE_CTRL_OFF;
187+
} else {
188+
cur = next;
189+
}
190+
/* Clear next mask if inherit-bit is not set */
191+
inherit = riscv_v_ctrl_test_inherit(tsk);
192+
if (!inherit)
193+
next = PR_RISCV_V_VSTATE_CTRL_DEFAULT;
194+
195+
riscv_v_ctrl_set(tsk, cur, next, inherit);
196+
}
197+
198+
long riscv_v_vstate_ctrl_get_current(void)
199+
{
200+
if (!has_vector())
201+
return -EINVAL;
202+
203+
return current->thread.vstate_ctrl & PR_RISCV_V_VSTATE_CTRL_MASK;
204+
}
205+
206+
long riscv_v_vstate_ctrl_set_current(unsigned long arg)
207+
{
208+
bool inherit;
209+
int cur, next;
210+
211+
if (!has_vector())
212+
return -EINVAL;
213+
214+
if (arg & ~PR_RISCV_V_VSTATE_CTRL_MASK)
215+
return -EINVAL;
216+
217+
cur = VSTATE_CTRL_GET_CUR(arg);
218+
switch (cur) {
219+
case PR_RISCV_V_VSTATE_CTRL_OFF:
220+
/* Do not allow user to turn off V if current is not off */
221+
if (riscv_v_ctrl_get_cur(current) != PR_RISCV_V_VSTATE_CTRL_OFF)
222+
return -EPERM;
223+
224+
break;
225+
case PR_RISCV_V_VSTATE_CTRL_ON:
226+
break;
227+
case PR_RISCV_V_VSTATE_CTRL_DEFAULT:
228+
cur = riscv_v_ctrl_get_cur(current);
229+
break;
230+
default:
231+
return -EINVAL;
232+
}
233+
234+
next = VSTATE_CTRL_GET_NEXT(arg);
235+
inherit = VSTATE_CTRL_GET_INHERIT(arg);
236+
switch (next) {
237+
case PR_RISCV_V_VSTATE_CTRL_DEFAULT:
238+
case PR_RISCV_V_VSTATE_CTRL_OFF:
239+
case PR_RISCV_V_VSTATE_CTRL_ON:
240+
riscv_v_ctrl_set(current, cur, next, inherit);
241+
return 0;
242+
}
243+
244+
return -EINVAL;
245+
}

arch/riscv/kvm/vcpu.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext)
8888
switch (ext) {
8989
case KVM_RISCV_ISA_EXT_H:
9090
return false;
91+
case KVM_RISCV_ISA_EXT_V:
92+
return riscv_v_vstate_ctrl_user_allowed();
9193
default:
9294
break;
9395
}

include/uapi/linux/prctl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,15 @@ struct prctl_mm_map {
294294

295295
#define PR_SET_MEMORY_MERGE 67
296296
#define PR_GET_MEMORY_MERGE 68
297+
298+
#define PR_RISCV_V_SET_CONTROL 69
299+
#define PR_RISCV_V_GET_CONTROL 70
300+
# define PR_RISCV_V_VSTATE_CTRL_DEFAULT 0
301+
# define PR_RISCV_V_VSTATE_CTRL_OFF 1
302+
# define PR_RISCV_V_VSTATE_CTRL_ON 2
303+
# define PR_RISCV_V_VSTATE_CTRL_INHERIT (1 << 4)
304+
# define PR_RISCV_V_VSTATE_CTRL_CUR_MASK 0x3
305+
# define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc
306+
# define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f
307+
297308
#endif /* _LINUX_PRCTL_H */

kernel/sys.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@
140140
#ifndef GET_TAGGED_ADDR_CTRL
141141
# define GET_TAGGED_ADDR_CTRL() (-EINVAL)
142142
#endif
143+
#ifndef RISCV_V_SET_CONTROL
144+
# define RISCV_V_SET_CONTROL(a) (-EINVAL)
145+
#endif
146+
#ifndef RISCV_V_GET_CONTROL
147+
# define RISCV_V_GET_CONTROL() (-EINVAL)
148+
#endif
143149

144150
/*
145151
* this is where the system-wide overflow UID and GID are defined, for
@@ -2708,6 +2714,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
27082714
error = !!test_bit(MMF_VM_MERGE_ANY, &me->mm->flags);
27092715
break;
27102716
#endif
2717+
case PR_RISCV_V_SET_CONTROL:
2718+
error = RISCV_V_SET_CONTROL(arg2);
2719+
break;
2720+
case PR_RISCV_V_GET_CONTROL:
2721+
error = RISCV_V_GET_CONTROL();
2722+
break;
27112723
default:
27122724
error = -EINVAL;
27132725
break;

0 commit comments

Comments
 (0)