Skip to content

Commit c9b859c

Browse files
deepak0414Paul Walmsley
authored andcommitted
riscv: add kernel command line option to opt out of user CFI
Add a kernel command line option to disable part or all of user CFI. User backward CFI and forward CFI can be controlled independently. The kernel command line parameter "riscv_nousercfi" can take the following values: - "all" : Disable forward and backward cfi both - "bcfi" : Disable backward cfi - "fcfi" : Disable forward cfi Signed-off-by: Deepak Gupta <debug@rivosinc.com> Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de> # QEMU, custom CVA6 Tested-by: Valentin Haudiquet <valentin.haudiquet@canonical.com> Link: https://patch.msgid.link/20251112-v5_user_cfi_series-v23-21-b55691eacf4f@rivosinc.com [pjw@kernel.org: fixed warnings from checkpatch; cleaned up patch description, doc, printk text] Signed-off-by: Paul Walmsley <pjw@kernel.org>
1 parent 30c3099 commit c9b859c

4 files changed

Lines changed: 69 additions & 13 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6606,6 +6606,14 @@ Kernel parameters
66066606
replacement properties are not found. See the Kconfig
66076607
entry for RISCV_ISA_FALLBACK.
66086608

6609+
riscv_nousercfi=
6610+
all Disable user CFI ABI to userspace even if cpu extension
6611+
are available.
6612+
bcfi Disable user backward CFI ABI to userspace even if
6613+
the shadow stack extension is available.
6614+
fcfi Disable user forward CFI ABI to userspace even if the
6615+
landing pad extension is available.
6616+
66096617
ro [KNL] Mount root device read-only on boot
66106618

66116619
rodata= [KNL,EARLY]

arch/riscv/include/asm/usercfi.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
#ifndef _ASM_RISCV_USERCFI_H
66
#define _ASM_RISCV_USERCFI_H
77

8+
#define CMDLINE_DISABLE_RISCV_USERCFI_FCFI 1
9+
#define CMDLINE_DISABLE_RISCV_USERCFI_BCFI 2
10+
#define CMDLINE_DISABLE_RISCV_USERCFI 3
11+
812
#ifndef __ASSEMBLER__
913
#include <linux/types.h>
1014
#include <linux/prctl.h>
@@ -13,6 +17,8 @@
1317
struct task_struct;
1418
struct kernel_clone_args;
1519

