diff --git a/kernel/base/hook.c b/kernel/base/hook.c index 2a823e61..08cbb943 100644 --- a/kernel/base/hook.c +++ b/kernel/base/hook.c @@ -328,16 +328,9 @@ KP_EXPORT_SYMBOL(ret_absolute); int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, uint64_t dst_addr) { -#if 0 - uint32_t len = branch_relative(tramp_buf, src_addr, dst_addr); + int32_t len = branch_relative(tramp_buf, src_addr, dst_addr); if (len) return len; -#else -#if 0 - return branch_absolute(tramp_buf, dst_addr); -#else return ret_absolute(tramp_buf, dst_addr); -#endif -#endif } // transit0 @@ -558,11 +551,11 @@ hook_err_t hook_prepare(hook_t *hook) } // trampline to replace_addr if (hook->origin_insts[0] == ARM64_PACIASP || hook->origin_insts[0] == ARM64_PACIBSP) { - hook->tramp_insts_num = branch_from_to(&hook->tramp_insts[1], hook->origin_addr, hook->replace_addr); + hook->tramp_insts_num = branch_absolute(&hook->tramp_insts[1], hook->replace_addr); hook->tramp_insts[0] = ARM64_BTI_JC; hook->tramp_insts_num++; } else { - hook->tramp_insts_num = branch_from_to(hook->tramp_insts, hook->origin_addr, hook->replace_addr); + hook->tramp_insts_num = branch_absolute(hook->tramp_insts, hook->replace_addr); } // relocate diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index 3c4c7adf..079d9316 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -1372,6 +1372,8 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen hook_local->data0 = 0; } + if (current_uid() != 0 && !hook_local->data0) return; + static char app_process[] = "/system/bin/app_process"; static char app_process64[] = "/system/bin/app_process64"; static int first_app_process_execed = 0; @@ -1521,13 +1523,15 @@ static void before_openat(hook_fargs4_t *args, void *udata) args->local.data3 = 0; static int replaced = 0; + if (replaced) return; + + if (current_uid() != 0) return; + const char __user *filename = (typeof(filename))syscall_argn(args, 1); char buf[256]; long rc = compat_strncpy_from_user(buf, filename, sizeof(buf)); if (rc <= 0) return; - if (replaced) return; - int file_count = sizeof(ORIGIN_RC_FILES) / sizeof(ORIGIN_RC_FILES[0]); for (int i = 0; i < file_count; i++) { if (ORIGIN_RC_FILES[i][0] == '\0') break; diff --git a/kernel/patch/common/kstorage.c b/kernel/patch/common/kstorage.c index 9b5ab2bd..41bfe643 100644 --- a/kernel/patch/common/kstorage.c +++ b/kernel/patch/common/kstorage.c @@ -18,13 +18,22 @@ #define KSTRORAGE_MAX_GROUP_NUM 4 +#define KSTORAGE_HASH_BITS 8 +#define KSTORAGE_NBUCKETS (1 << KSTORAGE_HASH_BITS) + // static atomic64_t used_max_group = ATOMIC_INIT(0); static int used_max_group = -1; -static struct list_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM]; +static struct hlist_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM][KSTORAGE_NBUCKETS]; static spinlock_t kstorage_glocks[KSTRORAGE_MAX_GROUP_NUM]; static int group_sizes[KSTRORAGE_MAX_GROUP_NUM] = { 0 }; static spinlock_t used_max_group_lock; +static inline struct hlist_head *kstorage_bucket(int gid, long did) +{ + unsigned long h = (unsigned long)did * 0x9e3779b97f4a7c15UL; + return &kstorage_groups[gid][h >> (64 - KSTORAGE_HASH_BITS)]; +} + static void reclaim_callback(struct rcu_head *rcu) { struct kstorage *ks = container_of(rcu, struct kstorage, rcu); @@ -54,13 +63,13 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data int rc = -ENOENT; if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc; - struct list_head *head = &kstorage_groups[gid]; + struct hlist_head *bucket = kstorage_bucket(gid, did); spinlock_t *lock = &kstorage_glocks[gid]; struct kstorage *pos = 0, *old = 0; rcu_read_lock(); - list_for_each_entry(pos, head, list) + hlist_for_each_entry_rcu(pos, bucket, hnode) { if (pos->did == did) { old = pos; @@ -68,7 +77,7 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data } } - struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len); + struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len); if (!new) { rcu_read_unlock(); return -ENOMEM; @@ -80,6 +89,7 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data void *drc = memdup_user(data + offset, len); if (IS_ERR(drc)) { rcu_read_unlock(); + kvfree(new); return PTR_ERR(drc); } memcpy(new->data, drc, len); @@ -91,9 +101,9 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data spin_lock(lock); if (old) { // update - list_replace_rcu(&old->list, &new->list); + hlist_replace_rcu(&old->hnode, &new->hnode); } else { // add new one - list_add_rcu(&new->list, head); + hlist_add_head_rcu(&new->hnode, bucket); group_sizes[gid]++; } spin_unlock(lock); @@ -117,10 +127,10 @@ const struct kstorage *get_kstorage(int gid, long did) { if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return ERR_PTR(-ENOENT); - struct list_head *head = &kstorage_groups[gid]; + struct hlist_head *bucket = kstorage_bucket(gid, did); struct kstorage *pos = 0; - list_for_each_entry(pos, head, list) + hlist_for_each_entry_rcu(pos, bucket, hnode) { if (pos->did == did) { return pos; @@ -137,17 +147,19 @@ int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata) int rc = 0; - struct list_head *head = &kstorage_groups[gid]; struct kstorage *pos = 0; rcu_read_lock(); - list_for_each_entry(pos, head, list) - { - int rc = cb(pos, udata); - if (rc) break; + for (int b = 0; b < KSTORAGE_NBUCKETS; b++) { + hlist_for_each_entry_rcu(pos, &kstorage_groups[gid][b], hnode) + { + rc = cb(pos, udata); + if (rc) goto out; + } } +out: rcu_read_unlock(); return rc; @@ -189,27 +201,29 @@ int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user) int cnt = 0; - struct list_head *head = &kstorage_groups[gid]; struct kstorage *pos = 0; rcu_read_lock(); - list_for_each_entry(pos, head, list) - { - if (cnt >= idslen) break; - - if (data_is_user) { - int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did)); - if (cplen <= 0) { - logkfe("compat_copy_to_user error: %d", cplen); - cnt = cplen; + for (int b = 0; b < KSTORAGE_NBUCKETS; b++) { + hlist_for_each_entry_rcu(pos, &kstorage_groups[gid][b], hnode) + { + if (cnt >= idslen) goto out; + + if (data_is_user) { + int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did)); + if (cplen <= 0) { + logkfe("compat_copy_to_user error: %d", cplen); + cnt = cplen; + } + } else { + memcpy(ids + cnt, &pos->did, sizeof(pos->did)); } - } else { - memcpy(ids + cnt, &pos->did, sizeof(pos->did)); + cnt++; } - cnt++; } +out: rcu_read_unlock(); return cnt; @@ -221,16 +235,16 @@ int remove_kstorage(int gid, long did) int rc = -ENOENT; if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc; - struct list_head *head = &kstorage_groups[gid]; + struct hlist_head *bucket = kstorage_bucket(gid, did); spinlock_t *lock = &kstorage_glocks[gid]; struct kstorage *pos = 0; spin_lock(lock); - list_for_each_entry(pos, head, list) + hlist_for_each_entry_rcu(pos, bucket, hnode) { if (pos->did == did) { - list_del_rcu(&pos->list); + hlist_del_rcu(&pos->hnode); spin_unlock(lock); group_sizes[gid]--; @@ -255,7 +269,9 @@ KP_EXPORT_SYMBOL(remove_kstorage); int kstorage_init() { for (int i = 0; i < KSTRORAGE_MAX_GROUP_NUM; i++) { - INIT_LIST_HEAD(&kstorage_groups[i]); + for (int b = 0; b < KSTORAGE_NBUCKETS; b++) { + INIT_HLIST_HEAD(&kstorage_groups[i][b]); + } spin_lock_init(&kstorage_glocks[i]); } spin_lock_init(&used_max_group_lock); diff --git a/kernel/patch/common/sucompat.c b/kernel/patch/common/sucompat.c index fc712f74..f11ac050 100644 --- a/kernel/patch/common/sucompat.c +++ b/kernel/patch/common/sucompat.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -310,7 +311,7 @@ __maybe_unused static void before_execveat(hook_fargs5_t *args, void *udata) // int, dfd, const char __user *, filename, unsigned, flags, // unsigned int, mask, // struct statx __user *, buffer) -static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) +__maybe_unused static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) { uid_t uid = current_uid(); if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return; @@ -331,6 +332,34 @@ static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) } } +static void after_getname_flags(hook_fargs3_t *args, void *udata) +{ + struct filename *fn = (struct filename *)args->ret; + if (IS_ERR_OR_NULL(fn)) return; + + uid_t uid = current_uid(); + if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return; + + const char *name = fn->name; + if (!name || strcmp(name, su_get_path())) return; + + if (strlen(sh_path) <= strlen(name)) { + strcpy((char *)name, sh_path); + return; + } + + if (kfunc(getname_kernel) && kfunc(putname)) { + struct filename *nf = kfunc(getname_kernel)(sh_path); + if (!IS_ERR_OR_NULL(nf)) { + kfunc(putname)(fn); + args->ret = (uint64_t)nf; + return; + } + } + + logkfi("uid: %d, cannot redirect su path to %s\n", uid, sh_path); +} + int set_ap_mod_exclude(uid_t uid, int exclude) { int rc = 0; @@ -394,23 +423,17 @@ int su_compat_init() rc = hook_syscalln(__NR_execve, 3, before_execve, 0, (void *)0); log_boot("hook __NR_execve rc: %d\n", rc); - rc = hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, 0, (void *)0); - log_boot("hook __NR3264_fstatat rc: %d\n", rc); - - rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, 0, (void *)0); - log_boot("hook __NR_faccessat rc: %d\n", rc); - // __NR_execve 11 rc = hook_compat_syscalln(11, 3, before_execve, 0, (void *)1); log_boot("hook 32 __NR_execve rc: %d\n", rc); - // __NR_fstatat64 327 - rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, 0, (void *)0); - log_boot("hook 32 __NR_fstatat64 rc: %d\n", rc); - - // __NR_faccessat 334 - rc = hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, 0, (void *)0); - log_boot("hook 32 __NR_faccessat rc: %d\n", rc); + unsigned long getname_flags_addr = kallsyms_lookup_name("getname_flags"); + if (getname_flags_addr) { + rc = hook_wrap3((void *)getname_flags_addr, 0, after_getname_flags, (void *)0); + log_boot("hook getname_flags rc: %d\n", rc); + } else { + log_boot("getname_flags not found\n"); + } return 0; } \ No newline at end of file diff --git a/kernel/patch/include/kstorage.h b/kernel/patch/include/kstorage.h index fca8c68a..66d446cc 100644 --- a/kernel/patch/include/kstorage.h +++ b/kernel/patch/include/kstorage.h @@ -12,7 +12,7 @@ struct kstorage { - struct list_head list; + struct hlist_node hnode; struct rcu_head rcu; int gid; diff --git a/kernel/patch/ksyms/misc.c b/kernel/patch/ksyms/misc.c index 20eeea72..a4f7baa3 100644 --- a/kernel/patch/ksyms/misc.c +++ b/kernel/patch/ksyms/misc.c @@ -467,8 +467,8 @@ static void _linux_fs_sym_match(const char *name, unsigned long addr) // kfunc_match(dentry_open, name, addr); kfunc_match(filp_close, name, addr); // kfunc_match(getname, name, addr); - // kfunc_match(getname_kernel, name, addr); - // kfunc_match(putname, name, addr); + kfunc_match(getname_kernel, name, addr); + kfunc_match(putname, name, addr); // kfunc_match(final_putname, name, addr); kfunc_match(vfs_llseek, name, addr); kfunc_match(iterate_dir, name, addr);