Commit b6e6cc1f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86_urgent_for_6.5_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 CFI fixes from Peter Zijlstra:
 "Fix kCFI/FineIBT weaknesses

  The primary bug Alyssa noticed was that with FineIBT enabled function
  prologues have a spurious ENDBR instruction:

    __cfi_foo:
	endbr64
	subl	$hash, %r10d
	jz	1f
	ud2
	nop
    1:
    foo:
	endbr64 <--- *sadface*

  This means that any indirect call that fails to target the __cfi
  symbol and instead targets (the regular old) foo+0, will succeed due
  to that second ENDBR.

  Fixing this led to the discovery of a single indirect call that was
  still doing this: ret_from_fork(). Since that's an assembly stub the
  compiler would not generate the proper kCFI indirect call magic and it
  would not get patched.

  Brian came up with the most comprehensive fix -- convert the thing to
  C with only a very thin asm wrapper. This ensures the kernel thread
  boostrap is a proper kCFI call.

  While discussing all this, Kees noted that kCFI hashes could/should be
  poisoned to seal all functions whose address is never taken, further
  limiting the valid kCFI targets -- much like we already do for IBT.

  So what was a 'simple' observation and fix cascaded into a bunch of
  inter-related CFI infrastructure fixes"

* tag 'x86_urgent_for_6.5_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/cfi: Only define poison_cfi() if CONFIG_X86_KERNEL_IBT=y
  x86/fineibt: Poison ENDBR at +0
  x86: Rewrite ret_from_fork() in C
  x86/32: Remove schedule_tail_wrapper()
  x86/cfi: Extend ENDBR sealing to kCFI
  x86/alternative: Rename apply_ibt_endbr()
  x86/cfi: Extend {JMP,CAKK}_NOSPEC comment
parents be522ac7 535d0ae3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -437,7 +437,7 @@ void __init arch_cpu_finalize_init(void)
	os_check_bugs();
}

void apply_ibt_endbr(s32 *start, s32 *end)
void apply_seal_endbr(s32 *start, s32 *end)
{
}

+13 −40
Original line number Diff line number Diff line
@@ -719,26 +719,6 @@ SYM_CODE_START(__switch_to_asm)
SYM_CODE_END(__switch_to_asm)
.popsection

/*
 * The unwinder expects the last frame on the stack to always be at the same
 * offset from the end of the page, which allows it to validate the stack.
 * Calling schedule_tail() directly would break that convention because its an
 * asmlinkage function so its argument has to be pushed on the stack.  This
 * wrapper creates a proper "end of stack" frame header before the call.
 */
.pushsection .text, "ax"
SYM_FUNC_START(schedule_tail_wrapper)
	FRAME_BEGIN

	pushl	%eax
	call	schedule_tail
	popl	%eax

	FRAME_END
	RET
SYM_FUNC_END(schedule_tail_wrapper)
.popsection

/*
 * A newly forked process directly context switches into this address.
 *
@@ -747,29 +727,22 @@ SYM_FUNC_END(schedule_tail_wrapper)
 * edi: kernel thread arg
 */
.pushsection .text, "ax"
SYM_CODE_START(ret_from_fork)
	call	schedule_tail_wrapper
SYM_CODE_START(ret_from_fork_asm)
	movl	%esp, %edx	/* regs */

	testl	%ebx, %ebx
	jnz	1f		/* kernel threads are uncommon */
	/* return address for the stack unwinder */
	pushl	$.Lsyscall_32_done

2:
	/* When we fork, we trace the syscall return in the child, too. */
	movl    %esp, %eax
	call    syscall_exit_to_user_mode
	jmp     .Lsyscall_32_done
	FRAME_BEGIN
	/* prev already in EAX */
	movl	%ebx, %ecx	/* fn */
	pushl	%edi		/* fn_arg */
	call	ret_from_fork
	addl	$4, %esp
	FRAME_END

	/* kernel thread */
1:	movl	%edi, %eax
	CALL_NOSPEC ebx
	/*
	 * A kernel thread is allowed to return here after successfully
	 * calling kernel_execve().  Exit to userspace to complete the execve()
	 * syscall.
	 */
	movl	$0, PT_EAX(%esp)
	jmp	2b
SYM_CODE_END(ret_from_fork)
	RET
SYM_CODE_END(ret_from_fork_asm)
.popsection

SYM_ENTRY(__begin_SYSENTER_singlestep_region, SYM_L_GLOBAL, SYM_A_NONE)
+8 −25
Original line number Diff line number Diff line
@@ -284,36 +284,19 @@ SYM_FUNC_END(__switch_to_asm)
 * r12: kernel thread arg
 */
.pushsection .text, "ax"
	__FUNC_ALIGN
SYM_CODE_START_NOALIGN(ret_from_fork)
	UNWIND_HINT_END_OF_STACK
SYM_CODE_START(ret_from_fork_asm)
	UNWIND_HINT_REGS
	ANNOTATE_NOENDBR // copy_thread
	CALL_DEPTH_ACCOUNT
	movq	%rax, %rdi
	call	schedule_tail			/* rdi: 'prev' task parameter */

	testq	%rbx, %rbx			/* from kernel_thread? */
	jnz	1f				/* kernel threads are uncommon */
	movq	%rax, %rdi		/* prev */
	movq	%rsp, %rsi		/* regs */
	movq	%rbx, %rdx		/* fn */
	movq	%r12, %rcx		/* fn_arg */
	call	ret_from_fork

2:
	UNWIND_HINT_REGS
	movq	%rsp, %rdi
	call	syscall_exit_to_user_mode	/* returns with IRQs disabled */
	jmp	swapgs_restore_regs_and_return_to_usermode

1:
	/* kernel thread */
	UNWIND_HINT_END_OF_STACK
	movq	%r12, %rdi
	CALL_NOSPEC rbx
	/*
	 * A kernel thread is allowed to return here after successfully
	 * calling kernel_execve().  Exit to userspace to complete the execve()
	 * syscall.
	 */
	movq	$0, RAX(%rsp)
	jmp	2b
SYM_CODE_END(ret_from_fork)
SYM_CODE_END(ret_from_fork_asm)
.popsection

.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
+1 −1
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ extern void alternative_instructions(void);
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
extern void apply_retpolines(s32 *start, s32 *end);
extern void apply_returns(s32 *start, s32 *end);
extern void apply_ibt_endbr(s32 *start, s32 *end);
extern void apply_seal_endbr(s32 *start, s32 *end);
extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
			  s32 *start_cfi, s32 *end_cfi);

+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@
/*
 * Create a dummy function pointer reference to prevent objtool from marking
 * the function as needing to be "sealed" (i.e. ENDBR converted to NOP by
 * apply_ibt_endbr()).
 * apply_seal_endbr()).
 */
#define IBT_NOSEAL(fname)				\
	".pushsection .discard.ibt_endbr_noseal\n\t"	\
Loading