Skip to content

Commit

Permalink
gumjs: Always expose thread's system error to NativeCallback
Browse files Browse the repository at this point in the history
Also when Interceptor isn't involved.
  • Loading branch information
oleavr committed May 10, 2024
1 parent d0551e6 commit ca9757b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 14 deletions.
57 changes: 52 additions & 5 deletions bindings/gumjs/gumquickcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ struct _GumQuickCallbackContext
{
JSValue wrapper;
GumQuickCpuContext * cpu_context;
gint * system_error;
GumAddress return_address;
GumAddress raw_return_address;
int initial_property_count;
Expand Down Expand Up @@ -312,9 +313,11 @@ static void gum_quick_native_callback_invoke (ffi_cif * cif,
GUMJS_DECLARE_FINALIZER (gumjs_callback_context_finalize)
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_return_address)
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_cpu_context)
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_system_error)
GUMJS_DECLARE_SETTER (gumjs_callback_context_set_system_error)
static JSValue gum_quick_callback_context_new (GumQuickCore * core,
GumCpuContext * cpu_context, GumAddress raw_return_address,
GumQuickCallbackContext ** context);
GumCpuContext * cpu_context, gint * system_error,
GumAddress raw_return_address, GumQuickCallbackContext ** context);
static gboolean gum_quick_callback_context_get (JSContext * ctx,
JSValueConst val, GumQuickCore * core, GumQuickCallbackContext ** ic);

Expand Down Expand Up @@ -567,6 +570,9 @@ static const JSCFunctionListEntry gumjs_callback_context_entries[] =
JS_CGETSET_DEF ("returnAddress", gumjs_callback_context_get_return_address,
NULL),
JS_CGETSET_DEF ("context", gumjs_callback_context_get_cpu_context, NULL),
JS_CGETSET_DEF (GUMJS_SYSTEM_ERROR_FIELD,
gumjs_callback_context_get_system_error,
gumjs_callback_context_set_system_error),
};

static const JSClassDef gumjs_cpu_context_def =
Expand Down Expand Up @@ -4522,7 +4528,7 @@ gum_quick_native_callback_invoke (ffi_cif * cif,
#endif

this_obj = gum_quick_callback_context_new (core, &cpu_context,
return_address, &jcc);
&saved_system_error, return_address, &jcc);
}

