[RFC,v1,18/28] prctl: arch-agnostic prtcl for indirect branch tracking
Commit Message
From: Deepak Gupta <debug@rivosinc.com>
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`
aarch64 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>
---
include/uapi/linux/prctl.h | 27 +++++++++++++++++++++++++++
kernel/sys.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+)
Comments
On Wed, Jan 24, 2024 at 10:21:43PM -0800, debug@rivosinc.com wrote:
> 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.
FWIW the arm64 BTI feature is enabled per page of executable memory
rather than in CPU state so it'd be hard for us to adopt this interface.
I don't think that's a blocker, just noting it.
On Tue, Feb 06, 2024 at 04:13:39PM +0000, Mark Brown wrote:
>On Wed, Jan 24, 2024 at 10:21:43PM -0800, debug@rivosinc.com wrote:
>
>> 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.
>
>FWIW the arm64 BTI feature is enabled per page of executable memory
>rather than in CPU state so it'd be hard for us to adopt this interface.
>I don't think that's a blocker, just noting it.
Got it, makes sense.
@@ -328,4 +328,31 @@ struct prctl_mm_map {
*/
#define PR_LOCK_SHADOW_STACK_STATUS 73
+/*
+ * 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 74
+
+/*
+ * 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 75
+# 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 76
+
#endif /* _LINUX_PRCTL_H */
@@ -2316,6 +2316,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 __user *status)
+{
+ return -EINVAL;
+}
+
+int __weak arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long __user *status)
+{
+ return -EINVAL;
+}
+
#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
#ifdef CONFIG_ANON_VMA_NAME
@@ -2773,6 +2788,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, (unsigned long __user *) arg2);
+ break;
+ case PR_LOCK_INDIR_BR_LP_STATUS:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ error = arch_lock_indir_br_lp_status(me, (unsigned long __user *) arg2);
+ break;
default:
error = -EINVAL;
break;