Skip to content

Commit

Permalink
[re_kernel] add binder_node_lock and binder_inner_proc_lock
Browse files Browse the repository at this point in the history
  • Loading branch information
lzghzr committed May 22, 2024
1 parent fb90c73 commit 6d5ec1e
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/re_kernel/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
RK_VERSION := 1.4.0.3
RK_VERSION := 1.4.0.4

ifndef KP_DIR
KP_DIR = ../..
Expand Down
82 changes: 78 additions & 4 deletions src/re_kernel/re_kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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);
Expand All @@ -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 */
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/re_kernel/re_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

// android/binder.c
struct binder_alloc;
struct binder_transaction_data;

enum transaction_flags {
TF_ONE_WAY = 0x01,
Expand Down
94 changes: 49 additions & 45 deletions src/re_kernel/re_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 */

0 comments on commit 6d5ec1e

Please sign in to comment.