argc = cif->nargs;
Expand All @@ -4544,6 +4550,7 @@ gum_quick_native_callback_invoke (ffi_cif * cif,

if (jcc != NULL)
{
jcc->system_error = NULL;
JS_FreeValue (ctx, jcc->cpu_context->wrapper);
jcc->cpu_context = NULL;
JS_FreeValue (ctx, jcc->wrapper);
Expand Down Expand Up @@ -4577,6 +4584,7 @@ GUMJS_DEFINE_FINALIZER (gumjs_callback_context_finalize)
static JSValue
gum_quick_callback_context_new (GumQuickCore * core,
GumCpuContext * cpu_context,
gint * system_error,
GumAddress raw_return_address,
GumQuickCallbackContext ** context)
{
Expand All @@ -4589,6 +4597,7 @@ gum_quick_callback_context_new (GumQuickCore * core,
jcc = g_slice_new (GumQuickCallbackContext);
jcc->wrapper = wrapper;
jcc->cpu_context = NULL;
jcc->system_error = system_error;
jcc->return_address = 0;
jcc->raw_return_address = raw_return_address;
jcc->initial_property_count = JS_GetOwnPropertyCountUnchecked (wrapper);
Expand Down Expand Up @@ -4647,14 +4656,52 @@ GUMJS_DEFINE_GETTER (gumjs_callback_context_get_cpu_context)
return JS_DupValue (ctx, self->cpu_context->wrapper);
}

GUMJS_DEFINE_GETTER (gumjs_callback_context_get_system_error)
{
GumQuickCallbackContext * self;

if (!gum_quick_callback_context_get (ctx, this_val, core, &self))
return JS_EXCEPTION;

return JS_NewInt32 (ctx, *self->system_error);
}

GUMJS_DEFINE_SETTER (gumjs_callback_context_set_system_error)
{
GumQuickCallbackContext * self;
gint value;

if (!gum_quick_callback_context_get (ctx, this_val, core, &self))
return JS_EXCEPTION;

if (!_gum_quick_int_get (ctx, val, &value))
return JS_EXCEPTION;

*self->system_error = value;

return JS_UNDEFINED;
}

static gboolean
gum_quick_callback_context_get (JSContext * ctx,
JSValueConst val,
GumQuickCore * core,
GumQuickCallbackContext ** cc)
{
return _gum_quick_unwrap (ctx, val, core->callback_context_class, core,
(gpointer *) cc);
GumQuickCallbackContext * c;

if (!_gum_quick_unwrap (ctx, val, core->callback_context_class, core,
(gpointer *) &c))
return FALSE;

if (c->cpu_context == NULL)
{
_gum_quick_throw_literal (ctx, "invalid operation");
return FALSE;
}

*cc = c;
return TRUE;
}

GUMJS_DEFINE_FINALIZER (gumjs_cpu_context_finalize)
Expand Down
50 changes: 42 additions & 8 deletions bindings/gumjs/gumv8core.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2022 Ole André Vadla Ravnås <[email protected]>
* Copyright (C) 2010-2024 Ole André Vadla Ravnås <[email protected]>
* Copyright (C) 2015 Asger Hautop Drewsen <[email protected]>
* Copyright (C) 2015 Marc Hartmayer <[email protected]>
* Copyright (C) 2020-2022 Francesco Tamagni <[email protected]>
Expand Down Expand Up @@ -143,6 +143,7 @@ struct GumV8CallbackContext
{
Global<Object> * wrapper;
Global<Object> * cpu_context;
gint * system_error;
GumAddress return_address;
GumAddress raw_return_address;
};
Expand Down Expand Up @@ -308,11 +309,13 @@ static void gum_v8_native_callback_invoke (ffi_cif * cif,
void * return_value, void ** args, void * user_data);

static GumV8CallbackContext * gum_v8_callback_context_new_persistent (
GumV8Core * core, GumCpuContext * cpu_context,
GumV8Core * core, GumCpuContext * cpu_context, gint * system_error,
GumAddress raw_return_address);
static void gum_v8_callback_context_free (GumV8CallbackContext * self);
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_return_address)
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_cpu_context)
GUMJS_DECLARE_GETTER (gumjs_callback_context_get_system_error)
GUMJS_DECLARE_SETTER (gumjs_callback_context_set_system_error)

GUMJS_DECLARE_CONSTRUCTOR (gumjs_cpu_context_construct)
GUMJS_DECLARE_GETTER (gumjs_cpu_context_get_gpr)
Expand Down Expand Up @@ -482,8 +485,21 @@ static const GumV8Function gumjs_native_function_functions[] =

static const GumV8Property gumjs_callback_context_values[] =
{
{ "returnAddress", gumjs_callback_context_get_return_address, NULL },
{ "context", gumjs_callback_context_get_cpu_context, NULL },
{
"returnAddress",
gumjs_callback_context_get_return_address,
NULL
},
{
"context",
gumjs_callback_context_get_cpu_context,
NULL
},
{
GUMJS_SYSTEM_ERROR_FIELD,
gumjs_callback_context_get_system_error,
gumjs_callback_context_set_system_error
},

{ NULL, NULL, NULL }
};
Expand Down Expand Up @@ -3530,7 +3546,7 @@ gum_v8_native_callback_invoke (ffi_cif * cif,
#endif

jcc = gum_v8_callback_context_new_persistent (self->core, &cpu_context,
return_address);
&error_scope.saved_error, return_address);
recv = Local<Object>::New (isolate, *jcc->wrapper);
}

