On Sat, Mar 15, 2025 at 6:51 AM Deepak Gupta debug@rivosinc.com wrote:
Three architectures (x86, aarch64, riscv) have support for indirect branch tracking feature in a very similar fashion. On a very high level, indirect branch tracking is a CPU feature where CPU tracks branches which uses memory operand to perform control transfer in program. As part of this tracking on indirect branches, CPU goes in a state where it expects a landing pad instr on target and if not found then CPU raises some fault (architecture dependent)
x86 landing pad instr - `ENDBRANCH` arch64 landing pad instr - `BTI` riscv landing instr - `lpad`
Given that three major arches have support for indirect branch tracking, This patch makes `prctl` for indirect branch tracking arch agnostic.
To allow userspace to enable this feature for itself, following prtcls are defined:
- PR_GET_INDIR_BR_LP_STATUS: Gets current configured status for indirect branch tracking.
- PR_SET_INDIR_BR_LP_STATUS: Sets a configuration for indirect branch tracking. Following status options are allowed - PR_INDIR_BR_LP_ENABLE: Enables indirect branch tracking on user thread. - PR_INDIR_BR_LP_DISABLE; Disables indirect branch tracking on user thread.
- PR_LOCK_INDIR_BR_LP_STATUS: Locks configured status for indirect branch tracking for user thread.
Signed-off-by: Deepak Gupta debug@rivosinc.com Reviewed-by: Mark Brown broonie@kernel.org
include/linux/cpu.h | 4 ++++ include/uapi/linux/prctl.h | 27 +++++++++++++++++++++++++++ kernel/sys.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 6a0a8f1c7c90..fb0c394430c6 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -204,4 +204,8 @@ static inline bool cpu_mitigations_auto_nosmt(void) } #endif
+int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status); +int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status); +int arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status);
#endif /* _LINUX_CPU_H_ */ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 5c6080680cb2..6cd90460cbad 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -353,4 +353,31 @@ struct prctl_mm_map { */ #define PR_LOCK_SHADOW_STACK_STATUS 76
+/*
- Get the current indirect branch tracking configuration for the current
- thread, this will be the value configured via PR_SET_INDIR_BR_LP_STATUS.
- */
+#define PR_GET_INDIR_BR_LP_STATUS 77
+/*
- Set the indirect branch tracking configuration. PR_INDIR_BR_LP_ENABLE will
- enable cpu feature for user thread, to track all indirect branches and ensure
- they land on arch defined landing pad instruction.
- x86 - If enabled, an indirect branch must land on `ENDBRANCH` instruction.
- arch64 - If enabled, an indirect branch must land on `BTI` instruction.
- riscv - If enabled, an indirect branch must land on `lpad` instruction.
- PR_INDIR_BR_LP_DISABLE will disable feature for user thread and indirect
- branches will no more be tracked by cpu to land on arch defined landing pad
- instruction.
- */
+#define PR_SET_INDIR_BR_LP_STATUS 78 +# define PR_INDIR_BR_LP_ENABLE (1UL << 0)
+/*
- Prevent further changes to the specified indirect branch tracking
- configuration. All bits may be locked via this call, including
- undefined bits.
- */
+#define PR_LOCK_INDIR_BR_LP_STATUS 79
#endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index cb366ff8703a..f347f3518d0b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2336,6 +2336,21 @@ int __weak arch_lock_shadow_stack_status(struct task_struct *t, unsigned long st return -EINVAL; }
+int __weak arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status) +{
return -EINVAL;
+}
+int __weak arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status) +{
return -EINVAL;
+}
+int __weak arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status) +{
return -EINVAL;
+}
#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
#ifdef CONFIG_ANON_VMA_NAME @@ -2811,6 +2826,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; error = arch_lock_shadow_stack_status(me, arg2); break;
case PR_GET_INDIR_BR_LP_STATUS:
if (arg3 || arg4 || arg5)
return -EINVAL;
error = arch_get_indir_br_lp_status(me, (unsigned long __user *)arg2);
break;
case PR_SET_INDIR_BR_LP_STATUS:
if (arg3 || arg4 || arg5)
return -EINVAL;
error = arch_set_indir_br_lp_status(me, arg2);
break;
case PR_LOCK_INDIR_BR_LP_STATUS:
if (arg3 || arg4 || arg5)
return -EINVAL;
error = arch_lock_indir_br_lp_status(me, arg2);
break; default: trace_task_prctl_unknown(option, arg2, arg3, arg4, arg5); error = -EINVAL;
LGTM
Reviewed-by: Zong Li zong.li@sifive.com
-- 2.34.1
linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv