aboutsummaryrefslogtreecommitdiff
path: root/lib/hook-functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hook-functions.c')
-rw-r--r--lib/hook-functions.c81
1 files changed, 41 insertions, 40 deletions
diff --git a/lib/hook-functions.c b/lib/hook-functions.c
index daf4093..5a502c8 100644
--- a/lib/hook-functions.c
+++ b/lib/hook-functions.c
@@ -11,7 +11,7 @@ struct hook_internal {
int offset_by_pcdiff[JUMP_PATCH_SIZE + 1];
uint8_t jump_patch[MAX_JUMP_PATCH_SIZE];
size_t jump_patch_size;
- uintptr_t pc_patch_start;
+ void *code;
void *outro_trampoline;
/* page allocated with execmem_alloc_unsealed - only if we had to allocate
* one when processing this hook */
@@ -21,18 +21,17 @@ struct hook_internal {
struct pc_callback_info {
struct hook_internal *his;
size_t nhooks;
-}
+};
static uintptr_t pc_callback(void *ctx, uintptr_t pc) {
struct pc_callback_info *restrict info = ctx;
uintptr_t real_pc = pc;
#ifdef __arm__
- bool thumb = pc & 1;
real_pc = pc & ~1;
#endif
for (size_t i = 0; i < info->nhooks; i++) {
struct hook_internal *hi = &info->his[i];
- uintptr_t diff = real_pc - hi->pc_patch_start;
+ uintptr_t diff = real_pc - (uintptr_t) hi->code;
if (diff < hi->jump_patch_size)
return (uintptr_t) hi->outro_trampoline + hi->offset_by_pcdiff[diff];
}
@@ -54,31 +53,27 @@ static uintptr_t pc_callback(void *ctx, uintptr_t pc) {
* If even that is out of range, then return an error code.
*/
-static int check_intro_trampline(void **trampoline_ptr_p
- size_t *trampoline_size_left_p,
- uintptr_t pc,
- uintptr_t dpc,
- int *patch_size_p,
- bool *need_intro_trampoline_p,
- void **trampoline_page_p,
- struct arch_dis_ctx arch) {
+static int check_intro_trampoline(void **trampoline_ptr_p,
+ size_t *trampoline_size_left_p,
+ uintptr_t pc,
+ uintptr_t dpc,
+ int *patch_size_p,
+ bool *need_intro_trampoline_p,
+ void **trampoline_page_p,
+ struct arch_dis_ctx arch) {
void *trampoline_ptr = *trampoline_ptr_p;
size_t trampoline_size_left = *trampoline_size_left_p;
/* Try direct */
*need_intro_trampoline_p = false;
- *patch_size_p = jump_patch_size(pc_patch_start,
- (uintptr_t) hook->replacement,
- arch);
+ *patch_size_p = jump_patch_size(pc, dpc, arch, /*force*/ false);
if (*patch_size_p != -1)
return SUBSTITUTE_OK;
/* Try existing trampoline */
- *patch_size_p = jump_patch_size(pc_patch_start,
- (uintptr_t) *trampoline_ptr,
- arch);
+ *patch_size_p = jump_patch_size(pc, (uintptr_t) trampoline_ptr, arch, false);
- if (*patch_size_p != -1 && *patch_size_p <= *trampoline_size_left_p)
+ if (*patch_size_p != -1 && (size_t) *patch_size_p <= *trampoline_size_left_p)
return SUBSTITUTE_OK;
/* Allocate new trampoline - try after dpc. If this fails, we can try
@@ -87,9 +82,7 @@ static int check_intro_trampline(void **trampoline_ptr_p
if (ret)
goto skip_after;
- *patch_size_p = jump_patch_size(pc_patch_start,
- (uintptr_t) *trampoline_ptr,
- arch);
+ *patch_size_p = jump_patch_size(pc, (uintptr_t) trampoline_ptr, arch, false);
if (*patch_size_p != -1) {
*trampoline_ptr_p = trampoline_ptr;
*trampoline_size_left_p = trampoline_size_left;
@@ -99,16 +92,14 @@ static int check_intro_trampline(void **trampoline_ptr_p
execmem_free(trampoline_ptr);
-skip_after:
+skip_after:;
/* Allocate new trampoline - try before dpc (xxx only meaningful on arm64) */
uintptr_t start_address = dpc - 0xffff0000;
ret = execmem_alloc_unsealed(start_address, &trampoline_ptr, &trampoline_size_left);
if (ret)
return ret;
- *patch_size_p = jump_patch_size(pc_patch_start,
- (uintptr_t) *trampoline_ptr,
- arch);
+ *patch_size_p = jump_patch_size(pc, (uintptr_t) trampoline_ptr, arch, false);
if (*patch_size_p != -1) {
*trampoline_ptr_p = trampoline_ptr;
*trampoline_size_left_p = trampoline_size_left;
@@ -126,7 +117,7 @@ EXPORT
int substitute_hook_functions(const struct substitute_function_hook *hooks,
size_t nhooks,
int options) {
- struct hook_internal *his = malloc(nhooks * sizeof(*hi));
+ struct hook_internal *his = malloc(nhooks * sizeof(*his));
if (!his)
return SUBSTITUTE_ERR_OOM;
@@ -160,6 +151,7 @@ int substitute_hook_functions(const struct substitute_function_hook *hooks,
code--;
}
#endif
+ hi->code = code;
uintptr_t pc_patch_start = (uintptr_t) code;
int patch_size;
bool need_intro_trampoline;
@@ -180,7 +172,6 @@ int substitute_hook_functions(const struct substitute_function_hook *hooks,
void *jp = hi->jump_patch;
make_jump_patch(&jp, pc_patch_start, initial_target, arch);
hi->jump_patch_size = (uint8_t *) jp - hi->jump_patch;
- hi->pc_patch_start = pc_patch_start;
uintptr_t pc_patch_end = pc_patch_start + patch_size;
/* Generate the rewritten start of the function for the outro
@@ -188,19 +179,27 @@ int substitute_hook_functions(const struct substitute_function_hook *hooks,
uint8_t rewritten_temp[MAX_REWRITTEN_SIZE];
void *rp = rewritten_temp;
if ((ret = transform_dis_main(code, &rp, pc_patch_start, pc_patch_end,
- arch, hi->offset_by_pcdiff))
+ arch, hi->offset_by_pcdiff)))
goto end;
/* Check some of the rest of the function for jumps back into the
* patched region. */
- if ((ret = jump_dis(code, pc_patch_start, pc_patch_end, arch)))
+ if ((ret = jump_dis_main(code, pc_patch_start, pc_patch_end, arch)))
goto end;
- size_t rewritten_size = (uint8_t *) rp - hi->rewritten_temp;
- if (trampoline_size_left < rewritten_size) {
+ size_t rewritten_size = (uint8_t *) rp - rewritten_temp;
+ size_t jumpback_size =
+ jump_patch_size((uintptr_t) trampoline_ptr + rewritten_size,
+ pc_patch_end, arch, /* force */ true);
+ size_t outro_size = rewritten_size + jumpback_size;
+ if (outro_size > trampoline_size_left) {
/* Not enough space left in our existing block... */
- if (ret = execmem_alloc_unsealed(0, &trampoline_ptr,
- &trampoline_size_left))
+ if ((ret = execmem_alloc_unsealed(0, &trampoline_ptr,
+ &trampoline_size_left)))
goto end;
+ jumpback_size =
+ jump_patch_size((uintptr_t) trampoline_ptr + rewritten_size,
+ pc_patch_end, arch, /* force */ true);
+ outro_size = rewritten_size + jumpback_size;
}
hi->outro_trampoline = trampoline_ptr;
@@ -209,7 +208,10 @@ int substitute_hook_functions(const struct substitute_function_hook *hooks,
hi->outro_trampoline++;
#endif
memcpy(trampoline_ptr, rewritten_temp, rewritten_size);
- trampoline_size_left -= rewritten_size;
+ trampoline_ptr += rewritten_size;
+ make_jump_patch(&trampoline_ptr, (uintptr_t) trampoline_ptr, pc_patch_end,
+ arch);
+ trampoline_size_left -= outro_size;
}
/* Now commit. */
@@ -217,20 +219,19 @@ int substitute_hook_functions(const struct substitute_function_hook *hooks,
const struct substitute_function_hook *hook = &hooks[i];
struct hook_internal *hi = &his[i];
emw_finished_i = (ssize_t) i;
- if ((ret = execmem_write(hi->pc_patch_start, hi->jump_patch,
- hi->jump_patch_size))) {
+ if ((ret = execmem_write(hi->code, hi->jump_patch, hi->jump_patch_size))) {
/* User is probably screwed, since this probably means a failure to
* re-protect exec, thanks to code signing, so now the function is
* permanently inaccessible. */
goto end;
}
if (hook->old_ptr)
- *(void **) hook_old_ptr = hi->outro_trampoline;
+ *(void **) hook->old_ptr = hi->outro_trampoline;
}
/* *sigh of relief* now we can rewrite the PCs. */
if (stopped) {
- struct pc_callback_info info = {hi, nhooks};
+ struct pc_callback_info info = {his, nhooks};
if ((ret = apply_pc_patch_callback(stop_token, pc_callback, &info)))
goto end;
}
@@ -241,7 +242,7 @@ end:
if (page) {
/* if we failed, get rid of the trampolines. if we succeeded, make
* them executable */
- if (ret && i >= emw_finished) {
+ if (ret && (ssize_t) i >= emw_finished_i) {
execmem_free(page);
} else {
/* we already patched them all, too late to go back.. */