Expand Down Expand Up @@ -3566,6 +3582,7 @@ gum_v8_native_callback_invoke (ffi_cif * cif,
static GumV8CallbackContext *
gum_v8_callback_context_new_persistent (GumV8Core * core,
GumCpuContext * cpu_context,
gint * system_error,
GumAddress raw_return_address)
{
auto isolate = core->isolate;
Expand All @@ -3576,12 +3593,13 @@ gum_v8_callback_context_new_persistent (GumV8Core * core,
*core->callback_context_value);
auto wrapper = callback_context_value->Clone ();
wrapper->SetAlignedPointerInInternalField (0, jcc);
jcc->wrapper = new Global<Object> (isolate, wrapper);
jcc->return_address = 0;
jcc->raw_return_address = raw_return_address;

jcc->wrapper = new Global<Object> (isolate, wrapper);
jcc->cpu_context = new Global<Object> (isolate,
_gum_v8_cpu_context_new_immutable (cpu_context, core));
jcc->system_error = system_error;
jcc->return_address = 0;
jcc->raw_return_address = raw_return_address;

return jcc;
}
Expand Down Expand Up @@ -3639,6 +3657,22 @@ GUMJS_DEFINE_CLASS_GETTER (gumjs_callback_context_get_cpu_context,
info.GetReturnValue ().Set (Local<Object>::New (isolate, *context));
}

GUMJS_DEFINE_CLASS_GETTER (gumjs_callback_context_get_system_error,
GumV8CallbackContext)
{
info.GetReturnValue ().Set (*self->system_error);
}

GUMJS_DEFINE_CLASS_SETTER (gumjs_callback_context_set_system_error,
GumV8CallbackContext)
{
gint system_error;
if (!_gum_v8_int_get (value, &system_error, core))
return;

*self->system_error = system_error;
}

GUMJS_DEFINE_CONSTRUCTOR (gumjs_cpu_context_construct)
{
GumCpuContext * cpu_context = NULL;
Expand Down
1 change: 0 additions & 1 deletion bindings/gumjs/gumv8core.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ class GumV8SystemErrorPreservationScope
gum_thread_set_system_error (saved_error);
}

private:
gint saved_error;
};

Expand Down
36 changes: 36 additions & 0 deletions tests/gumjs/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ TESTLIST_BEGIN (script)

TESTGROUP_BEGIN ("NativeCallback")
TESTENTRY (native_callback_can_be_invoked)
TESTENTRY (native_callback_should_provide_access_to_system_error)
TESTENTRY (native_callback_is_a_native_pointer)
TESTENTRY (native_callback_memory_should_be_eagerly_reclaimed)
TESTENTRY (native_callback_should_be_kept_alive_during_calls)
Expand Down Expand Up @@ -2173,6 +2174,41 @@ TESTCASE (native_callback_can_be_invoked)
g_assert_cmpstr (str, ==, "BADGER");
}

TESTCASE (native_callback_should_provide_access_to_system_error)
{
void (* callback) (void);

#ifdef HAVE_WINDOWS
COMPILE_AND_LOAD_SCRIPT (
"const cb = new NativeCallback(function () {"
" send(this.lastError);"
" this.lastError = this.lastError + 37;"
" return 0;"
"}, 'void', []);"
GUM_PTR_CONST ".writePointer(cb);", &callback);
EXPECT_NO_MESSAGES ();

SetLastError (1300);
callback ();
g_assert_cmpuint (GetLastError (), ==, 1337);
#else
COMPILE_AND_LOAD_SCRIPT (
"const cb = new NativeCallback(function () {"
" send(this.errno);"
" this.errno = this.errno + 37;"
" return 0;"
"}, 'void', []);"
GUM_PTR_CONST ".writePointer(cb);", &callback);
EXPECT_NO_MESSAGES ();

errno = 1300;
callback ();
g_assert_cmpuint (errno, ==, 1337);
#endif

EXPECT_SEND_MESSAGE_WITH ("1300");
}

TESTCASE (native_callback_is_a_native_pointer)
{
COMPILE_AND_LOAD_SCRIPT (
Expand Down

0 comments on commit ca9757b

Please sign in to comment.