2021-08-20 18:24:44

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 00/10] Control-flow Enforcement: Indirect Branch Tracking

Control-flow Enforcement (CET) is a new Intel processor feature that blocks
return/jump-oriented programming attacks. Details are in "Intel 64 and
IA-32 Architectures Software Developer's Manual" [1].

This is the second part of CET and enables Indirect Branch Tracking (IBT).
It is built on top of the shadow stack series.

Changes in v29:
- Rebase to Linus tree v5.14-rc6.

Changes in v28:
- Patch #10: Update change log and comments.
- Rebase to Linus tree v5.14-rc2.

Changes in v27:
- Use a ucontext flag to save/restore IBT status.
- Disable IBT support for IA32.
- Rebase to Linus tree v5.13-rc2.

[1] Intel 64 and IA-32 Architectures Software Developer's Manual:

https://software.intel.com/en-us/download/intel-64-and-ia-32-
architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4

H.J. Lu (3):
x86/cet/ibt: Update arch_prctl functions for Indirect Branch Tracking
x86/vdso: Insert endbr32/endbr64 to vDSO
x86/vdso/32: Add ENDBR to __kernel_vsyscall entry point

Yu-cheng Yu (7):
x86/cet/ibt: Add Kconfig option for Indirect Branch Tracking
x86/cet/ibt: Add user-mode Indirect Branch Tracking support
x86/cet/ibt: Handle signals for Indirect Branch Tracking
x86/cet/ibt: Disable IBT for ia32
x86/cet/ibt: Update ELF header parsing for Indirect Branch Tracking
x86/vdso: Introduce ENDBR macro
x86/vdso: Add ENDBR to __vdso_sgx_enter_enclave

arch/x86/Kconfig | 19 +++++
arch/x86/entry/vdso/Makefile | 4 +
arch/x86/entry/vdso/vdso32/system_call.S | 2 +
arch/x86/entry/vdso/vsgx.S | 4 +
arch/x86/ia32/ia32_signal.c | 22 +++++-
arch/x86/include/asm/cet.h | 13 ++++
arch/x86/include/asm/disabled-features.h | 8 +-
arch/x86/include/asm/elf.h | 13 +++-
arch/x86/include/asm/vdso.h | 20 ++++-
arch/x86/include/uapi/asm/ucontext.h | 5 ++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/cet_prctl.c | 5 ++
arch/x86/kernel/ibt.c | 99 ++++++++++++++++++++++++
arch/x86/kernel/process_64.c | 6 ++
arch/x86/kernel/signal.c | 6 ++
15 files changed, 221 insertions(+), 6 deletions(-)
create mode 100644 arch/x86/kernel/ibt.c

--
2.21.0


2021-08-20 18:24:47

by Yu-cheng Yu

[permalink] [raw]
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 <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Cyrill Gorcunov <[email protected]>
Cc: Florian Weimer <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Kees Cook <[email protected]>
Link: https://lore.kernel.org/linux-api/[email protected]/
---
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(&current->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

2021-08-20 18:25:31

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 09/10] x86/vdso/32: Add ENDBR to __kernel_vsyscall entry point

From: "H.J. Lu" <[email protected]>

ENDBR is a special new instruction for the Indirect Branch Tracking (IBT)
component of CET. IBT prevents attacks by ensuring that (most) indirect
branches and function calls may only land at ENDBR instructions. Branches
that don't follow the rules will result in control flow (#CF) exceptions.

ENDBR is a noop when IBT is unsupported or disabled. Most ENDBR
instructions are inserted automatically by the compiler, but branch
targets written in assembly must have ENDBR added manually.

Add that to __kernel_vsyscall entry point.

Signed-off-by: H.J. Lu <[email protected]>
Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Cc: Andy Lutomirski <[email protected]>
---
arch/x86/entry/vdso/vdso32/system_call.S | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S
index 6ddd7a937b3e..d321c2ded33a 100644
--- a/arch/x86/entry/vdso/vdso32/system_call.S
+++ b/arch/x86/entry/vdso/vdso32/system_call.S
@@ -7,6 +7,7 @@
#include <asm/dwarf2.h>
#include <asm/cpufeatures.h>
#include <asm/alternative.h>
+#include <asm/vdso.h>

