Skip to content

Commit 666e10e

Browse files
committed
x86: Shadow stacks compatibility for interceptor
This patch makes interceptor code compatible with Intel CET shadow stacks. * Make the on_leave_trampoline a legit address to return to from a CET-enabled intercepted function's point of view. * Ensure a proper call/ret discipline to not interfere shadow stacks. On Windows, this means that it will now be possible to intercept functions that live in CETCOMPAT modules when the user shadow stack mitigation is active (though not in strict mode).
1 parent 579c096 commit 666e10e

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

gum/backend-x86/guminterceptor-x86.c

+29-5
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ _gum_interceptor_backend_create_trampoline (GumInterceptorBackend * self,
171171
GumX86Relocator * rl = &self->relocator;
172172
GumX86FunctionContextData * data = GUM_FCDATA (ctx);
173173
GumAddress function_ctx_ptr;
174+
gpointer after_push_to_shadow_stack;
174175
guint reloc_bytes;
175176

176177
if (!gum_interceptor_backend_prepare_trampoline (self, ctx))
@@ -184,11 +185,24 @@ _gum_interceptor_backend_create_trampoline (GumInterceptorBackend * self,
184185
gum_x86_writer_put_bytes (cw, (guint8 *) &ctx,
185186
sizeof (GumFunctionContext *));
186187

187-
ctx->on_enter_trampoline = gum_x86_writer_cur (cw);
188+
after_push_to_shadow_stack = gum_x86_writer_cur (cw);
188189

190+
gum_x86_writer_put_lea_reg_reg_offset (cw, GUM_X86_XSP,
191+
GUM_X86_XSP, ((gssize) sizeof (gpointer)));
189192
gum_x86_writer_put_push_near_ptr (cw, function_ctx_ptr);
190193
gum_x86_writer_put_jmp_address (cw, GUM_ADDRESS (self->enter_thunk->data));
191194

195+
ctx->on_enter_trampoline = gum_x86_writer_cur (cw);
196+
197+
// We use a call instruction to push on_leave_trampoline as a legit return
198+
// address on the shadow stack.
199+
//
200+
// SAFETY: We call to a label that is only a few bytes away, so this will
201+
// only emit a call instruction (not a call-jump combo). So the
202+
// current position of the writer after emission is the exact return
203+
// address that will be pushed on the stack and the shadow stack.
204+
gum_x86_writer_put_call_address (cw, GUM_ADDRESS (after_push_to_shadow_stack));
205+
192206
ctx->on_leave_trampoline = gum_x86_writer_cur (cw);
193207

194208
gum_x86_writer_put_push_near_ptr (cw, function_ctx_ptr);
@@ -338,7 +352,7 @@ gum_emit_enter_thunk (GumX86Writer * cw)
338352
GUM_ARG_REGISTER, GUM_X86_XDX,
339353
GUM_ARG_REGISTER, GUM_X86_XCX);
340354

341-
gum_emit_epilog (cw);
355+
gum_emit_epilog (cw, FALSE);
342356
}
343357

344358
static void
@@ -359,7 +373,7 @@ gum_emit_leave_thunk (GumX86Writer * cw)
359373
GUM_ARG_REGISTER, GUM_X86_XSI,
360374
GUM_ARG_REGISTER, GUM_X86_XDX);
361375

362-
gum_emit_epilog (cw);
376+
gum_emit_epilog (cw, TRUE);
363377
}
364378

365379
static void
@@ -401,7 +415,7 @@ gum_emit_prolog (GumX86Writer * cw,
401415
}
402416

403417
static void
404-
gum_emit_epilog (GumX86Writer * cw)
418+
gum_emit_epilog (GumX86Writer * cw, gboolean do_ret)
405419
{
406420
guint8 fxrstor[] = {
407421
0x0f, 0xae, 0x0c, 0x24 /* fxrstor [esp] */
@@ -415,5 +429,15 @@ gum_emit_epilog (GumX86Writer * cw)
415429
GumCpuContext.xip */
416430
gum_x86_writer_put_popax (cw);
417431
gum_x86_writer_put_popfx (cw);
418-
gum_x86_writer_put_ret (cw);
432+
433+
if (do_ret) {
434+
gum_x86_writer_put_ret (cw);
435+
}
436+
else {
437+
// emulates a ret, but does not affect the shadow stack
438+
gum_x86_writer_put_lea_reg_reg_offset (cw, GUM_X86_XSP,
439+
GUM_X86_XSP, ((gssize) sizeof (gpointer)));
440+
gum_x86_writer_put_jmp_reg_offset_ptr (cw, GUM_X86_XSP,
441+
-((gssize) sizeof (gpointer)));
442+
}
419443
}

gum/guminterceptor.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -1619,12 +1619,21 @@ _gum_function_context_begin_invocation (GumFunctionContext * function_ctx,
16191619

16201620
if (!will_trap_on_leave)
16211621
{
1622-
g_atomic_int_dec_and_test (&function_ctx->trampoline_usage_counter);
1622+
goto bypass;
16231623
}
16241624

16251625
return;
16261626

16271627
bypass:
1628+
// pop on_leave_trampoline from the shadow stack
1629+
#if defined (HAVE_I386)
1630+
# if GLIB_SIZEOF_VOID_P == 4
1631+
_incsspd(1);
1632+
# else
1633+
_incsspq(1);
1634+
# endif
1635+
#endif
1636+
16281637
g_atomic_int_dec_and_test (&function_ctx->trampoline_usage_counter);
16291638
}
16301639

0 commit comments

Comments
 (0)