Thread (50 messages) 50 messages, 4 authors, 2021-04-10

Re: [PATCH v24 24/30] x86/cet/shstk: Introduce shadow stack token setup/verify routines

From: Andy Lutomirski <luto@kernel.org>
Date: 2021-04-06 22:49:49
Also in: linux-arch, linux-doc, linux-mm, lkml

On Thu, Apr 1, 2021 at 3:12 PM Yu-cheng Yu [off-list ref] wrote:
quoted hunk ↗ jump to hunk
A shadow stack restore token marks a restore point of the shadow stack, and
the address in a token must point directly above the token, which is within
the same shadow stack.  This is distinctively different from other pointers
on the shadow stack, since those pointers point to executable code area.

The restore token can be used as an extra protection for signal handling.
To deliver a signal, create a shadow stack restore token and put the token
and the signal restorer address on the shadow stack.  In sigreturn, verify
the token and restore from it the shadow stack pointer.

Introduce token setup and verify routines.  Also introduce WRUSS, which is
a kernel-mode instruction but writes directly to user shadow stack.  It is
used to construct user signal stack as described above.

Signed-off-by: Yu-cheng Yu <redacted>
Cc: Kees Cook <redacted>
---
 arch/x86/include/asm/cet.h           |   9 ++
 arch/x86/include/asm/special_insns.h |  32 +++++++
 arch/x86/kernel/shstk.c              | 126 +++++++++++++++++++++++++++
 3 files changed, 167 insertions(+)
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index 8b83ded577cc..ef6155213b7e 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -20,6 +20,10 @@ int shstk_setup_thread(struct task_struct *p, unsigned long clone_flags,
                       unsigned long stack_size);
 void shstk_free(struct task_struct *p);
 void shstk_disable(void);
+int shstk_setup_rstor_token(bool ia32, unsigned long rstor,
+                           unsigned long *token_addr, unsigned long *new_ssp);
+int shstk_check_rstor_token(bool ia32, unsigned long token_addr,
+                           unsigned long *new_ssp);
 #else
 static inline int shstk_setup(void) { return 0; }
 static inline int shstk_setup_thread(struct task_struct *p,
@@ -27,6 +31,11 @@ static inline int shstk_setup_thread(struct task_struct *p,
                                     unsigned long stack_size) { return 0; }
 static inline void shstk_free(struct task_struct *p) {}
 static inline void shstk_disable(void) {}
+static inline int shstk_setup_rstor_token(bool ia32, unsigned long rstor,
+                                         unsigned long *token_addr,
+                                         unsigned long *new_ssp) { return 0; }
+static inline int shstk_check_rstor_token(bool ia32, unsigned long token_addr,
+                                         unsigned long *new_ssp) { return 0; }
 #endif

 #endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 1d3cbaef4bb7..c41c371f6c7d 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -234,6 +234,38 @@ static inline void clwb(volatile void *__p)
                : [pax] "a" (p));
 }

+#ifdef CONFIG_X86_SHADOW_STACK
+#if defined(CONFIG_IA32_EMULATION) || defined(CONFIG_X86_X32)
+static inline int write_user_shstk_32(unsigned long addr, unsigned int val)
u32 __user *addr?
+{
+       asm_volatile_goto("1: wrussd %1, (%0)\n"
+                         _ASM_EXTABLE(1b, %l[fail])
+                         :: "r" (addr), "r" (val)
+                         :: fail);
+       return 0;
+fail:
+       return -EPERM;
-EFAULT?
+}
+#else
+static inline int write_user_shstk_32(unsigned long addr, unsigned int val)
+{
+       WARN_ONCE(1, "%s used but not supported.\n", __func__);
+       return -EFAULT;
+}
+#endif
+
+static inline int write_user_shstk_64(unsigned long addr, unsigned long val)
u64 __user *addr, perhaps?
+{
+       asm_volatile_goto("1: wrussq %1, (%0)\n"
+                         _ASM_EXTABLE(1b, %l[fail])
+                         :: "r" (addr), "r" (val)
Can you use the modern [addr] "r" (addr) syntax?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help