.text
.globl __kernel_vsyscall
@@ -14,6 +15,7 @@
ALIGN
__kernel_vsyscall:
CFI_STARTPROC
+ ENDBR32
/*
* Reshuffle regs so that all of any of the entry instructions
* will preserve enough state.
--
2.21.0

2021-08-20 18:25:31

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 04/10] x86/cet/ibt: Disable IBT for ia32

In a signal, a task's IBT status needs to be saved to the signal frame, and
later restored in sigreturn. For the purpose, previous versions of the
series add a new struct to the signal frame. However, a new signal frame
format (or re-using a reserved space) introduces complex compatibility
issues.

In the discussion (see link below), Andy Lutomirski proposed using a
ucontext flag. The approach is clean and eliminates most compatibility
issues.

However, a legacy IA32 signal frame does not have ucontext and cannot
support a uc flag. Thus,

- Disable IBT for ia32.
- In ia32 sigreturn, verify ibt is disabled.

Signed-off-by: Yu-cheng Yu <[email protected]>
Acked-by: Andy Lutomirski <[email protected]>
Cc: Cyrill Gorcunov <[email protected]>
Cc: Florian Weimer <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Kees Cook <[email protected]>
Link: https://lore.kernel.org/linux-api/[email protected]/
---
arch/x86/ia32/ia32_signal.c | 7 +++++++
arch/x86/include/asm/elf.h | 13 ++++++++++++-
2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 77d0fa90cc19..946039cb3150 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -104,6 +104,13 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
sigset_t set;

+ /*
+ * Verify legacy sigreturn does not have IBT enabled.
+ */
+#ifdef CONFIG_X86_IBT
+ if (current->thread.shstk.ibt)
+ goto badframe;
+#endif
if (!access_ok(frame, sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 3281a3d01bd2..cf9eeb30c00c 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -6,6 +6,7 @@
* ELF register definitions..
*/
#include <linux/thread_info.h>
+#include <uapi/linux/elf.h>

#include <asm/ptrace.h>
#include <asm/user.h>
@@ -403,7 +404,17 @@ struct arch_elf_state {
}

#define arch_elf_pt_proc(ehdr, phdr, elf, interp, state) (0)
-#define arch_check_elf(ehdr, interp, interp_ehdr, state) (0)
+static inline int arch_check_elf(void *ehdr, bool interp,
+ void *interp_ehdr,
+ struct arch_elf_state *state)
+{
+ /*
+ * Disable IBT for ia32
+ */
+ if (elf_check_arch_ia32((struct elf32_hdr *)ehdr))
+ state->gnu_property &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
+ return 0;
+}

/* Do not change the values. See get_align_mask() */
enum align_flags {
--
2.21.0

2021-08-20 18:25:32

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 06/10] x86/cet/ibt: Update arch_prctl functions for Indirect Branch Tracking

From: "H.J. Lu" <[email protected]>

Update ARCH_X86_CET_STATUS and ARCH_X86_CET_DISABLE for Indirect Branch
Tracking.

Signed-off-by: H.J. Lu <[email protected]>
Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
arch/x86/kernel/cet_prctl.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/x86/kernel/cet_prctl.c b/arch/x86/kernel/cet_prctl.c
index b426d200e070..bd3c80d402e7 100644
--- a/arch/x86/kernel/cet_prctl.c
+++ b/arch/x86/kernel/cet_prctl.c
@@ -22,6 +22,9 @@ static int cet_copy_status_to_user(struct thread_shstk *shstk, u64 __user *ubuf)
buf[2] = shstk->size;
}

+ if (shstk->ibt)
+ buf[0] |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+
return copy_to_user(ubuf, buf, sizeof(buf));
}

