[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210820182245.1188-4-yu-cheng.yu@intel.com>
Date: Fri, 20 Aug 2021 11:22:38 -0700
From: Yu-cheng Yu <yu-cheng.yu@...el.com>
To: x86@...nel.org, "H. Peter Anvin" <hpa@...or.com>,
Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>, linux-kernel@...r.kernel.org,
linux-doc@...r.kernel.org, linux-mm@...ck.org,
linux-arch@...r.kernel.org, linux-api@...r.kernel.org,
Arnd Bergmann <arnd@...db.de>,
Andy Lutomirski <luto@...nel.org>,
Balbir Singh <bsingharora@...il.com>,
Borislav Petkov <bp@...en8.de>,
Cyrill Gorcunov <gorcunov@...il.com>,
Dave Hansen <dave.hansen@...ux.intel.com>,
Eugene Syromiatnikov <esyr@...hat.com>,
Florian Weimer <fweimer@...hat.com>,
"H.J. Lu" <hjl.tools@...il.com>, Jann Horn <jannh@...gle.com>,
Jonathan Corbet <corbet@....net>,
Kees Cook <keescook@...omium.org>,
Mike Kravetz <mike.kravetz@...cle.com>,
Nadav Amit <nadav.amit@...il.com>,
Oleg Nesterov <oleg@...hat.com>, Pavel Machek <pavel@....cz>,
Peter Zijlstra <peterz@...radead.org>,
Randy Dunlap <rdunlap@...radead.org>,
"Ravi V. Shankar" <ravi.v.shankar@...el.com>,
Dave Martin <Dave.Martin@....com>,
Weijiang Yang <weijiang.yang@...el.com>,
Pengfei Xu <pengfei.xu@...el.com>,
Haitao Huang <haitao.huang@...el.com>,
Rick P Edgecombe <rick.p.edgecombe@...el.com>
Cc: Yu-cheng Yu <yu-cheng.yu@...el.com>
Subject: [PATCH v29 03/10] x86/cet/ibt: Handle signals for Indirect Branch Tracking
IBT state machine tracks CALL/JMP instructions. When a such instruction is
executed and before arriving at an ENDBR, it is in WAIT_FOR_ENDBR state,
which can be read from CET_WAIT_ENDBR bit of MSR_IA32_U_CET.
Further details are described in Intel SDM Vol. 1, Sec. 18.3.
In handling signals, WAIT_FOR_ENDBR state is saved/restored with a new
UC_WAIT_ENDBR flag being introduced.
A legacy IA32 signal frame does not have ucontext, and cannot be supported
with a uc flag. Thus, IBT feature is not supported for ia32 app's, which
is handled in a separate patch.
Signed-off-by: Yu-cheng Yu <yu-cheng.yu@...el.com>
Cc: Andy Lutomirski <luto@...nel.org>
Cc: Cyrill Gorcunov <gorcunov@...il.com>
Cc: Florian Weimer <fweimer@...hat.com>
Cc: H. Peter Anvin <hpa@...or.com>
Cc: Kees Cook <keescook@...omium.org>
Link: https://lore.kernel.org/linux-api/f6e61dae-9805-c855-8873-7481ceb7ea79@intel.com/
---
arch/x86/ia32/ia32_signal.c | 15 ++++++++--
arch/x86/include/asm/cet.h | 4 +++
arch/x86/include/uapi/asm/ucontext.h | 5 ++++
arch/x86/kernel/ibt.c | 41 ++++++++++++++++++++++++++++
arch/x86/kernel/signal.c | 6 ++++
5 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index d7a30bc98e66..77d0fa90cc19 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -129,6 +129,7 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct rt_sigframe_ia32 __user *frame;
+ unsigned int uc_flags;
sigset_t set;
frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
@@ -137,6 +138,11 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
goto badframe;
if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask))
goto badframe;
+ if (__get_user(uc_flags, &frame->uc.uc_flags))
+ goto badframe;
+
+ if (uc_flags & UC_WAIT_ENDBR)
+ ibt_set_wait_endbr();
set_current_blocked(&set);
@@ -312,6 +318,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
compat_sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe_ia32 __user *frame;
+ unsigned int uc_flags = 0;
void __user *restorer;
void __user *fp = NULL;
@@ -339,6 +346,9 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
if (setup_signal_shadow_stack(1, restorer))
return -EFAULT;
+ if (ibt_get_clear_wait_endbr())
+ uc_flags |= UC_WAIT_ENDBR;
+
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
@@ -348,9 +358,8 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
/* Create the ucontext. */
if (static_cpu_has(X86_FEATURE_XSAVE))
- unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
- else
- unsafe_put_user(0, &frame->uc.uc_flags, Efault);
+ uc_flags |= UC_FP_XSTATE;
+ unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
unsafe_put_user(0, &frame->uc.uc_link, Efault);
unsafe_compat_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index 3dfca29a7c0b..2618faf3fda5 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -46,9 +46,13 @@ static inline int restore_signal_shadow_stack(void) { return 0; }
#ifdef CONFIG_X86_IBT
int ibt_setup(void);
void ibt_disable(void);
+int ibt_get_clear_wait_endbr(void);
+int ibt_set_wait_endbr(void);
#else
static inline int ibt_setup(void) { return 0; }
static inline void ibt_disable(void) {}
+static inline int ibt_get_clear_wait_endbr(void) { return 0; }
+static inline int ibt_set_wait_endbr(void) { return 0; }
#endif
#ifdef CONFIG_X86_SHADOW_STACK
diff --git a/arch/x86/include/uapi/asm/ucontext.h b/arch/x86/include/uapi/asm/ucontext.h
index 5657b7a49f03..905419de2cc7 100644
--- a/arch/x86/include/uapi/asm/ucontext.h
+++ b/arch/x86/include/uapi/asm/ucontext.h
@@ -51,6 +51,11 @@
#define UC_STRICT_RESTORE_SS 0x4
#endif
+/*
+ * Indicates IBT WAIT-ENDBR status.
+ */
+#define UC_WAIT_ENDBR 0x08
+
#include <asm-generic/ucontext.h>
#endif /* _ASM_X86_UCONTEXT_H */
diff --git a/arch/x86/kernel/ibt.c b/arch/x86/kernel/ibt.c
index 4ab7af33b274..5ab8632a1f7e 100644
--- a/arch/x86/kernel/ibt.c
+++ b/arch/x86/kernel/ibt.c
@@ -56,3 +56,44 @@ void ibt_disable(void)
ibt_set_clear_msr_bits(0, CET_ENDBR_EN);
current->thread.shstk.ibt = 0;
}
+
+int ibt_get_clear_wait_endbr(void)
+{
+ u64 msr_val = 0;
+
+ if (!current->thread.shstk.ibt)
+ return 0;
+
+ fpregs_lock();
+
+ if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
+ if (!rdmsrl_safe(MSR_IA32_U_CET, &msr_val))
+ wrmsrl(MSR_IA32_U_CET, msr_val & ~CET_WAIT_ENDBR);
+ } else {
+ struct cet_user_state *cet;
+
+ /*
+ * If !TIF_NEED_FPU_LOAD and get_xsave_addr() returns zero,
+ * XFEATURE_CET_USER is in init state (cet is not active).
+ * Return zero status.
+ */
+ cet = get_xsave_addr(¤t->thread.fpu.state.xsave,
+ XFEATURE_CET_USER);
+ if (cet) {
+ msr_val = cet->user_cet;
+ cet->user_cet = msr_val & ~CET_WAIT_ENDBR;
+ }
+ }
+
+ fpregs_unlock();
+
+ return msr_val & CET_WAIT_ENDBR;
+}
+
+int ibt_set_wait_endbr(void)
+{
+ if (!current->thread.shstk.ibt)
+ return 0;
+
+ return ibt_set_clear_msr_bits(CET_WAIT_ENDBR, 0);
+}
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 661e46803b84..a1285650852e 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -135,6 +135,9 @@ static int restore_sigcontext(struct pt_regs *regs,
*/
if (unlikely(!(uc_flags & UC_STRICT_RESTORE_SS) && user_64bit_mode(regs)))
force_valid_ss(regs);
+
+ if (uc_flags & UC_WAIT_ENDBR)
+ ibt_set_wait_endbr();
#endif
return fpu__restore_sig((void __user *)sc.fpstate,
@@ -455,6 +458,9 @@ static unsigned long frame_uc_flags(struct pt_regs *regs)
if (likely(user_64bit_mode(regs)))
flags |= UC_STRICT_RESTORE_SS;
+ if (ibt_get_clear_wait_endbr())
+ flags |= UC_WAIT_ENDBR;
+
return flags;
}
--
2.21.0
Powered by blists - more mailing lists