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 v24:
- Split IBT into a separate Kconfig option, update related areas
accordingly. Specific changes are called out in each patch's commit
log.
- Patch #7: Update ENDBR definition with compiler macros.
- Rebase to Linus tree v5.12-rc5.
[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
[2] Indirect Branch Tracking patches v23:
https://lore.kernel.org/r/20210316151320.6123-1-yu-cheng.yu@intel.com/
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 (6):
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: 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 | 22 +++++++++
arch/x86/entry/vdso/Makefile | 5 +++
arch/x86/entry/vdso/vdso32/system_call.S | 2 +
arch/x86/entry/vdso/vsgx.S | 4 ++
arch/x86/include/asm/cet.h | 9 ++++
arch/x86/include/asm/disabled-features.h | 8 +++-
arch/x86/include/asm/vdso.h | 19 +++++++-
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/cet_prctl.c | 5 +++
arch/x86/kernel/fpu/signal.c | 30 +++++++++++--
arch/x86/kernel/ibt.c | 57 ++++++++++++++++++++++++
arch/x86/kernel/process_64.c | 8 ++++
12 files changed, 165 insertions(+), 5 deletions(-)
create mode 100644 arch/x86/kernel/ibt.c
--
2.21.0
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 <redacted>
Cc: Kees Cook <redacted>
---
arch/x86/Kconfig | 20 ++++++++++++++++++++
arch/x86/include/asm/disabled-features.h | 8 +++++++-
2 files changed, 27 insertions(+), 1 deletion(-)
From: "H.J. Lu" <redacted>
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 <redacted>
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Kees Cook <redacted>
---
arch/x86/entry/vdso/vdso32/system_call.S | 2 ++
1 file changed, 2 insertions(+)
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 <redacted>
Cc: Kees Cook <redacted>
---
v24:
- Update for changes introduced from splitting shadow stack and ibt.
arch/x86/Kconfig | 2 ++
arch/x86/kernel/process_64.c | 8 ++++++++
2 files changed, 10 insertions(+)
When an indirect CALL/JMP instruction is executed and before it reaches
the target, it is in 'WAIT_ENDBR' status, which can be read from
MSR_IA32_U_CET. The status is part of a task's status before a signal is
raised and preserved in the signal frame. It is restored for sigreturn.
IBT state machine is described in Intel SDM Vol. 1, Sec. 18.3.
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Kees Cook <redacted>
---
v24:
- Update for changes from splitting shadow stack and ibt.
arch/x86/kernel/fpu/signal.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
@@ -626,7 +650,7 @@ static unsigned long fpu__alloc_sigcontext_ext(unsigned long sp)*sigcontext_extisat:fpu+fpu_user_xstate_size+*FP_XSTATE_MAGIC2_SIZE,thenalignedto8.*/-if(cet->shstk_size)+if(cet->shstk_size||cet->ibt_enabled)sp-=(sizeof(structsc_ext)+8);#endifreturnsp;
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() branch targets.
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
---
arch/x86/entry/vdso/vsgx.S | 4 ++++
1 file changed, 4 insertions(+)
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.
There are two ENDBR versions: endbr64 and endbr32. The compilers (gcc and
clang) have _CET_ENDBR defined for the proper one. Introduce ENDBR macro,
which equals the compiler macro when enabled, otherwise nothing.
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
---
arch/x86/entry/vdso/Makefile | 1 +
arch/x86/include/asm/vdso.h | 19 ++++++++++++++++++-
2 files changed, 19 insertions(+), 1 deletion(-)
From: "H.J. Lu" <redacted>
When Indirect Branch Tracking (IBT) is enabled, vDSO functions may be
called indirectly, and must have ENDBR32 or ENDBR64 as the first
instruction. The compiler must support -fcf-protection=branch so that it
can be used to compile vDSO.
Signed-off-by: H.J. Lu <redacted>
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Kees Cook <redacted>
---
v24:
- Replace CONFIG_X86_CET with CONFIG_X86_IBT to reflect splitting of shadow
stack and ibt.
arch/x86/entry/vdso/Makefile | 4 ++++
1 file changed, 4 insertions(+)
From: Jarkko Sakkinen <jarkko@kernel.org> Date: 2021-04-04 15:54:43
On Thu, Apr 01, 2021 at 03:14:03PM -0700, Yu-cheng Yu wrote:
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() branch targets.
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
From: Sean Christopherson <seanjc@google.com> Date: 2021-05-24 18:51:24
On Thu, Apr 01, 2021, Yu-cheng Yu wrote:
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() branch targets.
^
|- indirect
After reading the changelog, I was expecting ENDBR on every label.
quoted hunk
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
---
arch/x86/entry/vdso/vsgx.S | 4 ++++
1 file changed, 4 insertions(+)
It would be better to move this below the comment about EEXIT. As is, it looks
like a misplaced annotation on the AEP. The AEP doesn't need ENDBR, it's the
EEXIT target that needs ENDBR because EEXIT is treated as an indirect branch.
Might also be helpful for future readers to explicitly state in the changelog
that EEXIT is considered an indirect branch.
I.e.
/* EEXIT jumps here unless the enclave is doing something fancy. */
ENDBR
quoted hunk
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
@@ -91,6 +94,7 @@ SYM_FUNC_START(__vdso_sgx_enter_enclave) jmp .Lout .Lhandle_exception:+ ENDBR mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx /* Set the exception info. */
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() branch targets.
^
|- indirect
After reading the changelog, I was expecting ENDBR on every label.
Sorry about the confusion.
quoted
Signed-off-by: Yu-cheng Yu <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
---
arch/x86/entry/vdso/vsgx.S | 4 ++++
1 file changed, 4 insertions(+)
It would be better to move this below the comment about EEXIT. As is, it looks
like a misplaced annotation on the AEP. The AEP doesn't need ENDBR, it's the
EEXIT target that needs ENDBR because EEXIT is treated as an indirect branch.
Might also be helpful for future readers to explicitly state in the changelog
that EEXIT is considered an indirect branch.
I.e.
quoted
/* EEXIT jumps here unless the enclave is doing something fancy. */
ENDBR
quoted
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
@@ -91,6 +94,7 @@ SYM_FUNC_START(__vdso_sgx_enter_enclave) jmp .Lout .Lhandle_exception:+ ENDBR mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx /* Set the exception info. */