@@ -34,6 +34,7 @@
#include <asm/sigframe.h>
#include <asm/sighandling.h>
#include <asm/smap.h>
+#include <asm/cet.h>
static inline void reload_segments(struct sigcontext_32 *sc)
{
@@ -112,6 +113,10 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
if (!ia32_restore_sigcontext(regs, &frame->sc))
goto badframe;
+
+ if (restore_signal_shadow_stack())
+ goto badframe;
+
return regs->ax;
badframe:
@@ -137,6 +142,9 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
if (!ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
+ if (restore_signal_shadow_stack())
+ goto badframe;
+
if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;
@@ -261,6 +269,9 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
restorer = &frame->retcode;
}
+ if (setup_signal_shadow_stack(1, restorer))
+ return -EFAULT;
+
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
@@ -318,6 +329,15 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
frame = get_sigframe(ksig, regs, sizeof(*frame), &fp);
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ restorer = ksig->ka.sa.sa_restorer;
+ else
+ restorer = current->mm->context.vdso +
+ vdso_image_32.sym___kernel_rt_sigreturn;
+
+ if (setup_signal_shadow_stack(1, restorer))
+ return -EFAULT;
+
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
@@ -333,11 +353,6 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
unsafe_put_user(0, &frame->uc.uc_link, Efault);
unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
- if (ksig->ka.sa.sa_flags & SA_RESTORER)
- restorer = ksig->ka.sa.sa_restorer;
- else
- restorer = current->mm->context.vdso +
- vdso_image_32.sym___kernel_rt_sigreturn;
unsafe_put_user(ptr_to_compat(restorer), &frame->pretcode, Efault);
/*
@@ -22,6 +22,8 @@ void reset_thread_shstk(void);
int shstk_setup_rstor_token(bool proc32, unsigned long restorer,
unsigned long *new_ssp);
int shstk_check_rstor_token(bool proc32, unsigned long *new_ssp);
+int setup_signal_shadow_stack(int proc32, void __user *restorer);
+int restore_signal_shadow_stack(void);
#else
static inline void shstk_setup(void) {}
static inline int shstk_alloc_thread_stack(struct task_struct *p,
@@ -34,6 +36,8 @@ static inline int shstk_setup_rstor_token(bool proc32, unsigned long restorer,
unsigned long *new_ssp) { return 0; }
static inline int shstk_check_rstor_token(bool proc32,
unsigned long *new_ssp) { return 0; }
+static inline int setup_signal_shadow_stack(int proc32, void __user *restorer) { return 0; }
+static inline int restore_signal_shadow_stack(void) { return 0; }
#endif /* CONFIG_X86_SHADOW_STACK */
#endif /* __ASSEMBLY__ */
@@ -335,3 +335,47 @@ int shstk_check_rstor_token(bool proc32, unsigned long *new_ssp)
return 0;
}
+
+int setup_signal_shadow_stack(int proc32, void __user *restorer)
+{
+ struct thread_shstk *shstk = ¤t->thread.shstk;
+ unsigned long new_ssp;
+ void *xstate;
+ int err;
+
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK) || !shstk->size)
+ return 0;
+
+ err = shstk_setup_rstor_token(proc32, (unsigned long)restorer,
+ &new_ssp);
+ if (err)
+ return err;
+
+ xstate = start_update_xsave_msrs(XFEATURE_CET_USER);
+ err = xsave_wrmsrl(xstate, MSR_IA32_PL3_SSP, new_ssp);
+ end_update_xsave_msrs();
+
+ return err;
+}
+
+int restore_signal_shadow_stack(void)
+{
+ struct thread_shstk *shstk = ¤t->thread.shstk;
+ void *xstate;
+ int proc32 = in_ia32_syscall();
+ unsigned long new_ssp;
+ int err;
+
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK) || !shstk->size)
+ return 0;
+
+ err = shstk_check_rstor_token(proc32, &new_ssp);
+ if (err)
+ return err;
+
+ xstate = start_update_xsave_msrs(XFEATURE_CET_USER);
+ err = xsave_wrmsrl(xstate, MSR_IA32_PL3_SSP, new_ssp);
+ end_update_xsave_msrs();
+
+ return err;
+}
@@ -48,6 +48,7 @@
#include <asm/syscall.h>
#include <asm/sigframe.h>
#include <asm/signal.h>
+#include <asm/cet.h>
#ifdef CONFIG_X86_64
/*
@@ -471,6 +472,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
uc_flags = frame_uc_flags(regs);
+ if (setup_signal_shadow_stack(0, ksig->ka.sa.sa_restorer))
+ return -EFAULT;
+
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
@@ -576,6 +580,9 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
uc_flags = frame_uc_flags(regs);
+ if (setup_signal_shadow_stack(0, ksig->ka.sa.sa_restorer))
+ return -EFAULT;
+
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
@@ -674,6 +681,9 @@ SYSCALL_DEFINE0(rt_sigreturn)
if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
goto badframe;
+ if (restore_signal_shadow_stack())
+ goto badframe;
+
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
@@ -991,6 +1001,9 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
goto badframe;
+ if (restore_signal_shadow_stack())
+ goto badframe;
+
if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;