@@ -46,6 +49,8 @@ int prctl_cet(int option, u64 arg2)
return -EINVAL;
if (arg2 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
shstk_disable();
+ if (arg2 & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ ibt_disable();
return 0;

case ARCH_X86_CET_LOCK:
--
2.21.0

2021-08-20 18:25:47

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 05/10] x86/cet/ibt: Update ELF header parsing for Indirect Branch Tracking

An ELF file's .note.gnu.property indicates features the file supports.
The property is parsed at loading time and passed to arch_setup_elf_
property(). Update it for Indirect Branch Tracking.

Signed-off-by: Yu-cheng Yu <[email protected]>
Cc: Kees Cook <[email protected]>
---
v27:
- Remove selecting of ARCH_USE_GNU_PROPERTY and ARCH_BINFMT_ELF_STATE,
since they are already selected by X86_64.
---
arch/x86/kernel/process_64.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 4271963fdd8c..4ab751a5146e 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -884,6 +884,12 @@ int arch_setup_elf_property(struct arch_elf_state *state)

if (state->gnu_property & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
r = shstk_setup();
+
+ if (r < 0)
+ return r;
+
+ if (state->gnu_property & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ r = ibt_setup();
#endif

return r;
--
2.21.0

2021-08-20 18:26:31

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 07/10] x86/vdso: Insert endbr32/endbr64 to vDSO

From: "H.J. Lu" <[email protected]>

When Indirect Branch Tracking (IBT) is enabled, vDSO entry points need
ENDBR32/ENDBR64 as first instructions. Kconfig X86_IBT verifies compiler's
-fcf-protection support. Update vDso Makefile to enable it.

Signed-off-by: H.J. Lu <[email protected]>
Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Cc: Andy Lutomirski <[email protected]>
---
arch/x86/entry/vdso/Makefile | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index 05c4abc2fdfd..a773a5f03b63 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -93,6 +93,10 @@ endif

$(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)

+ifdef CONFIG_X86_IBT
+$(vobjs) $(vobjs32): KBUILD_CFLAGS += -fcf-protection=branch
+endif
+
#
# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
#
--
2.21.0

2021-08-20 18:26:37

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 08/10] x86/vdso: Introduce ENDBR macro

ENDBR is a special new instruction for the Indirect Branch Tracking (IBT)
component of CET. IBT prevents attacks by ensuring that (most) indirect
branches and function calls may only land at ENDBR instructions. Branches
that don't follow the rules will result in control flow (#CF) exceptions.

ENDBR is a noop when IBT is unsupported or disabled. Most ENDBR
instructions are inserted automatically by the compiler, but branch
targets written in assembly must have ENDBR added manually.

Introduce ENDBR64/ENDBR32 macros.

Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Jarkko Sakkinen <[email protected]>
Cc: Peter Zijlstra <[email protected]>
---
arch/x86/include/asm/vdso.h | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 98aa103eb4ab..97358246e4c7 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -52,6 +52,24 @@ extern int map_vdso_once(const struct vdso_image *image, unsigned long addr);
extern bool fixup_vdso_exception(struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr);
-#endif /* __ASSEMBLER__ */
+#else /* __ASSEMBLER__ */
+
+/*
+ * ENDBR is an instruction for the Indirect Branch Tracking (IBT) component
+ * of CET. IBT prevents attacks by ensuring that (most) indirect branches
+ * function calls may only land at ENDBR instructions. Branches that don't
+ * follow the rules will result in control flow (#CF) exceptions.
+ * ENDBR is a noop when IBT is unsupported or disabled. Most ENDBR
+ * instructions are inserted automatically by the compiler, but branch
+ * targets written in assembly must have ENDBR added manually.
+ */
+#ifdef CONFIG_X86_IBT
+#define ENDBR64 endbr64
+#define ENDBR32 endbr32
+#else
+#define ENDBR64
+#define ENDBR32
+#endif

+#endif /* __ASSEMBLER__ */
#endif /* _ASM_X86_VDSO_H */
--
2.21.0

2021-08-20 18:26:40

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 01/10] x86/cet/ibt: Add Kconfig option for Indirect Branch Tracking

