diff --git a/upatch-manage/process_entity.c b/upatch-manage/process_entity.c index 281a85e9eab48131852417bf8e929751523f1c56..a3568982ebbdf440a9610d19aabc82277f96b6f0 100644 --- a/upatch-manage/process_entity.c +++ b/upatch-manage/process_entity.c @@ -141,18 +141,31 @@ static bool is_patch_removable(pid_t pid, const void *page, void *context) static const size_t VALUE_NR = PAGE_SIZE / sizeof(unsigned long); const struct patch_info *patch = context; + const unsigned long *stack_page = page; + unsigned long stack_value; + size_t i; - const bool check_text = (patch->text_len > 0); - const unsigned long text_start = patch->text_addr; - const unsigned long text_end = patch->text_addr + patch->text_len; + struct patch_jump_entry *entry; + int bkt; - const unsigned long *page_data = page; - size_t i; + if (unlikely(patch->jump_min_addr >= patch->jump_max_addr)) { + return true; + } for (i = 0; i < VALUE_NR; i++) { - if (check_text && unlikely(page_data[i] >= text_start && page_data[i] < text_end)) { - log_err("process %d: found patch text 0x%lx on stack\n", pid, page_data[i]); - return false; + stack_value = stack_page[i]; + + /* Filter value does not in jump table range */ + if (likely(stack_value < patch->jump_min_addr || stack_value >= patch->jump_max_addr)) { + continue; + } + + /* Check if value is on the jump table */ + hash_for_each(patch->jump_table, bkt, entry, node) { + if (unlikely(stack_value >= entry->new_addr && stack_value < entry->new_end)) { + log_err("process %d: found patch function 0x%lx on stack\n", pid, entry->new_addr); + return false; + } } } @@ -294,6 +307,9 @@ int process_load_patch(struct process_entity *process, struct patch_entity *patc patch_info->rodata_addr = ctx->layout.base + ctx->layout.text_end; patch_info->rodata_len = ctx->layout.ro_after_init_end - ctx->layout.text_end; + patch_info->jump_min_addr = ULONG_MAX; + patch_info->jump_max_addr = 0; + hash_init(patch_info->jump_table); for (i = 0; i < func_num; ++i) { @@ -308,6 +324,14 @@ int process_load_patch(struct process_entity *process, struct patch_entity *patc INIT_HLIST_NODE(&jump_entry->node); jump_entry->old_addr = funcs[i].old_addr + ctx->load_bias + ctx->target->load_offset; jump_entry->new_addr = funcs[i].new_addr; + jump_entry->new_end = funcs[i].new_addr + funcs[i].new_size; + + if (patch_info->jump_min_addr > jump_entry->new_addr) { + patch_info->jump_min_addr = jump_entry->new_addr; + } + if (patch_info->jump_max_addr < jump_entry->new_end) { + patch_info->jump_max_addr = jump_entry->new_end; + } log_debug("process %d: old_addr=0x%08lx, new_addr=0x%08lx, func='%s'\n", process->tgid, jump_entry->old_addr, jump_entry->new_addr, func_name); diff --git a/upatch-manage/process_entity.h b/upatch-manage/process_entity.h index 8e8c71d5a8e8a1f1fcf711dec3ed3053ec76a695..de6635a8c5199ccd8b96d70349109c585da2e954 100644 --- a/upatch-manage/process_entity.h +++ b/upatch-manage/process_entity.h @@ -43,6 +43,7 @@ struct patch_jump_entry { unsigned long old_addr; unsigned long new_addr; + unsigned long new_end; }; struct patch_info { @@ -55,6 +56,9 @@ struct patch_info { unsigned long rodata_addr; size_t rodata_len; + unsigned long jump_min_addr; + unsigned long jump_max_addr; + DECLARE_HASHTABLE(jump_table, PATCH_FUNC_HASH_BITS); };