This commit adds a kernel command line option using which user cfi can be
disabled. User backward cfi and forward cfi can be enabled independently.
Kernel command line parameter "riscv_nousercfi" can take below values:
 - "all" : Disable forward and backward cfi both.
 - "bcfi" : Disable backward cfi.
 - "fcfi" : Disable forward cfi

Signed-off-by: Deepak Gupta <de...@rivosinc.com>
---
 Documentation/admin-guide/kernel-parameters.txt |  8 ++++
 arch/riscv/include/asm/usercfi.h                |  7 +++
 arch/riscv/kernel/usercfi.c                     | 59 ++++++++++++++++++++-----
 3 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index 76e538c77e31..f75d50420a56 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6237,6 +6237,14 @@
                        replacement properties are not found. See the Kconfig
                        entry for RISCV_ISA_FALLBACK.
 
+       riscv_nousercfi=
+               all     Disable user cfi ABI to userspace even if cpu extension
+                       are available.
+               bcfi    Disable user backward cfi ABI to userspace even if
+                       shadow stack extension is available.
+               fcfi    Disable user forward cfi ABI to userspace even if 
landing
+                       pad extension is available.
+
        ro              [KNL] Mount root device read-only on boot
 
        rodata=         [KNL,EARLY]
diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h
index 68da5b7b79fd..6867ba6bd5a5 100644
--- a/arch/riscv/include/asm/usercfi.h
+++ b/arch/riscv/include/asm/usercfi.h
@@ -5,6 +5,10 @@
 #ifndef _ASM_RISCV_USERCFI_H
 #define _ASM_RISCV_USERCFI_H
 
+#define CMDLINE_DISABLE_RISCV_USERCFI_FCFI     1
+#define CMDLINE_DISABLE_RISCV_USERCFI_BCFI     2
+#define CMDLINE_DISABLE_RISCV_USERCFI          3
+
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
 #include <linux/prctl.h>
@@ -83,6 +87,9 @@ void set_indir_lp_lock(struct task_struct *task);
 
 #endif /* CONFIG_RISCV_USER_CFI */
 