Indirect Branch Tracking (IBT) provides protection against CALL-/JMP-
oriented programming attacks. It is active when the kernel has this
feature enabled, and the processor and the application support it.
When this feature is enabled, legacy non-IBT applications continue to
work, but without IBT protection.

Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
arch/x86/Kconfig | 19 +++++++++++++++++++
arch/x86/include/asm/disabled-features.h | 8 +++++++-
2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 34692f02118c..b063d6d2491f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1932,6 +1932,25 @@ config X86_SHADOW_STACK

If unsure, say N.

+config X86_IBT
+ prompt "Intel Indirect Branch Tracking"
+ def_bool n
+ depends on X86_SHADOW_STACK
+ depends on $(cc-option,-fcf-protection)
+ help
+ Indirect Branch Tracking (IBT) provides protection against
+ CALL-/JMP-oriented programming attacks. It is active when
+ the kernel has this feature enabled, and the processor and
+ the application support it. When this feature is enabled,
+ legacy non-IBT applications continue to work, but without
+ IBT protection.
+ Support for this feature is present on Tiger Lake family of
+ processors released in 2020 or later. Enabling this feature
+ increases kernel text size by 3.7 KB.
+ See Documentation/x86/intel_cet.rst for more information.
+
+ If unsure, say N.
+
config EFI
bool "EFI runtime service support"
depends on ACPI
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index b7728f7afb2b..e3a08fcd72f4 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -71,6 +71,12 @@
#define DISABLE_SHSTK (1 << (X86_FEATURE_SHSTK & 31))
#endif

+#ifdef CONFIG_X86_IBT
+#define DISABLE_IBT 0
+#else
+#define DISABLE_IBT (1 << (X86_FEATURE_IBT & 31))
+#endif
+
/*
* Make sure to add features to the correct mask
*/
@@ -93,7 +99,7 @@
#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP| \
DISABLE_ENQCMD|DISABLE_SHSTK)
#define DISABLED_MASK17 0
-#define DISABLED_MASK18 0
+#define DISABLED_MASK18 (DISABLE_IBT)
#define DISABLED_MASK19 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)

--
2.21.0

2021-08-20 18:26:49

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 10/10] x86/vdso: Add ENDBR to __vdso_sgx_enter_enclave

ENDBR is a special new instruction for the Indirect Branch Tracking (IBT)
component of CET. IBT prevents attacks by ensuring that (most) indirect
branches and function calls may only land at ENDBR instructions. Branches
that don't follow the rules will result in control flow (#CF) exceptions.

ENDBR is a noop when IBT is unsupported or disabled. Most ENDBR
instructions are inserted automatically by the compiler, but branch
targets written in assembly must have ENDBR added manually.

Add ENDBR to __vdso_sgx_enter_enclave() indirect branch targets, including
EEXIT, which is considered an indirect branch.

Signed-off-by: Yu-cheng Yu <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Acked-by: Jarkko Sakkinen <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Peter Zijlstra <[email protected]>
---
v28:
- Move ENDBR64 below EEXIT comment (no functional change).
- Update change log, state EEXIT is considered an indirect branch.
---
arch/x86/entry/vdso/vsgx.S | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/x86/entry/vdso/vsgx.S b/arch/x86/entry/vdso/vsgx.S
index 99dafac992e2..d65a7f9dea8b 100644
--- a/arch/x86/entry/vdso/vsgx.S
+++ b/arch/x86/entry/vdso/vsgx.S
@@ -4,6 +4,7 @@
#include <asm/export.h>
#include <asm/errno.h>
#include <asm/enclu.h>
+#include <asm/vdso.h>

#include "extable.h"

@@ -27,6 +28,7 @@
SYM_FUNC_START(__vdso_sgx_enter_enclave)
/* Prolog */
.cfi_startproc
+ ENDBR64
push %rbp
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rbp, 0
@@ -64,6 +66,7 @@ SYM_FUNC_START(__vdso_sgx_enter_enclave)
enclu

/* EEXIT jumps here unless the enclave is doing something fancy. */
+ ENDBR64
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx

