Re: [PATCH v2 4/4] x86/static_call: Add inline static call implementation for x86-64

Josh Poimboeuf
2018-11-30T18:39:23Z

On Fri, Nov 30, 2018 at 08:42:26AM -0800, Andy Lutomirski wrote:
> On Thu, Nov 29, 2018 at 12:24 PM Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> >
> > > Alternatively, we could actually emulate call instructions like this:
> > >
> > > void __noreturn jump_to_kernel_pt_regs(struct pt_regs *regs, ...)
> > > {
> > > struct pt_regs ptregs_copy = *regs;
> > > barrier();
> > > *(unsigned long *)(regs->sp - 8) = whatever; /* may clobber old
> > > regs, but so what? */
> > > asm volatile ("jmp return_to_alternate_ptregs");
> > > }
> > >
> > > where return_to_alternate_ptregs points rsp to the ptregs and goes
> > > through the normal return path. It's ugly, but we could have a test
> > > case for it, and it should work fine.
> >
> > Is that really any better than my patch to create a gap in the stack
> > (modified for kernel space #BP only)?
> >
>
> I tend to prefer a nice local hack like mine over a hack that further
> complicates the entry in general. This is not to say I'm thrilled by
> my idea either.

They're both mucking with the location of the pt_regs. The above code
just takes that fact and hides it in the corner and hopes that there are
no bugs lurking there.

Even with the CPL check, the "gap" code is simple and self-contained
(see below). The kernel pt_regs can already be anywhere on the stack so
there should be no harm in moving them.

AFAICT, all the other proposed options seem to have major issues.

diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index ce25d84023c0..f487f7daed6c 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -876,7 +876,7 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt
* @paranoid == 2 is special: the stub will never switch stacks. This is for
* #DF: if the thread stack is somehow unusable, we'll still get a useful OOPS.
*/
-.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 create_gap=1
ENTRY(\sym)
UNWIND_HINT_IRET_REGS offset=\has_error_code*8

@@ -896,6 +896,18 @@ ENTRY(\sym)
jnz .Lfrom_usermode_switch_stack_\@
.endif

+#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
+ .if \create_gap == 1
+ testb $3, CS-ORIG_RAX(%rsp)
+ jnz .Lfrom_usermode_no_gap_\@
+ .rept 6
+ pushq 5*8(%rsp)
+ .endr
+ UNWIND_HINT_IRET_REGS offset=8
+.Lfrom_usermode_no_gap_\@:
+ .endif
+#endif
+
.if \paranoid
call paranoid_entry
.else
@@ -1126,7 +1138,7 @@ apicinterrupt3 HYPERV_STIMER0_VECTOR \
#endif /* CONFIG_HYPERV */

idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry int3 do_int3 has_error_code=0
+idtentry int3 do_int3 has_error_code=0 create_gap=1
idtentry stack_segment do_stack_segment has_error_code=1

#ifdef CONFIG_XEN_PV