[v1,RFC,Zisslpcfi,15/20] sslp prctl: arch-agnostic prctl for shadow stack and landing pad instr
Commit Message
Three architectures (x86, aarch64, riscv) have announced support for
shadow stack and enforcing requirement of landing pad instructions on
indirect call/jmp. This patch adds arch-agnostic prtcl support to enable
/disable/get/set status of shadow stack and forward control (landing pad)
flow cfi statuses.
New prctls are
- PR_GET_SHADOW_STACK_STATUS, PR_SET_SHADOW_STACK_STATUS
- PR_GET_INDIRECT_BR_LP_STATUS, PR_SET_INDIRECT_BR_LP_STATUS
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
include/uapi/linux/prctl.h | 26 +++++++++++++++++++++++++
kernel/sys.c | 40 ++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
Comments
On Sun, Feb 12, 2023 at 08:53:44PM -0800, Deepak Gupta wrote:
> Three architectures (x86, aarch64, riscv) have announced support for
> shadow stack and enforcing requirement of landing pad instructions on
> indirect call/jmp. This patch adds arch-agnostic prtcl support to enable
> /disable/get/set status of shadow stack and forward control (landing pad)
> flow cfi statuses.
>
> New prctls are
> - PR_GET_SHADOW_STACK_STATUS, PR_SET_SHADOW_STACK_STATUS
> - PR_GET_INDIRECT_BR_LP_STATUS, PR_SET_INDIRECT_BR_LP_STATUS
FWIW I had something very similar in my in progress arm64 support for
GCS (our equivalent feature), though without the LP stuff as we don't
have that.
Reviewed-by: Mark Brown <broonie@kernel.org>
I'll pull this into my branch and redo things on top of it if that's OK,
seems sensible to avoid collisions/duplication?
On Sun, Feb 12, 2023 at 08:53:44PM -0800, Deepak Gupta wrote:
> +int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
> +{
> + return -EINVAL;
> +}
Having looked at this further is there any great reason why the status
is passed as a pointer? It seems needless effort.
I am really sorry to have missed this and being late.
I saw your GCS patches. Thanks for picking this up.
On Wed, Jun 7, 2023 at 1:22 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Sun, Feb 12, 2023 at 08:53:44PM -0800, Deepak Gupta wrote:
>
> > +int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
> > +{
> > + return -EINVAL;
> > +}
>
> Having looked at this further is there any great reason why the status
> is passed as a pointer? It seems needless effort.
I was trying to be cleaner here to not overload returned status with a pointer.
You could say that any negative value is an error. I don't have any
favorites here.
-Deepak
On Mon, Oct 09, 2023 at 02:22:51PM -0700, Deepak Gupta wrote:
> On Wed, Jun 7, 2023 at 1:22 PM Mark Brown <broonie@kernel.org> wrote:
> > On Sun, Feb 12, 2023 at 08:53:44PM -0800, Deepak Gupta wrote:
> > > +int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
> > > +{
> > > + return -EINVAL;
> > > +}
> > Having looked at this further is there any great reason why the status
> > is passed as a pointer? It seems needless effort.
> I was trying to be cleaner here to not overload returned status with a pointer.
> You could say that any negative value is an error. I don't have any
> favorites here.
OK, thanks - I changed it to treat negative codes as errors, I'll leave
things like that.
@@ -284,4 +284,30 @@ struct prctl_mm_map {
#define PR_SET_VMA 0x53564d41
# define PR_SET_VMA_ANON_NAME 0
+/*
+ * get shadow stack status for current thread. Assumes shadow stack is min 4 byte aligned.
+ * Note shadow stack can be 8 byte aligned on 64bit.
+ * Lower 2 bits can give status of locked and enabled/disabled.
+ * size and address range can be obtained via /proc/maps. get_shadow_stack_status will
+ * return base of shadow stack.
+ */
+#define PR_GET_SHADOW_STACK_STATUS 65
+/*
+ * set shadow stack status for current thread (including enabling, disabling or locking)
+ * note that it will only set the status and setup of the shadow stack. Allocating shadow
+ * stack should be done separately using mmap.
+ */
+#define PR_SET_SHADOW_STACK_STATUS 66
+# define PR_SHADOW_STACK_LOCK (1UL << 0)
+# define PR_SHADOW_STACK_ENABLE (1UL << 1)
+
+/* get status of requirement of a landing pad instruction for current thread */
+#define PR_GET_INDIRECT_BR_LP_STATUS 67
+/*
+ * set status of requirement of a landing pad instruction for current thread
+ * (including enabling, disabling or locking)
+ */
+#define PR_SET_INDIRECT_BR_LP_STATUS 68
+# define PR_INDIRECT_BR_LP_LOCK (1UL << 0)
+# define PR_INDIRECT_BR_LP_ENABLE (1UL << 1)
#endif /* _LINUX_PRCTL_H */
@@ -2284,6 +2284,26 @@ int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
return -EINVAL;
}
+int __weak arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
+{
+ return -EINVAL;
+}
+
+int __weak arch_set_shadow_stack_status(struct task_struct *t, unsigned long __user *status)
+{
+ 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;
+}
+
#define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE)
#ifdef CONFIG_ANON_VMA_NAME
@@ -2628,6 +2648,26 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;
+ case PR_GET_SHADOW_STACK_STATUS:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ error = arch_get_shadow_stack_status(me, (unsigned long __user *) arg2);
+ break;
+ case PR_SET_SHADOW_STACK_STATUS:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ error = arch_set_shadow_stack_status(me, (unsigned long __user *) arg2);
+ break;
+ case PR_GET_INDIRECT_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_INDIRECT_BR_LP_STATUS:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ error = arch_set_indir_br_lp_status(me, (unsigned long __user *) arg2);
+ break;
default:
error = -EINVAL;
break;