/* Set exit_reason. */
@@ -91,6 +94,7 @@ SYM_FUNC_START(__vdso_sgx_enter_enclave)
jmp .Lout

.Lhandle_exception:
+ ENDBR64
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx

/* Set the exception info. */
--
2.21.0

2021-08-20 18:27:55

by Yu-cheng Yu

[permalink] [raw]
Subject: [PATCH v29 02/10] x86/cet/ibt: Add user-mode Indirect Branch Tracking support

Introduce user-mode Indirect Branch Tracking (IBT) support. Add routines
for the setup/disable of IBT.

Signed-off-by: Yu-cheng Yu <[email protected]>
Cc: Kees Cook <[email protected]>
---
v28:
- When IBT feature is not present, make ibt_setup() return success,
since this is a setup function.

v27:
- Change struct thread_shstk: ibt_enabled to ibt.
- Create a helper for set/clear bits of MSR_IA32_U_CET.
---
arch/x86/include/asm/cet.h | 9 ++++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/ibt.c | 58 ++++++++++++++++++++++++++++++++++++++
3 files changed, 68 insertions(+)
create mode 100644 arch/x86/kernel/ibt.c

diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index c76a85fbd59f..3dfca29a7c0b 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -14,6 +14,7 @@ struct thread_shstk {
u64 base;
u64 size;
u64 locked:1;
+ u64 ibt:1;
};

#ifdef CONFIG_X86_SHADOW_STACK
@@ -42,6 +43,14 @@ static inline int setup_signal_shadow_stack(int ia32, void __user *restorer) { r
static inline int restore_signal_shadow_stack(void) { return 0; }
#endif

+#ifdef CONFIG_X86_IBT
+int ibt_setup(void);
+void ibt_disable(void);
+#else
+static inline int ibt_setup(void) { return 0; }
+static inline void ibt_disable(void) {}
+#endif
+
#ifdef CONFIG_X86_SHADOW_STACK
int prctl_cet(int option, u64 arg2);
#else
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 39e826b5cabd..cce07a920fec 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -152,6 +152,7 @@ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev.o
obj-$(CONFIG_X86_SHADOW_STACK) += shstk.o
obj-$(CONFIG_X86_SHADOW_STACK) += shstk.o cet_prctl.o
+obj-$(CONFIG_X86_IBT) += ibt.o
###
# 64 bit specific files
ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/ibt.c b/arch/x86/kernel/ibt.c
new file mode 100644
index 000000000000..4ab7af33b274
--- /dev/null
+++ b/arch/x86/kernel/ibt.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ibt.c - Intel Indirect Branch Tracking support
+ *
+ * Copyright (c) 2021, Intel Corporation.
+ * Yu-cheng Yu <[email protected]>
+ */
+
+#include <linux/user.h>
+#include <asm/fpu/internal.h>
+#include <asm/fpu/xstate.h>
+#include <asm/fpu/types.h>
+#include <asm/msr.h>
+#include <asm/cet.h>
+
+static int ibt_set_clear_msr_bits(u64 set, u64 clear)
+{
+ u64 msr;
+ int r;
+
+ fpregs_lock();
+
+ if (test_thread_flag(TIF_NEED_FPU_LOAD))
+ fpregs_restore_userregs();
+
+ r = rdmsrl_safe(MSR_IA32_U_CET, &msr);
+ if (!r) {
+ msr = (msr & ~clear) | set;
+ r = wrmsrl_safe(MSR_IA32_U_CET, msr);
+ }
+
+ fpregs_unlock();
+
+ return r;
+}
+
+int ibt_setup(void)
+{
+ int r;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return 0;
+
+ r = ibt_set_clear_msr_bits(CET_ENDBR_EN | CET_NO_TRACK_EN, 0);
+ if (!r)
+ current->thread.shstk.ibt = 1;
+
+ return r;
+}
+
+void ibt_disable(void)
+{
+ if (!current->thread.shstk.ibt)
+ return;
+
+ ibt_set_clear_msr_bits(0, CET_ENDBR_EN);
+ current->thread.shstk.ibt = 0;
+}
--
2.21.0