diff --git a/src/re_kernel/Makefile b/src/re_kernel/Makefile index 4cf612a..218cc69 100644 --- a/src/re_kernel/Makefile +++ b/src/re_kernel/Makefile @@ -1,4 +1,4 @@ -RK_VERSION := 1.4.0.3 +RK_VERSION := 1.4.0.4 ifndef KP_DIR KP_DIR = ../.. diff --git a/src/re_kernel/re_kernel.c b/src/re_kernel/re_kernel.c index 889fa86..524ba37 100644 --- a/src/re_kernel/re_kernel.c +++ b/src/re_kernel/re_kernel.c @@ -89,6 +89,10 @@ void kfunc_def(kfree)(const void* objp); static struct binder_stats kvar_def(binder_stats); // hook do_send_sig_info static int (*do_send_sig_info)(int sig, struct siginfo* info, struct task_struct* p, enum pid_type type); + +// _raw_spin_lock && _raw_spin_unlock +void kfunc_def(_raw_spin_lock)(raw_spinlock_t* lock); +void kfunc_def(_raw_spin_unlock)(raw_spinlock_t* lock); // trace int kfunc_def(tracepoint_probe_register)(struct tracepoint* tp, void* probe, void* data); int kfunc_def(tracepoint_probe_unregister)(struct tracepoint* tp, void* probe, void* data); @@ -98,12 +102,14 @@ struct tracepoint kvar_def(__tracepoint_binder_transaction); int kfunc_def(get_cmdline)(struct task_struct* task, char* buffer, int buflen); #endif /* DEBUG */ +// 最好初始化一个大于 0xffffffff 的值, 否则编译器优化后, 全局变量可能出错 static uint64_t task_struct_flags_offset = UZERO, task_struct_jobctl_offset = UZERO, task_struct_pid_offset = UZERO, task_struct_group_leader_offset = UZERO, task_struct_frozen_offset = UZERO, task_struct_css_set_offset = UZERO, -binder_proc_alloc_offset = UZERO, +binder_proc_alloc_offset = UZERO, binder_proc_context_offset = UZERO, binder_proc_inner_lock_offset = UZERO, binder_proc_outer_lock_offset = UZERO, binder_alloc_pid_offset = UZERO, binder_alloc_buffer_size_offset = UZERO, binder_alloc_free_async_space_offset = UZERO, binder_alloc_vma_offset = UZERO, css_set_dfl_cgrp_offset = UZERO, cgroup_flags_offset = UZERO, -task_struct_frozen_bit = UZERO; +task_struct_frozen_bit = UZERO, +binder_transaction_buffer_release_ver = UZERO; static struct sock* rekernel_netlink; static unsigned long rekernel_netlink_unit = UZERO, trace = UZERO; @@ -119,6 +125,24 @@ static inline pid_t task_tgid(struct task_struct* task) { pid_t tgid = *(pid_t*)((uintptr_t)task + task_struct_pid_offset + 0x4); return tgid; } +// binder_node_lock +static inline void binder_node_lock(struct binder_node* node) { + spin_lock(&node->lock); +} +// binder_node_unlock +static inline void binder_node_unlock(struct binder_node* node) { + spin_unlock(&node->lock); +} +// binder_inner_proc_lock +static inline void binder_inner_proc_lock(struct binder_proc* proc) { + spinlock_t* inner_lock = (spinlock_t*)((uintptr_t)proc + binder_proc_inner_lock_offset); + spin_lock(inner_lock); +} +// binder_inner_proc_unlock +static inline void binder_inner_proc_unlock(struct binder_proc* proc) { + spinlock_t* inner_lock = (spinlock_t*)((uintptr_t)proc + binder_proc_inner_lock_offset); + spin_unlock(inner_lock); +} // 判断线程是否进入 frozen 状态 static inline bool cgroup_task_frozen(struct task_struct* task) { if (task_struct_frozen_offset == UZERO) { @@ -326,7 +350,6 @@ static bool binder_can_update_transaction(struct binder_transaction* t1, struct return false; } -// TODO: binder_inner_proc_lock(proc); static struct binder_transaction* binder_find_outdated_transaction_ilocked(struct binder_transaction* t, struct list_head* target_list) { struct binder_work* w; @@ -343,7 +366,7 @@ static struct binder_transaction* binder_find_outdated_transaction_ilocked(struc } static inline void binder_release_entire_buffer(struct binder_proc* proc, struct binder_thread* thread, struct binder_buffer* buffer, bool is_failure) { - if (kver > VERSION(5, 0, 0)) { + if (binder_transaction_buffer_release_ver == IZERO) { binder_size_t off_end_offset = ALIGN(buffer->data_size, sizeof(void*)); off_end_offset += buffer->offsets_size; @@ -360,6 +383,7 @@ static inline void binder_stats_deleted(enum binder_stat_types type) { static void binder_proc_transaction_before(hook_fargs3_t* args, void* udata) { struct binder_transaction* t = (struct binder_transaction*)args->arg0; + struct binder_proc* proc = (struct binder_proc*)args->arg1; // 兼容不支持 trace 的内核 if (trace == UZERO) { rekernel_binder_transaction(NULL, false, t, NULL); @@ -370,10 +394,23 @@ static void binder_proc_transaction_before(hook_fargs3_t* args, void* udata) { && t->to_proc->tsk && frozen_task_group(t->to_proc->tsk)) { struct binder_node* node = t->buffer->target_node; + if (!node) + return; + struct binder_alloc* target_alloc = (struct binder_alloc*)((uintptr_t)t->to_proc + binder_proc_alloc_offset); + binder_node_lock(node); + binder_inner_proc_lock(proc); + struct binder_transaction* t_outdated = binder_find_outdated_transaction_ilocked(t, &node->async_todo); if (t_outdated) { + list_del_init(&t_outdated->work.entry); + } + + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + + if (t_outdated) { #ifdef DEBUG printk("re_kernel: free_outdated pid=%d,uid=%d,data_size=%d\n", t->to_proc->pid, task_uid(t->to_proc->tsk).val, t_outdated->buffer->data_size); #endif /* DEBUG */ @@ -469,6 +506,41 @@ static long calculate_offsets() { task_struct_jobctl_offset = sign64_extend((imm12), 16u) - 0x2; } } + // 获取 binder_transaction_buffer_release 版本, 以参数数量做判断 + uint32_t* binder_transaction_buffer_release_src = (uint32_t*)binder_transaction_buffer_release; + for (u32 i = 0; i < 0x20; i++) { +#ifdef DEBUG + printk("re_kernel: binder_transaction_buffer_release %x %llx\n", i, binder_transaction_buffer_release_src[i]); +#endif /* DEBUG */ + if (binder_transaction_buffer_release_src[i] == ARM64_RET) { + break; + } else if ((binder_transaction_buffer_release_src[i] & MASK_STR_Rn_SP_Rt_4) == INST_STR_Rn_SP_Rt_4) { + binder_transaction_buffer_release_ver = IZERO; + break; + } else if ((binder_transaction_buffer_release_src[i] & MASK_MOV_Rm_4_WZR) == INST_MOV_Rm_4_WZR) { + binder_transaction_buffer_release_ver = IZERO; + break; + } + } + // 获取 binder_proc->context, binder_proc->inner_lock, binder_proc->outer_lock + void (*binder_transaction)(struct binder_proc* proc, struct binder_thread* thread, struct binder_transaction_data* tr, int reply, binder_size_t extra_buffers_size); + lookup_name(binder_transaction); + + uint32_t* binder_transaction_src = (uint32_t*)binder_transaction; + for (u32 i = 0; i < 0x20; i++) { + if (binder_transaction_src[i] == ARM64_RET) { + break; + } else if ((binder_transaction_src[i] & MASK_LDR_64_X0) == INST_LDR_64_X0) { + uint64_t imm12 = bits32(binder_transaction_src[i], 21, 10); + binder_proc_context_offset = sign64_extend((imm12 << 0b11u), 16u); + binder_proc_inner_lock_offset = binder_proc_context_offset + 0x8; + binder_proc_outer_lock_offset = binder_proc_context_offset + 0xC; + break; + } + } + if (binder_proc_context_offset == UZERO || binder_proc_inner_lock_offset == UZERO || binder_proc_outer_lock_offset == UZERO) { + return -11; + } // 获取 binder_proc->alloc void (*binder_free_proc)(struct binder_proc* proc); binder_free_proc = (typeof(binder_free_proc))kallsyms_lookup_name("binder_free_proc"); @@ -572,6 +644,8 @@ static long inline_hook_init(const char* args, const char* event, void* __user r kfunc_lookup_name(tracepoint_probe_register); kfunc_lookup_name(tracepoint_probe_unregister); + kfunc_lookup_name(_raw_spin_lock); + kfunc_lookup_name(_raw_spin_unlock); kvar_lookup_name(__tracepoint_binder_transaction); lookup_name(binder_transaction_buffer_release); diff --git a/src/re_kernel/re_kernel.h b/src/re_kernel/re_kernel.h index 571702d..672bb57 100644 --- a/src/re_kernel/re_kernel.h +++ b/src/re_kernel/re_kernel.h @@ -9,6 +9,7 @@ // android/binder.c struct binder_alloc; +struct binder_transaction_data; enum transaction_flags { TF_ONE_WAY = 0x01, diff --git a/src/re_kernel/re_utils.h b/src/re_kernel/re_utils.h index 9526713..0c25748 100644 --- a/src/re_kernel/re_utils.h +++ b/src/re_kernel/re_utils.h @@ -35,6 +35,8 @@ typedef uint32_t inst_mask_t; #define INST_LDRH 0x79400000u #define INST_LDRSH 0x79800000u #define INST_LDRSH_64_ 0x79800000u +#define INST_MOV_Rm_4_WZR 0x2A0403E0u +#define INST_STR_Rn_SP_Rt_4 0xB90003E4u #define INST_STR_32_x0 0xB9000000u #define INST_CBZ 0x34000000 #define INST_CBNZ 0x35000000 @@ -57,6 +59,8 @@ typedef uint32_t inst_mask_t; #define MASK_LDRH 0xFFC00000u #define MASK_LDRSH 0xFF800000u #define MASK_LDRSH_64_ 0xFFC00000u +#define MASK_MOV_Rm_4_WZR 0x7FFFFFE0u +#define MASK_STR_Rn_SP_Rt_4 0xBFC003E4u #define MASK_STR_32_x0 0xFFC003E0u #define MASK_CBZ 0x7F000000u #define MASK_CBNZ 0x7F000000u @@ -118,123 +122,123 @@ typedef uint32_t inst_mask_t; extern bool kfunc_def(freezing_slow_path)(struct task_struct* p); static inline bool freezing_slow_path(struct task_struct* p) { - kfunc_call(freezing_slow_path, p); - kfunc_not_found(); - return false; + kfunc_call(freezing_slow_path, p); + kfunc_not_found(); + return false; } extern struct sk_buff* kfunc_def(__alloc_skb)(unsigned int size, gfp_t gfp_mask, int flags, int node); static inline struct sk_buff* alloc_skb(unsigned int size, gfp_t priority) { - kfunc_call(__alloc_skb, size, priority, 0, NUMA_NO_NODE); - kfunc_not_found(); - return NULL; + kfunc_call(__alloc_skb, size, priority, 0, NUMA_NO_NODE); + kfunc_not_found(); + return NULL; } static inline int nlmsg_msg_size(int payload) { - return NLMSG_HDRLEN + payload; + return NLMSG_HDRLEN + payload; } static inline int nlmsg_total_size(int payload) { - return NLMSG_ALIGN(nlmsg_msg_size(payload)); + return NLMSG_ALIGN(nlmsg_msg_size(payload)); } static inline void* nlmsg_data(const struct nlmsghdr* nlh) { - return (unsigned char*)nlh + NLMSG_HDRLEN; + return (unsigned char*)nlh + NLMSG_HDRLEN; } static inline struct sk_buff* nlmsg_new(size_t payload, gfp_t flags) { - return alloc_skb(nlmsg_total_size(payload), flags); + return alloc_skb(nlmsg_total_size(payload), flags); } extern struct nlmsghdr* kfunc_def(__nlmsg_put)(struct sk_buff* skb, u32 portid, u32 seq, int type, int len, int flags); static inline struct nlmsghdr* nlmsg_put(struct sk_buff* skb, u32 portid, u32 seq, int type, int payload, int flags) { - kfunc_call(__nlmsg_put, skb, portid, seq, type, payload, flags); - kfunc_not_found(); - return NULL; + kfunc_call(__nlmsg_put, skb, portid, seq, type, payload, flags); + kfunc_not_found(); + return NULL; } extern void kfunc_def(kfree_skb)(struct sk_buff* skb); static inline void nlmsg_free(struct sk_buff* skb) { - kfunc_call_void(kfree_skb, skb); + kfunc_call_void(kfree_skb, skb); } extern int kfunc_def(netlink_unicast)(struct sock* ssk, struct sk_buff* skb, u32 portid, int nonblock); static inline int netlink_unicast(struct sock* ssk, struct sk_buff* skb, u32 portid, int nonblock) { - kfunc_call(netlink_unicast, ssk, skb, portid, nonblock); - kfunc_not_found(); - return -ESRCH; + kfunc_call(netlink_unicast, ssk, skb, portid, nonblock); + kfunc_not_found(); + return -ESRCH; } extern struct sock* kfunc_def(__netlink_kernel_create)(struct net* net, int unit, struct module* module, struct netlink_kernel_cfg* cfg); static inline struct sock* netlink_kernel_create(struct net* net, int unit, struct netlink_kernel_cfg* cfg) { - kfunc_call(__netlink_kernel_create, net, unit, THIS_MODULE, cfg); - kfunc_not_found(); - return NULL; + kfunc_call(__netlink_kernel_create, net, unit, THIS_MODULE, cfg); + kfunc_not_found(); + return NULL; } extern void kfunc_def(netlink_kernel_release)(struct sock* sk); static inline void netlink_kernel_release(struct sock* sk) { - kfunc_call_void(netlink_kernel_release, sk); + kfunc_call_void(netlink_kernel_release, sk); } extern struct proc_dir_entry* kfunc_def(proc_mkdir)(const char* name, struct proc_dir_entry* parent); static inline struct proc_dir_entry* proc_mkdir(const char* name, struct proc_dir_entry* parent) { - kfunc_call(proc_mkdir, name, parent); - kfunc_not_found(); - return NULL; + kfunc_call(proc_mkdir, name, parent); + kfunc_not_found(); + return NULL; } extern struct proc_dir_entry* kfunc_def(proc_create_data)(const char* name, umode_t mode, struct proc_dir_entry* parent, const struct file_operations* proc_fops, void* data); static inline struct proc_dir_entry* proc_create(const char* name, umode_t mode, struct proc_dir_entry* parent, const struct file_operations* proc_fops) { - kfunc_call(proc_create_data, name, mode, parent, proc_fops, NULL); - kfunc_not_found(); - return NULL; + kfunc_call(proc_create_data, name, mode, parent, proc_fops, NULL); + kfunc_not_found(); + return NULL; } extern void kfunc_def(proc_remove)(struct proc_dir_entry* de); static inline void proc_remove(struct proc_dir_entry* de) { - kfunc_call_void(proc_remove, de); + kfunc_call_void(proc_remove, de); } extern void kfunc_def(seq_printf)(struct seq_file* m, const char* f, ...); static inline void seq_printf(struct seq_file* m, const char* f, ...) { - va_list args; - va_start(args, f); - kfunc(seq_printf)(m, f, args); - va_end(args); + va_list args; + va_start(args, f); + kfunc(seq_printf)(m, f, args); + va_end(args); } extern int kfunc_def(single_open)(struct file* file, int (*show)(struct seq_file*, void*), void* data); static inline int single_open(struct file* file, int (*show)(struct seq_file*, void*), void* data) { - kfunc_call(single_open, file, show, data); - kfunc_not_found(); - return -ESRCH; + kfunc_call(single_open, file, show, data); + kfunc_not_found(); + return -ESRCH; } extern int kfunc_def(get_cmdline)(struct task_struct* task, char* buffer, int buflen); static inline int get_cmdline(struct task_struct* task, char* buffer, int buflen) { - kfunc_call(get_cmdline, task, buffer, buflen); - kfunc_not_found(); - return -ESRCH; + kfunc_call(get_cmdline, task, buffer, buflen); + kfunc_not_found(); + return -ESRCH; } extern int kfunc_def(tracepoint_probe_register)(struct tracepoint* tp, void* probe, void* data); static inline int tracepoint_probe_register(struct tracepoint* tp, void* probe, void* data) { - kfunc_call(tracepoint_probe_register, tp, probe, data); - kfunc_not_found(); - return -ESRCH; + kfunc_call(tracepoint_probe_register, tp, probe, data); + kfunc_not_found(); + return -ESRCH; } extern int kfunc_def(tracepoint_probe_unregister)(struct tracepoint* tp, void* probe, void* data); static inline int tracepoint_probe_unregister(struct tracepoint* tp, void* probe, void* data) { - kfunc_call(tracepoint_probe_unregister, tp, probe, data); - kfunc_not_found(); - return -ESRCH; + kfunc_call(tracepoint_probe_unregister, tp, probe, data); + kfunc_not_found(); + return -ESRCH; } extern void kfunc_def(kfree)(const void* objp); static inline void kfree(const void* objp) { - kfunc_call_void(kfree, objp); + kfunc_call_void(kfree, objp); } #endif /* __RE_UTILS_H */