20+
extern unsigned long riscv_nousercfi;
21+
1622
#ifdef CONFIG_RISCV_USER_CFI
1723
struct cfi_state {
1824
unsigned long ubcfi_en : 1; /* Enable for backward cfi. */
@@ -83,6 +89,9 @@ void set_indir_lp_lock(struct task_struct *task);
8389

8490
#endif /* CONFIG_RISCV_USER_CFI */
8591

92+
bool is_user_shstk_enabled(void);
93+
bool is_user_lpad_enabled(void);
94+
8695
#endif /* __ASSEMBLER__ */
8796

8897
#endif /* _ASM_RISCV_USERCFI_H */

arch/riscv/kernel/cpufeature.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <asm/vector.h>
2929
#include <asm/vendor_extensions.h>
3030
#include <asm/vendor_extensions/thead.h>
31+
#include <asm/usercfi.h>
3132

3233
#define NUM_ALPHA_EXTS ('z' - 'a' + 1)
3334

@@ -299,7 +300,8 @@ static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
299300
static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
300301
const unsigned long *isa_bitmap)
301302
{
302-
if (!IS_ENABLED(CONFIG_RISCV_USER_CFI))
303+
if (!IS_ENABLED(CONFIG_RISCV_USER_CFI) ||
304+
(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI))
303305
return -EINVAL;
304306

305307
return 0;
@@ -308,7 +310,8 @@ static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
308310
static int riscv_cfiss_validate(const struct riscv_isa_ext_data *data,
309311
const unsigned long *isa_bitmap)
310312
{
311-
if (!IS_ENABLED(CONFIG_RISCV_USER_CFI))
313+
if (!IS_ENABLED(CONFIG_RISCV_USER_CFI) ||
314+
(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI))
312315
return -EINVAL;
313316

314317
return 0;

arch/riscv/kernel/usercfi.c

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <asm/csr.h>
1818
#include <asm/usercfi.h>
1919

20+
unsigned long riscv_nousercfi __read_mostly;
21+
2022
#define SHSTK_ENTRY_SIZE sizeof(void *)
2123

2224
bool is_shstk_enabled(struct task_struct *task)
@@ -59,7 +61,7 @@ unsigned long get_active_shstk(struct task_struct *task)
5961

6062
void set_shstk_status(struct task_struct *task, bool enable)
6163
{
62-
if (!cpu_supports_shadow_stack())
64+
if (!is_user_shstk_enabled())
6365
return;
6466

6567
task->thread_info.user_cfi_state.ubcfi_en = enable ? 1 : 0;
@@ -89,7 +91,7 @@ bool is_indir_lp_locked(struct task_struct *task)
8991

9092
void set_indir_lp_status(struct task_struct *task, bool enable)
9193
{
92-
if (!cpu_supports_indirect_br_lp_instr())
94+
if (!is_user_lpad_enabled())
9395
return;
9496

9597
task->thread_info.user_cfi_state.ufcfi_en = enable ? 1 : 0;
@@ -257,7 +259,7 @@ SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsi
257259
bool set_tok = flags & SHADOW_STACK_SET_TOKEN;
258260
unsigned long aligned_size = 0;
259261

260-
if (!cpu_supports_shadow_stack())
262+
if (!is_user_shstk_enabled())
261263
return -EOPNOTSUPP;
262264

263265
/* Anything other than set token should result in invalid param */
@@ -304,7 +306,7 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *tsk,
304306
unsigned long addr, size;
305307

306308
/* If shadow stack is not supported, return 0 */
307-
if (!cpu_supports_shadow_stack())
309+
if (!is_user_shstk_enabled())
308310
return 0;
309311

310312
/*
@@ -350,7 +352,7 @@ void shstk_release(struct task_struct *tsk)
350352
{
351353
unsigned long base = 0, size = 0;
352354
/* If shadow stack is not supported or not enabled, nothing to release */
353-
if (!cpu_supports_shadow_stack() || !is_shstk_enabled(tsk))
355+
if (!is_user_shstk_enabled() || !is_shstk_enabled(tsk))
354356
return;
355357

356358
/*
@@ -379,7 +381,7 @@ int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *st
379381
{
380382
unsigned long bcfi_status = 0;
381383

382-
if (!cpu_supports_shadow_stack())
384+
if (!is_user_shstk_enabled())
383385
return -EINVAL;
384386

385387
/* this means shadow stack is enabled on the task */
@@ -393,7 +395,7 @@ int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status)
393395
unsigned long size = 0, addr = 0;
394396
bool enable_shstk = false;
395397

396-
if (!cpu_supports_shadow_stack())
398+
if (!is_user_shstk_enabled())
397399
return -EINVAL;
398400

399401
/* Reject unknown flags */
@@ -446,7 +448,7 @@ int arch_lock_shadow_stack_status(struct task_struct *task,
446448
unsigned long arg)
447449
{
448450
/* If shtstk not supported or not enabled on task, nothing to lock here */
449-
if (!cpu_supports_shadow_stack() ||
451+
if (!is_user_shstk_enabled() ||
450452
!is_shstk_enabled(task) || arg != 0)
451453
return -EINVAL;
452454

@@ -459,7 +461,7 @@ int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *sta
459461
{
460462
unsigned long fcfi_status = 0;
461463

462-
if (!cpu_supports_indirect_br_lp_instr())
464+
if (!is_user_lpad_enabled())
463465
return -EINVAL;
464466

465467
/* indirect branch tracking is enabled on the task or not */
@@ -472,7 +474,7 @@ int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status)
472474
{
473475
bool enable_indir_lp = false;
474476

475-
if (!cpu_supports_indirect_br_lp_instr())
477+
if (!is_user_lpad_enabled())
476478
return -EINVAL;
477479

478480
/* indirect branch tracking is locked and further can't be modified by user */
@@ -496,11 +498,45 @@ int arch_lock_indir_br_lp_status(struct task_struct *task,
496498
* If indirect branch tracking is not supported or not enabled on task,
497499
* nothing to lock here
498500
*/
499-
if (!cpu_supports_indirect_br_lp_instr() ||
501+
if (!is_user_lpad_enabled() ||
500502
!is_indir_lp_enabled(task) || arg != 0)
501503
return -EINVAL;
502504

503505
set_indir_lp_lock(task);
504506

505507
return 0;
506508
}
509+
510+
bool is_user_shstk_enabled(void)
511+
{
512+
return (cpu_supports_shadow_stack() &&
513+
!(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI));
514+
}
515+
516+
bool is_user_lpad_enabled(void)
517+
{
518+
return (cpu_supports_indirect_br_lp_instr() &&
519+
!(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI));
520+
}
521+
522+
static int __init setup_global_riscv_enable(char *str)
523+
{
524+
if (strcmp(str, "all") == 0)
525+
riscv_nousercfi = CMDLINE_DISABLE_RISCV_USERCFI;
526+
527+
if (strcmp(str, "fcfi") == 0)
528+
riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_FCFI;
529+
530+
if (strcmp(str, "bcfi") == 0)
531+
riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_BCFI;
532+
533+
if (riscv_nousercfi)
534+
pr_info("RISC-V user CFI disabled via cmdline - shadow stack status : %s, landing pad status : %s\n",
535+
(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI) ? "disabled" :
536+
"enabled", (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI) ?
537+
"disabled" : "enabled");
538+
539+
return 1;
540+
}
541+
542+
__setup("riscv_nousercfi=", setup_global_riscv_enable);

0 commit comments

Comments
 (0)