+bool is_user_shstk_enabled(void);
+bool is_user_lpad_enabled(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_RISCV_USERCFI_H */
diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c
index 8bc3e1e3f712..5ef357f43ad7 100644
--- a/arch/riscv/kernel/usercfi.c
+++ b/arch/riscv/kernel/usercfi.c
@@ -17,6 +17,8 @@
 #include <asm/csr.h>
 #include <asm/usercfi.h>
 
+unsigned int riscv_nousercfi;
+
 #define SHSTK_ENTRY_SIZE sizeof(void *)
 
 bool is_shstk_enabled(struct task_struct *task)
@@ -59,7 +61,7 @@ unsigned long get_active_shstk(struct task_struct *task)
 
 void set_shstk_status(struct task_struct *task, bool enable)
 {
-       if (!cpu_supports_shadow_stack())
+       if (!is_user_shstk_enabled())
                return;
 
        task->thread_info.user_cfi_state.ubcfi_en = enable ? 1 : 0;
@@ -89,7 +91,7 @@ bool is_indir_lp_locked(struct task_struct *task)
 
 void set_indir_lp_status(struct task_struct *task, bool enable)
 {
-       if (!cpu_supports_indirect_br_lp_instr())
+       if (!is_user_lpad_enabled())
                return;
 
        task->thread_info.user_cfi_state.ufcfi_en = enable ? 1 : 0;
@@ -259,7 +261,7 @@ SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, 
unsigned long, size, unsi
        bool set_tok = flags & SHADOW_STACK_SET_TOKEN;
        unsigned long aligned_size = 0;
 
-       if (!cpu_supports_shadow_stack())
+       if (!is_user_shstk_enabled())
                return -EOPNOTSUPP;
 
        /* Anything other than set token should result in invalid param */
@@ -306,7 +308,7 @@ unsigned long shstk_alloc_thread_stack(struct task_struct 
*tsk,
        unsigned long addr, size;
 
        /* If shadow stack is not supported, return 0 */
-       if (!cpu_supports_shadow_stack())
+       if (!is_user_shstk_enabled())
                return 0;
 
        /*
@@ -352,7 +354,7 @@ void shstk_release(struct task_struct *tsk)
 {
        unsigned long base = 0, size = 0;
        /* If shadow stack is not supported or not enabled, nothing to release 
*/
-       if (!cpu_supports_shadow_stack() || !is_shstk_enabled(tsk))
+       if (!is_user_shstk_enabled() || !is_shstk_enabled(tsk))
                return;
 
        /*
@@ -381,7 +383,7 @@ int arch_get_shadow_stack_status(struct task_struct *t, 
unsigned long __user *st
 {
        unsigned long bcfi_status = 0;
 
-       if (!cpu_supports_shadow_stack())
+       if (!is_user_shstk_enabled())
                return -EINVAL;
 
        /* this means shadow stack is enabled on the task */
@@ -395,7 +397,7 @@ int arch_set_shadow_stack_status(struct task_struct *t, 
unsigned long status)
        unsigned long size = 0, addr = 0;
        bool enable_shstk = false;
 
-       if (!cpu_supports_shadow_stack())
+       if (!is_user_shstk_enabled())
                return -EINVAL;
 
        /* Reject unknown flags */
@@ -448,7 +450,7 @@ int arch_lock_shadow_stack_status(struct task_struct *task,
                                  unsigned long arg)
 {
        /* If shtstk not supported or not enabled on task, nothing to lock here 
*/
-       if (!cpu_supports_shadow_stack() ||
+       if (!is_user_shstk_enabled() ||
            !is_shstk_enabled(task) || arg != 0)
                return -EINVAL;
 
@@ -461,7 +463,7 @@ int arch_get_indir_br_lp_status(struct task_struct *t, 
unsigned long __user *sta
 {
        unsigned long fcfi_status = 0;
 
-       if (!cpu_supports_indirect_br_lp_instr())
+       if (!is_user_lpad_enabled())
                return -EINVAL;
 
        /* indirect branch tracking is enabled on the task or not */
@@ -474,7 +476,7 @@ int arch_set_indir_br_lp_status(struct task_struct *t, 
unsigned long status)
 {
        bool enable_indir_lp = false;
 
-       if (!cpu_supports_indirect_br_lp_instr())
+       if (!is_user_lpad_enabled())
                return -EINVAL;
 
        /* indirect branch tracking is locked and further can't be modified by 
user */
@@ -498,7 +500,7 @@ int arch_lock_indir_br_lp_status(struct task_struct *task,
         * If indirect branch tracking is not supported or not enabled on task,
         * nothing to lock here
         */
-       if (!cpu_supports_indirect_br_lp_instr() ||
+       if (!is_user_lpad_enabled() ||
            !is_indir_lp_enabled(task) || arg != 0)
                return -EINVAL;
 
@@ -506,3 +508,38 @@ int arch_lock_indir_br_lp_status(struct task_struct *task,
 
        return 0;
 }
+
+bool is_user_shstk_enabled(void)
+{
+       return (cpu_supports_shadow_stack() &&
+               !(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI));
+}
+
+bool is_user_lpad_enabled(void)
+{
+       return (cpu_supports_indirect_br_lp_instr() &&
+               !(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI));
+}
+
+static int __init setup_global_riscv_enable(char *str)
+{
+       if (strcmp(str, "all") == 0)
+               riscv_nousercfi = CMDLINE_DISABLE_RISCV_USERCFI;
+
+       if (strcmp(str, "fcfi") == 0)
+               riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_FCFI;
+
+       if (strcmp(str, "bcfi") == 0)
+               riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_BCFI;
+
+       if (riscv_nousercfi)
+               pr_info("riscv user cfi disabled via cmdline"
+                       "shadow stack status : %s, landing pad status : %s\n",
+                       (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI) 
? "disabled" :
+                       "enabled", (riscv_nousercfi & 
CMDLINE_DISABLE_RISCV_USERCFI_FCFI) ?
+                       "disabled" : "enabled");
+
+       return 1;
+}
+
+__setup("riscv_nousercfi=", setup_global_riscv_enable);

-- 
2.43.0


Reply via email to