From 325faac507873c8d27fbb6c731da5f49dd1b1a14 Mon Sep 17 00:00:00 2001 From: bmax Date: Sat, 28 Sep 2024 16:42:51 +0800 Subject: [PATCH] tmp save --- kernel/include/preset.h | 1 + kernel/include/stdbool.h | 7 +- kernel/patch/common/kstorage.c | 224 ++++++++++++ kernel/patch/common/sucompat.c | 356 ++++-------------- kernel/patch/common/sucompat.c.bak | 554 +++++++++++++++++++++++++++++ kernel/patch/common/supercall.c | 16 +- kernel/patch/common/supercmd.c | 23 +- kernel/patch/common/syscall.c | 32 +- kernel/patch/include/accctl.h | 4 +- kernel/patch/include/kstorage.h | 42 +++ kernel/patch/include/syscall.h | 24 +- kernel/patch/include/uapi/scdefs.h | 39 +- kernel/patch/patch.c | 4 + 13 files changed, 963 insertions(+), 363 deletions(-) create mode 100644 kernel/patch/common/kstorage.c create mode 100644 kernel/patch/common/sucompat.c.bak create mode 100644 kernel/patch/include/kstorage.h diff --git a/kernel/include/preset.h b/kernel/include/preset.h index 81658194..6f9b601b 100644 --- a/kernel/include/preset.h +++ b/kernel/include/preset.h @@ -101,6 +101,7 @@ _Static_assert(sizeof(map_symbol_t) == MAP_SYMBOL_SIZE, "sizeof map_symbol_t mis #define PATCH_CONFIG_SU_ENABLE 0x1 #define PATCH_CONFIG_SU_HOOK_NO_WRAP 0x2 +#define PATCH_CONFIG_SU_ENABLE32 0x2 struct patch_config { diff --git a/kernel/include/stdbool.h b/kernel/include/stdbool.h index b40bcdfa..f66cbbb9 100644 --- a/kernel/include/stdbool.h +++ b/kernel/include/stdbool.h @@ -1,9 +1,12 @@ #ifndef _KP_STDBOOL_H_ #define _KP_STDBOOL_H_ +#ifndef __bool_true_false_are_defined + #define bool _Bool +#define true 1 +#define false 0 -#define true ((bool)1) -#define false ((bool)0) +#endif #endif \ No newline at end of file diff --git a/kernel/patch/common/kstorage.c b/kernel/patch/common/kstorage.c new file mode 100644 index 00000000..6fe80107 --- /dev/null +++ b/kernel/patch/common/kstorage.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KSTRORAGE_MAX_GROUP_NUM 4 + +// static atomic64_t used_max_group = ATOMIC_INIT(0); +static int used_max_group = 0; +static struct list_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM]; +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 void reclaim_callback(struct rcu_head *rcu) +// { +// struct kstorage *ks = container_of(rcu, struct kstorage, rcu); +// kvfree(ks); +// } + +int try_alloc_kstroage_group() +{ + spin_lock(&used_max_group_lock); + used_max_group++; + if (used_max_group >= KSTRORAGE_MAX_GROUP_NUM) return -1; + spin_unlock(&used_max_group_lock); + return used_max_group; +} + +int kstorage_group_size(int gid) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; + return group_sizes[gid]; +} + +int write_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user) +{ + int rc = -ENOENT; + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc; + + struct list_head *head = &kstorage_groups[gid]; + spinlock_t *lock = &kstorage_glocks[gid]; + struct kstorage *pos = 0, *old = 0; + + rcu_read_lock(); + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + old = pos; + break; + } + } + + struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len); + new->gid = gid; + new->did = did; + new->dlen = 0; + if (data_is_user) { + void *drc = memdup_user(data + offset, len); + if (IS_ERR(drc)) { + rcu_read_unlock(); + return PTR_ERR(drc); + } + memcpy(new->data, drc, len); + kvfree(drc); + } else { + memcpy(new->data, data + offset, len); + } + new->dlen = len; + + spin_lock(lock); + if (old) { // update + list_replace_rcu(&old->list, &new->list); + logkfi("update %d %d\n", gid, did); + } else { // add new one + list_add_rcu(&new->list, head); + group_sizes[gid]++; + logkfi("new %d %d\n", gid, did); + } + spin_unlock(lock); + + rcu_read_unlock(); + + if (old) { + // if (async) { + // call_rcu(&old->rcu, reclaim_callback); + // } else { + synchronize_rcu(); + kvfree(old); + // } + } + return 0; +} +KP_EXPORT_SYMBOL(write_kstorage); + +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 kstorage *pos = 0; + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + return pos; + } + } + + return ERR_PTR(-ENOENT); +} +KP_EXPORT_SYMBOL(get_kstorage); + +int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return; + + 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; + } + + rcu_read_unlock(); + + return rc; +} +KP_EXPORT_SYMBOL(on_each_kstorage_elem); + +int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user) +{ + int rc = 0; + rcu_read_lock(); + + struct kstorage *pos = get_kstorage(gid, did); + if (IS_ERR(pos)) return PTR_ERR(pos); + + int min_len = pos->dlen - offset > len ? len : pos->dlen - offset; + + if (data_is_user) { + int cplen = compat_copy_to_user(data, pos->data + offset, min_len); + logkfd("%d %ld %d\n", gid, did, pos->dlen); + + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + } + } else { + memcpy(data, pos->data + offset, min_len); + } + + rcu_read_unlock(); + return rc; +} +KP_EXPORT_SYMBOL(read_kstorage); + +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]; + spinlock_t *lock = &kstorage_glocks[gid]; + struct kstorage *pos = 0; + + spin_lock(&kstorage_glocks[gid]); + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + list_del_rcu(&pos->list); + spin_unlock(lock); + + group_sizes[did]--; + + logkfi("%d %ld\n", gid, did); + + // if (async) { + // call_rcu(&pos->rcu, reclaim_callback); + // } else { + synchronize_rcu(); + kvfree(pos); + // } + return 0; + } + } + + spin_unlock(lock); + + return 0; +} +KP_EXPORT_SYMBOL(remove_kstorage); + +int kstorage_init() +{ + for (int i = 0; i < KSTRORAGE_MAX_GROUP_NUM; i++) { + INIT_LIST_HEAD(&kstorage_groups[i]); + spin_lock_init(&kstorage_glocks[i]); + } + spin_lock_init(&used_max_group_lock); + + return 0; +} \ No newline at end of file diff --git a/kernel/patch/common/sucompat.c b/kernel/patch/common/sucompat.c index 0911bd8d..54e27de1 100644 --- a/kernel/patch/common/sucompat.c +++ b/kernel/patch/common/sucompat.c @@ -19,20 +19,17 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -40,6 +37,7 @@ #include #include #include +#include const char sh_path[] = SH_PATH; const char default_su_path[] = SU_PATH; @@ -51,161 +49,82 @@ const char apd_path[] = APD_PATH; static const char *current_su_path = 0; -static struct list_head allow_uid_list; -static spinlock_t list_lock; - -static void allow_reclaim_callback(struct rcu_head *rcu) +struct su_profile { - struct allow_uid *allow = container_of(rcu, struct allow_uid, rcu); - kvfree(allow); -} - -struct su_profile profile_su_allow_uid(uid_t uid) -{ - rcu_read_lock(); - struct allow_uid *pos; - struct su_profile profile = { 0 }; - list_for_each_entry_rcu(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - memcpy(&profile, &pos->profile, sizeof(struct su_profile)); - rcu_read_unlock(); - return profile; - } - } - rcu_read_unlock(); - return profile; -} -KP_EXPORT_SYMBOL(profile_su_allow_uid); + uid_t uid; + uid_t to_uid; + char scontext[SUPERCALL_SCONTEXT_LEN]; +}; int is_su_allow_uid(uid_t uid) { rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry_rcu(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - rcu_read_unlock(); - return 1; - } - } + const struct kstorage *ks = get_kstorage(KSTORAGE_SU_LIST_GROUP, uid); + struct su_profile *profile = (struct su_profile *)ks->data; + int rc = profile != 0; rcu_read_unlock(); - return 0; + return rc; } KP_EXPORT_SYMBOL(is_su_allow_uid); -int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext, struct su_profile_ext *ext, int async) +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext) { if (!scontext) scontext = ""; - - rcu_read_lock(); - struct allow_uid *pos, *old = 0; - list_for_each_entry(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - old = pos; - break; - } - } - // todo: vmalloc -> kmalloc, gfp - struct allow_uid *new = (struct allow_uid *)vmalloc(sizeof(struct allow_uid)); - new->uid = uid; - new->profile.uid = uid; - new->profile.to_uid = to_uid; - strncpy(new->profile.scontext, scontext, sizeof(new->profile.scontext)); - new->profile.scontext[sizeof(new->profile.scontext) - 1] = '\0'; - new->profile.ext = *ext; - - spin_lock(&list_lock); - if (old) { // update - list_replace_rcu(&old->list, &new->list); - logkfi("update uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); - } else { // add new one - list_add_rcu(&new->list, &allow_uid_list); - logkfi("new uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); - } - spin_unlock(&list_lock); - - rcu_read_unlock(); - if (old) { - if (async) { - call_rcu(&old->rcu, allow_reclaim_callback); - } else { - synchronize_rcu(); - kvfree(old); - } - } - return 0; + struct su_profile profile = { uid, to_uid, scontext }; + int rc = write_kstorage(KSTORAGE_SU_LIST_GROUP, uid, &profile, 0, sizeof(struct su_profile), false); + logkfd("uid: %d, to_uid: %d, sctx: %s, rc: %d\n", uid, to_uid, scontext, rc); + return rc; } KP_EXPORT_SYMBOL(su_add_allow_uid); -int su_remove_allow_uid(uid_t uid, int async) +int su_remove_allow_uid(uid_t uid) { - struct allow_uid *pos; - spin_lock(&list_lock); - list_for_each_entry(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - list_del_rcu(&pos->list); - spin_unlock(&list_lock); - logkfi("uid: %d, to_uid: %d, sctx: %s\n", pos->uid, pos->profile.to_uid, pos->profile.scontext); - if (async) { - call_rcu(&pos->rcu, allow_reclaim_callback); - } else { - synchronize_rcu(); - kvfree(pos); - } - return 0; - } - } - spin_unlock(&list_lock); - return 0; + return remove_kstorage(KSTORAGE_SU_LIST_GROUP, uid); } KP_EXPORT_SYMBOL(su_remove_allow_uid); int su_allow_uid_nums() { - int num = 0; - rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry(pos, &allow_uid_list, list) + return kstorage_group_size(KSTORAGE_SU_LIST_GROUP); +} +KP_EXPORT_SYMBOL(su_allow_uid_nums); + +static int allow_uids_cb(struct kstorage *kstorage, void *udata) +{ + struct { - num++; + int is_user; + uid_t *out_uids; + int out_num; + } *up = (typeof(up))udata; + + if (up->is_user) { + int cplen = compat_copy_to_user(up->out_uids + num, &uid, sizeof(uid)); + logkfd("uid: %d\n", uid); + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + goto out; + } + } else { + out_uids[num] = uid; } - rcu_read_unlock(); - logkfd("%d\n", num); - return num; + + num++; + + return 0; } -KP_EXPORT_SYMBOL(su_allow_uid_nums); int su_allow_uids(int is_user, uid_t *out_uids, int out_num) { int rc = 0; - int num = 0; - rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry(pos, &allow_uid_list, list) + struct { - if (num >= out_num) goto out; - - uid_t uid = pos->profile.uid; - if (is_user) { - int cplen = compat_copy_to_user(out_uids + num, &uid, sizeof(uid)); - logkfd("uid: %d\n", uid); - if (cplen <= 0) { - logkfd("compat_copy_to_user error: %d", cplen); - rc = cplen; - goto out; - } - } else { - out_uids[num] = uid; - } - - num++; - } - rc = num; -out: - rcu_read_unlock(); + int iu; + uid_t *up; + int un; + } udata = { is_user, out_uids, out_num }; + on_each_kstorage_elem(KSTORAGE_SU_LIST_GROUP, allow_uids_cb, &udata); return rc; } KP_EXPORT_SYMBOL(su_allow_uids); @@ -257,17 +176,8 @@ const char *su_get_path() } KP_EXPORT_SYMBOL(su_get_path); -// #define TRY_DIRECT_MODIFY_USER - -#define INLINE_HOOK_SYSCALL - -static void handle_before_execve(hook_local_t *hook_local, char **__user u_filename_p, char **__user uargv, void *udata) +static void handle_before_execve(char **__user u_filename_p, char **__user uargv, void *udata) { -#ifdef TRY_DIRECT_MODIFY_USER - // copy to user len - hook_local->data0 = 0; -#endif - char __user *ufilename = *u_filename_p; char filename[SU_PATH_MAX_LEN]; int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); @@ -286,54 +196,28 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen struct file *filp = filp_open(apd_path, O_RDONLY, 0); if (!filp || IS_ERR(filp)) { #endif - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); - if (cplen > 0) { - hook_local->data0 = cplen; - hook_local->data1 = (uint64_t)u_filename_p; - logkfi("call su uid: %d, to_uid: %d, sctx: %s, cplen: %d\n", uid, to_uid, sctx, cplen); - } -#endif - if (cplen <= 0) { - void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); - if (uptr && !IS_ERR(uptr)) { - *u_filename_p = (char *__user)uptr; - } - logkfi("call su uid: %d, to_uid: %d, sctx: %s, uptr: %llx\n", uid, to_uid, sctx, uptr); + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = (char *__user)uptr; } - + logkfi("call su uid: %d, to_uid: %d, sctx: %s, uptr: %llx\n", uid, to_uid, sctx, uptr); #ifdef ANDROID } else { filp_close(filp, 0); // command - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, apd_path, sizeof(apd_path)); - if (cplen > 0) { - hook_local->data0 = cplen; - hook_local->data1 = (uint64_t)u_filename_p; - } -#endif uint64_t sp = 0; - if (cplen <= 0) { - sp = current_user_stack_pointer(); - sp -= sizeof(apd_path); - sp &= 0xFFFFFFFFFFFFFFF8; - cplen = compat_copy_to_user((void *)sp, apd_path, sizeof(apd_path)); - if (cplen > 0) { - *u_filename_p = (char *)sp; - } + sp = current_user_stack_pointer(); + sp -= sizeof(apd_path); + sp &= 0xFFFFFFFFFFFFFFF8; + int cplen = compat_copy_to_user((void *)sp, apd_path, sizeof(apd_path)); + if (cplen > 0) { + *u_filename_p = (char *)sp; } // argv int argv_cplen = 0; if (strcmp(legacy_su_path, filename)) { -#ifdef TRY_DIRECT_MODIFY_USER - const char __user *p1 = get_user_arg_ptr(0, *uargv, 0); - argv_cplen = compat_copy_to_user((void *__user)p1, legacy_su_path, sizeof(legacy_su_path)); -#endif if (argv_cplen <= 0) { sp = sp ?: current_user_stack_pointer(); sp -= sizeof(legacy_su_path); @@ -357,17 +241,6 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen } } -#ifdef TRY_DIRECT_MODIFY_USER -static void handle_after_execve(hook_local_t *hook_local) -{ - int cplen = hook_local->data0; - char **__user u_filename_p = (char **__user)hook_local->data1; - if (cplen > 0) { - compat_copy_to_user((void *)*u_filename_p, current_su_path, cplen); - } -} -#endif - // https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2107 // COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, // const compat_uptr_t __user *, argv, @@ -381,17 +254,8 @@ static void before_execve(hook_fargs3_t *args, void *udata) { void *arg0p = syscall_argn_p(args, 0); void *arg1p = syscall_argn_p(args, 1); - handle_before_execve(&args->local, (char **)arg0p, (char **)arg1p, udata); -} - -#ifdef TRY_DIRECT_MODIFY_USER -static void after_execve(hook_fargs3_t *args, void *udata) -{ - handle_after_execve(&args->local); + handle_before_execve((char **)arg0p, (char **)arg1p, udata); } -#else -#define after_execve 0 -#endif // https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2114 // COMPAT_SYSCALL_DEFINE5(execveat, int, fd, @@ -407,18 +271,9 @@ __maybe_unused static void before_execveat(hook_fargs5_t *args, void *udata) { void *arg1p = syscall_argn_p(args, 1); void *arg2p = syscall_argn_p(args, 2); - handle_before_execve(&args->local, (char **)arg1p, (char **)arg2p, udata); + handle_before_execve((char **)arg1p, (char **)arg2p, udata); } -#ifdef TRY_DIRECT_MODIFY_USER -static void after_execveat(hook_fargs5_t *args, void *udata) -{ - handle_after_execve(&args->local); -} -#else -#define after_execveat 0 -#endif - // https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L431 // SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, // struct stat __user *, statbuf, int, flag) @@ -436,9 +291,6 @@ static void after_execveat(hook_fargs5_t *args, void *udata) // struct statx __user *, buffer) static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) { - // copy to user len - args->local.data0 = 0; - uid_t uid = current_uid(); if (!is_su_allow_uid(uid)) return; @@ -449,52 +301,24 @@ static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) if (flen <= 0) return; if (!strcmp(current_su_path, filename)) { - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); - if (cplen > 0) { - args->local.data0 = cplen; - args->local.data1 = (uint64_t)*u_filename_p; - logkfi("su uid: %d, cp: %d\n", uid, cplen); + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = uptr; } else { -#endif - void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); - if (uptr && !IS_ERR(uptr)) { - *u_filename_p = uptr; - } else { - logkfi("su uid: %d, cp stack error: %d\n", uid, uptr); - } -#ifdef TRY_DIRECT_MODIFY_USER + logkfi("su uid: %d, cp stack error: %d\n", uid, uptr); } -#endif } } -#ifdef TRY_DIRECT_MODIFY_USER -static void su_handler_arg1_ufilename_after(hook_fargs6_t *args, void *udata) -{ - int cplen = args->local.data0; - if (cplen > 0) { - compat_copy_to_user((void *)args->local.data1, current_su_path, cplen); - } -} -#else -#define su_handler_arg1_ufilename_after 0 -#endif - int su_compat_init() { current_su_path = default_su_path; - INIT_LIST_HEAD(&allow_uid_list); - spin_lock_init(&list_lock); - #ifdef ANDROID // default shell if (!all_allow_sctx[0]) strcpy(all_allow_sctx, ALL_ALLOW_SCONTEXT_MAGISK); - struct su_profile_ext ext = { .exclude = 0 }; - su_add_allow_uid(2000, 0, all_allow_sctx, &ext, 1); - su_add_allow_uid(0, 0, all_allow_sctx, &ext, 1); + su_add_allow_uid(2000, 0, all_allow_sctx, 1); + su_add_allow_uid(0, 0, all_allow_sctx, 1); #endif hook_err_t rc = HOOK_NO_ERR; @@ -504,56 +328,28 @@ int su_compat_init() bool wrap = su_config & PATCH_CONFIG_SU_HOOK_NO_WRAP; log_boot("su config, enable: %d, wrap: %d\n"); - rc = hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)0); - log_boot("hook __NR_execve rc: %d\n", rc); + if (!enable) return; - // rc = hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)0); - // log_boot("hook __NR_execveat rc: %d\n", rc); + 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, su_handler_arg1_ufilename_after, - (void *)0); + 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_statx, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - // log_boot("hook __NR_statx rc: %d\n", rc); - - rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, 0, (void *)0); log_boot("hook __NR_faccessat rc: %d\n", rc); - // rc = - // hook_syscalln(__NR_faccessat2, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - // log_boot("hook __NR_faccessat2 rc: %d\n", rc); - - // #include - // __NR_execve 11 - rc = hook_compat_syscalln(11, 3, before_execve, after_execve, (void *)1); + rc = hook_compat_syscalln(11, 3, before_execve, 0, (void *)1); log_boot("hook 32 __NR_execve rc: %d\n", rc); - // __NR_execveat 387 - // rc = hook_compat_syscalln(387, 5, before_execveat, after_execveat, (void *)1); - // log_boot("hook 32 __NR_execveat rc: %d\n", rc); - - // __NR_statx 397 - // rc = hook_compat_syscalln(397, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - // log_boot("hook 32 __NR_statx rc: %d\n", rc); - - // #define __NR_stat 106 - // #define __NR_lstat 107 - // #define __NR_stat64 195 - // #define __NR_lstat64 196 - // __NR_fstatat64 327 - rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + 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, su_handler_arg1_ufilename_after, (void *)0); + rc = hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, 0, (void *)0); log_boot("hook 32 __NR_faccessat rc: %d\n", rc); - // __NR_faccessat2 439 - // rc = hook_compat_syscalln(439, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - // log_boot("hook 32 __NR_faccessat2 rc: %d\n", rc); - return 0; } \ No newline at end of file diff --git a/kernel/patch/common/sucompat.c.bak b/kernel/patch/common/sucompat.c.bak new file mode 100644 index 00000000..be3ab2e4 --- /dev/null +++ b/kernel/patch/common/sucompat.c.bak @@ -0,0 +1,554 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 bmax121. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char sh_path[] = SH_PATH; +const char default_su_path[] = SU_PATH; + +#ifdef ANDROID +const char legacy_su_path[] = LEGACY_SU_PATH; +const char apd_path[] = APD_PATH; +#endif + +static const char *current_su_path = 0; + +static struct list_head allow_uid_list; +static spinlock_t list_lock; + +static void allow_reclaim_callback(struct rcu_head *rcu) +{ + struct allow_uid *allow = container_of(rcu, struct allow_uid, rcu); + kvfree(allow); +} + +struct su_profile profile_su_allow_uid(uid_t uid) +{ + rcu_read_lock(); + struct allow_uid *pos; + struct su_profile profile = { 0 }; + list_for_each_entry_rcu(pos, &allow_uid_list, list) + { + if (pos->uid == uid) { + memcpy(&profile, &pos->profile, sizeof(struct su_profile)); + rcu_read_unlock(); + return profile; + } + } + rcu_read_unlock(); + return profile; +} +KP_EXPORT_SYMBOL(profile_su_allow_uid); + +int is_su_allow_uid(uid_t uid) +{ + rcu_read_lock(); + struct allow_uid *pos; + list_for_each_entry_rcu(pos, &allow_uid_list, list) + { + if (pos->uid == uid) { + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + return 0; +} +KP_EXPORT_SYMBOL(is_su_allow_uid); + +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext, int async) +{ + if (!scontext) scontext = ""; + + rcu_read_lock(); + struct allow_uid *pos, *old = 0; + list_for_each_entry(pos, &allow_uid_list, list) + { + if (pos->uid == uid) { + old = pos; + break; + } + } + // todo: vmalloc -> kmalloc, gfp + struct allow_uid *new = (struct allow_uid *)vmalloc(sizeof(struct allow_uid)); + new->uid = uid; + new->profile.uid = uid; + new->profile.to_uid = to_uid; + strncpy(new->profile.scontext, scontext, sizeof(new->profile.scontext)); + new->profile.scontext[sizeof(new->profile.scontext) - 1] = '\0'; + + spin_lock(&list_lock); + if (old) { // update + list_replace_rcu(&old->list, &new->list); + logkfi("update uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); + } else { // add new one + list_add_rcu(&new->list, &allow_uid_list); + logkfi("new uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); + } + spin_unlock(&list_lock); + + rcu_read_unlock(); + if (old) { + if (async) { + call_rcu(&old->rcu, allow_reclaim_callback); + } else { + synchronize_rcu(); + kvfree(old); + } + } + return 0; +} +KP_EXPORT_SYMBOL(su_add_allow_uid); + +int su_remove_allow_uid(uid_t uid, int async) +{ + struct allow_uid *pos; + spin_lock(&list_lock); + list_for_each_entry(pos, &allow_uid_list, list) + { + if (pos->uid == uid) { + list_del_rcu(&pos->list); + spin_unlock(&list_lock); + logkfi("uid: %d, to_uid: %d, sctx: %s\n", pos->uid, pos->profile.to_uid, pos->profile.scontext); + if (async) { + call_rcu(&pos->rcu, allow_reclaim_callback); + } else { + synchronize_rcu(); + kvfree(pos); + } + return 0; + } + } + spin_unlock(&list_lock); + return 0; +} +KP_EXPORT_SYMBOL(su_remove_allow_uid); + +int su_allow_uid_nums() +{ + int num = 0; + rcu_read_lock(); + struct allow_uid *pos; + list_for_each_entry(pos, &allow_uid_list, list) + { + num++; + } + rcu_read_unlock(); + logkfd("%d\n", num); + return num; +} +KP_EXPORT_SYMBOL(su_allow_uid_nums); + +int su_allow_uids(int is_user, uid_t *out_uids, int out_num) +{ + int rc = 0; + int num = 0; + rcu_read_lock(); + struct allow_uid *pos; + list_for_each_entry(pos, &allow_uid_list, list) + { + if (num >= out_num) goto out; + + uid_t uid = pos->profile.uid; + if (is_user) { + int cplen = compat_copy_to_user(out_uids + num, &uid, sizeof(uid)); + logkfd("uid: %d\n", uid); + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + goto out; + } + } else { + out_uids[num] = uid; + } + + num++; + } + rc = num; +out: + rcu_read_unlock(); + return rc; +} +KP_EXPORT_SYMBOL(su_allow_uids); + +int su_allow_uid_profile(int is_user, uid_t uid, struct su_profile *profile) +{ + int rc = -ENOENT; + rcu_read_lock(); + struct allow_uid *pos; + list_for_each_entry(pos, &allow_uid_list, list) + { + if (pos->profile.uid != uid) continue; + if (is_user) { + int cplen = compat_copy_to_user(profile, &pos->profile, sizeof(struct su_profile)); + logkfd("profile: %d %d %s\n", uid, pos->profile.to_uid, pos->profile.scontext); + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + goto out; + } + } else { + memcpy(profile, &pos->profile, sizeof(struct su_profile)); + } + rc = 0; + goto out; + } +out: + rcu_read_unlock(); + return rc; +} +KP_EXPORT_SYMBOL(su_allow_uid_profile); + +// no free, no lock +int su_reset_path(const char *path) +{ + if (!path) return -EINVAL; + if (IS_ERR(path)) return PTR_ERR(path); + current_su_path = path; + logkfd("%s\n", current_su_path); + dsb(ish); + return 0; +} +KP_EXPORT_SYMBOL(su_reset_path); + +const char *su_get_path() +{ + if (!current_su_path) current_su_path = default_su_path; + return current_su_path; +} +KP_EXPORT_SYMBOL(su_get_path); + +// #define TRY_DIRECT_MODIFY_USER + +#define INLINE_HOOK_SYSCALL + +static void handle_before_execve(hook_local_t *hook_local, char **__user u_filename_p, char **__user uargv, void *udata) +{ +#ifdef TRY_DIRECT_MODIFY_USER + // copy to user len + hook_local->data0 = 0; +#endif + + char __user *ufilename = *u_filename_p; + char filename[SU_PATH_MAX_LEN]; + int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); + if (flen <= 0) return; + + if (!strcmp(current_su_path, filename)) { + uid_t uid = current_uid(); + if (!is_su_allow_uid(uid)) return; + struct su_profile profile = profile_su_allow_uid(uid); + + uid_t to_uid = profile.to_uid; + const char *sctx = profile.scontext; + commit_su(to_uid, sctx); + +#ifdef ANDROID + struct file *filp = filp_open(apd_path, O_RDONLY, 0); + if (!filp || IS_ERR(filp)) { +#endif + int cplen = 0; +#ifdef TRY_DIRECT_MODIFY_USER + cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); + if (cplen > 0) { + hook_local->data0 = cplen; + hook_local->data1 = (uint64_t)u_filename_p; + logkfi("call su uid: %d, to_uid: %d, sctx: %s, cplen: %d\n", uid, to_uid, sctx, cplen); + } +#endif + if (cplen <= 0) { + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = (char *__user)uptr; + } + logkfi("call su uid: %d, to_uid: %d, sctx: %s, uptr: %llx\n", uid, to_uid, sctx, uptr); + } + +#ifdef ANDROID + } else { + filp_close(filp, 0); + + // command + int cplen = 0; +#ifdef TRY_DIRECT_MODIFY_USER + cplen = compat_copy_to_user(*u_filename_p, apd_path, sizeof(apd_path)); + if (cplen > 0) { + hook_local->data0 = cplen; + hook_local->data1 = (uint64_t)u_filename_p; + } +#endif + uint64_t sp = 0; + if (cplen <= 0) { + sp = current_user_stack_pointer(); + sp -= sizeof(apd_path); + sp &= 0xFFFFFFFFFFFFFFF8; + cplen = compat_copy_to_user((void *)sp, apd_path, sizeof(apd_path)); + if (cplen > 0) { + *u_filename_p = (char *)sp; + } + } + + // argv + int argv_cplen = 0; + if (strcmp(legacy_su_path, filename)) { +#ifdef TRY_DIRECT_MODIFY_USER + const char __user *p1 = get_user_arg_ptr(0, *uargv, 0); + argv_cplen = compat_copy_to_user((void *__user)p1, legacy_su_path, sizeof(legacy_su_path)); +#endif + if (argv_cplen <= 0) { + sp = sp ?: current_user_stack_pointer(); + sp -= sizeof(legacy_su_path); + sp &= 0xFFFFFFFFFFFFFFF8; + argv_cplen = compat_copy_to_user((void *)sp, legacy_su_path, sizeof(legacy_su_path)); + if (argv_cplen > 0) { + int rc = set_user_arg_ptr(0, *uargv, 0, sp); + if (rc < 0) { // todo: modify entire argv + logkfi("call apd argv error, uid: %d, to_uid: %d, sctx: %s, rc: %d\n", uid, to_uid, sctx, + rc); + } + } + } + } + logkfi("call apd uid: %d, to_uid: %d, sctx: %s, cplen: %d, %d\n", uid, to_uid, sctx, cplen, argv_cplen); + } +#endif // ANDROID + } else if (!strcmp(SUPERCMD, filename)) { + handle_supercmd(u_filename_p, uargv); + return; + } +} + +#ifdef TRY_DIRECT_MODIFY_USER +static void handle_after_execve(hook_local_t *hook_local) +{ + int cplen = hook_local->data0; + char **__user u_filename_p = (char **__user)hook_local->data1; + if (cplen > 0) { + compat_copy_to_user((void *)*u_filename_p, current_su_path, cplen); + } +} +#endif + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2107 +// COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, +// const compat_uptr_t __user *, argv, +// const compat_uptr_t __user *, envp) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2087 +// SYSCALL_DEFINE3(execve, const char __user *, filename, const char __user *const __user *, argv, +// const char __user *const __user *, envp) + +static void before_execve(hook_fargs3_t *args, void *udata) +{ + void *arg0p = syscall_argn_p(args, 0); + void *arg1p = syscall_argn_p(args, 1); + handle_before_execve(&args->local, (char **)arg0p, (char **)arg1p, udata); +} + +#ifdef TRY_DIRECT_MODIFY_USER +static void after_execve(hook_fargs3_t *args, void *udata) +{ + handle_after_execve(&args->local); +} +#else +#define after_execve 0 +#endif + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2114 +// COMPAT_SYSCALL_DEFINE5(execveat, int, fd, +// const char __user *, filename, +// const compat_uptr_t __user *, argv, +// const compat_uptr_t __user *, envp, +// int, flags) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2095 +// SYSCALL_DEFINE5(execveat, int, fd, const char __user *, filename, const char __user *const __user *, argv, +// const char __user *const __user *, envp, int, flags) +__maybe_unused static void before_execveat(hook_fargs5_t *args, void *udata) +{ + void *arg1p = syscall_argn_p(args, 1); + void *arg2p = syscall_argn_p(args, 2); + handle_before_execve(&args->local, (char **)arg1p, (char **)arg2p, udata); +} + +#ifdef TRY_DIRECT_MODIFY_USER +static void after_execveat(hook_fargs5_t *args, void *udata) +{ + handle_after_execve(&args->local); +} +#else +#define after_execveat 0 +#endif + +// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L431 +// SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, +// struct stat __user *, statbuf, int, flag) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L492 +// SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L497 +// SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode, int, flags) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L661 +// SYSCALL_DEFINE5(statx, +// 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) +{ + // copy to user len + args->local.data0 = 0; + + uid_t uid = current_uid(); + if (!is_su_allow_uid(uid)) return; + + char __user **u_filename_p = (char __user **)syscall_argn_p(args, 1); + + char filename[SU_PATH_MAX_LEN]; + int flen = compat_strncpy_from_user(filename, *u_filename_p, sizeof(filename)); + if (flen <= 0) return; + + if (!strcmp(current_su_path, filename)) { +#ifdef TRY_DIRECT_MODIFY_USER + int cplen = 0; + cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); + if (cplen > 0) { + args->local.data0 = cplen; + args->local.data1 = (uint64_t)*u_filename_p; + logkfi("su uid: %d, cp: %d\n", uid, cplen); + } else { +#endif + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = uptr; + } else { + logkfi("su uid: %d, cp stack error: %d\n", uid, uptr); + } +#ifdef TRY_DIRECT_MODIFY_USER + } +#endif + } +} + +#ifdef TRY_DIRECT_MODIFY_USER +static void su_handler_arg1_ufilename_after(hook_fargs6_t *args, void *udata) +{ + int cplen = args->local.data0; + if (cplen > 0) { + compat_copy_to_user((void *)args->local.data1, current_su_path, cplen); + } +} +#else +#define su_handler_arg1_ufilename_after 0 +#endif + +int su_compat_init() +{ + current_su_path = default_su_path; + + INIT_LIST_HEAD(&allow_uid_list); + spin_lock_init(&list_lock); + +#ifdef ANDROID + // default shell + if (!all_allow_sctx[0]) strcpy(all_allow_sctx, ALL_ALLOW_SCONTEXT_MAGISK); + su_add_allow_uid(2000, 0, all_allow_sctx, 1); + su_add_allow_uid(0, 0, all_allow_sctx, 1); +#endif + + hook_err_t rc = HOOK_NO_ERR; + + uint8_t su_config = patch_config->patch_su_config; + bool enable = su_config & PATCH_CONFIG_SU_ENABLE; + bool wrap = su_config & PATCH_CONFIG_SU_HOOK_NO_WRAP; + log_boot("su config, enable: %d, wrap: %d\n"); + + rc = hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)0); + log_boot("hook __NR_execve rc: %d\n", rc); + + // rc = hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)0); + // log_boot("hook __NR_execveat rc: %d\n", rc); + + rc = hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, + (void *)0); + log_boot("hook __NR3264_fstatat rc: %d\n", rc); + + // rc = hook_syscalln(__NR_statx, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook __NR_statx rc: %d\n", rc); + + rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + log_boot("hook __NR_faccessat rc: %d\n", rc); + + // rc = + // hook_syscalln(__NR_faccessat2, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook __NR_faccessat2 rc: %d\n", rc); + + // #include + + // __NR_execve 11 + rc = hook_compat_syscalln(11, 3, before_execve, after_execve, (void *)1); + log_boot("hook 32 __NR_execve rc: %d\n", rc); + + // __NR_execveat 387 + // rc = hook_compat_syscalln(387, 5, before_execveat, after_execveat, (void *)1); + // log_boot("hook 32 __NR_execveat rc: %d\n", rc); + + // __NR_statx 397 + // rc = hook_compat_syscalln(397, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook 32 __NR_statx rc: %d\n", rc); + + // #define __NR_stat 106 + // #define __NR_lstat 107 + // #define __NR_stat64 195 + // #define __NR_lstat64 196 + + // __NR_fstatat64 327 + rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (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, su_handler_arg1_ufilename_after, (void *)0); + log_boot("hook 32 __NR_faccessat rc: %d\n", rc); + + // __NR_faccessat2 439 + // rc = hook_compat_syscalln(439, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook 32 __NR_faccessat2 rc: %d\n", rc); + + return 0; +} \ No newline at end of file diff --git a/kernel/patch/common/supercall.c b/kernel/patch/common/supercall.c index 05311e8f..f8bf6fb7 100644 --- a/kernel/patch/common/supercall.c +++ b/kernel/patch/common/supercall.c @@ -38,19 +38,6 @@ static long call_test(long arg1, long arg2, long arg3) { - // char *cmd = "/system/bin/touch"; - // // const char *superkey = get_superkey(); - // char *argv[] = { - // cmd, - // "/data/local/tmp/test.txt", - // NULL, - // }; - // char *envp[] = { - // "PATH=/system/bin:/data/adb", - // NULL, - // }; - // int rc = call_usermodehelper(cmd, argv, envp, UMH_WAIT_PROC); - // log_boot("user_init: %d\n", rc); return 0; } @@ -179,7 +166,7 @@ static long call_grant_uid(struct su_profile *__user uprofile) { struct su_profile *profile = memdup_user(uprofile, sizeof(struct su_profile)); if (!profile || IS_ERR(profile)) return PTR_ERR(profile); - int rc = su_add_allow_uid(profile->uid, profile->to_uid, profile->scontext, &profile->ext, 1); + int rc = su_add_allow_uid(profile->uid, profile->to_uid, profile->scontext, 1); kvfree(profile); return rc; } @@ -328,7 +315,6 @@ static long supercall(int is_key_auth, long cmd, long arg1, long arg2, long arg3 } switch (cmd) { - case SUPERCALL_MEM_PHYS: default: break; } diff --git a/kernel/patch/common/supercmd.c b/kernel/patch/common/supercmd.c index d63f92dd..afcc24e2 100644 --- a/kernel/patch/common/supercmd.c +++ b/kernel/patch/common/supercmd.c @@ -75,14 +75,14 @@ static const char supercmd_help[] = " whose full PATH is '/system/bin/kp'. This can avoid conflicts with the existing 'su' command.\n" " If you wish to modify this PATH, you can use the 'reset' command.\n" " SubCommand:\n" - " grant [TO_UID [SCONTEXT [EXCLUDE]]] Grant su permission to UID. EXCLUDE is 'true' or 'false'.\n" - " revoke Revoke su permission to UID.\n" - " num Get the number of uids with the aforementioned permissions.\n" - " list List all su allowed uids.\n" - " profile Get the profile of the uid configuration.\n" - " path [PATH] Get or Reset current su path. The length of PATH must 2-127.\n" - " sctx [SCONTEXT] Get or Reset current all allowed security context, \n" - " event Report EVENT.\n" + " grant [TO_UID [SCONTEXT]] Grant su permission to UID.\n" + " revoke Revoke su permission to UID.\n" + " num Get the number of uids with the aforementioned permissions.\n" + " list List all su allowed uids.\n" + " profile Get the profile of the uid configuration.\n" + " path [PATH] Get or Reset current su path. The length of PATH must 2-127.\n" + " sctx [SCONTEXT] Get or Reset current all allowed security context, \n" + " event Report EVENT.\n" "\n" "The command below requires superkey authentication.\n" " module [...]: KernelPatch Module manager\n" @@ -122,9 +122,7 @@ static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char } if (carr[3]) kstrtoull(carr[3], 10, &to_uid); if (carr[4]) scontext = carr[4]; - struct su_profile_ext ext = { .exclude = false }; - if (carr[5] && !strcmp(carr[5], "true")) ext.exclude = true; - su_add_allow_uid(uid, to_uid, scontext, &ext, 1); + su_add_allow_uid(uid, to_uid, scontext, 1); sprintf(buffer, "grant %d, %d, %s", uid, to_uid, scontext); cmd_res->msg = buffer; } else if (!strcmp(sub_cmd, "revoke")) { @@ -163,8 +161,7 @@ static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char cmd_res->rc = su_allow_uid_profile(0, uid, &profile); if (cmd_res->rc) return; - sprintf(buffer, "uid: %d, to_uid: %d, scontext: %s, exclude: %d", profile.uid, profile.to_uid, profile.scontext, - profile.ext.exclude); + sprintf(buffer, "uid: %d, to_uid: %d, scontext: %s", profile.uid, profile.to_uid, profile.scontext); cmd_res->msg = buffer; } else if (!strcmp(sub_cmd, "path")) { diff --git a/kernel/patch/common/syscall.c b/kernel/patch/common/syscall.c index 17c64d6e..6a7c3909 100644 --- a/kernel/patch/common/syscall.c +++ b/kernel/patch/common/syscall.c @@ -265,7 +265,7 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 } KP_EXPORT_SYMBOL(raw_syscall6); -hook_err_t __fp_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) +hook_err_t fp_wrap_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) { if (!is_compat) { if (!sys_call_table) return HOOK_BAD_ADDRESS; @@ -279,9 +279,9 @@ hook_err_t __fp_hook_syscalln(int nr, int narg, int is_compat, void *before, voi return fp_hook_wrap(fp_addr, narg, before, after, udata); } } -KP_EXPORT_SYMBOL(__fp_hook_syscalln); +KP_EXPORT_SYMBOL(fp_wrap_syscalln); -void __fp_unhook_syscalln(int nr, int is_compat, void *before, void *after) +void fp_unwrap_syscalln(int nr, int is_compat, void *before, void *after) { if (!is_compat) { if (!sys_call_table) return; @@ -293,7 +293,7 @@ void __fp_unhook_syscalln(int nr, int is_compat, void *before, void *after) fp_hook_unwrap(fp_addr, before, after); } } -KP_EXPORT_SYMBOL(__fp_unhook_syscalln); +KP_EXPORT_SYMBOL(fp_unwrap_syscalln); /* sys_xxx.cfi_jt @@ -301,47 +301,47 @@ sys_xxx.cfi_jt hint #0x22 # bti c b #0xfffffffffeb452f4 */ -hook_err_t __inline_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) +hook_err_t inline_wrap_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) { uintptr_t addr = syscalln_name_addr(nr, is_compat); if (!addr) return -HOOK_BAD_ADDRESS; if (has_syscall_wrapper) narg = 1; return hook_wrap((void *)addr, narg, before, after, udata); } -KP_EXPORT_SYMBOL(__inline_hook_syscalln); +KP_EXPORT_SYMBOL(inline_wrap_syscalln); -void __inline_unhook_syscalln(int nr, int is_compat, void *before, void *after) +void inline_unwrap_syscalln(int nr, int is_compat, void *before, void *after) { uintptr_t addr = syscalln_name_addr(nr, is_compat); hook_unwrap((void *)addr, before, after); } -KP_EXPORT_SYMBOL(__inline_unhook_syscalln); +KP_EXPORT_SYMBOL(inline_unwrap_syscalln); hook_err_t hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { - if (sys_call_table) return __fp_hook_syscalln(nr, narg, 0, before, after, udata); - return __inline_hook_syscalln(nr, narg, 0, before, after, udata); + if (sys_call_table) return fp_wrap_syscalln(nr, narg, 0, before, after, udata); + return inline_wrap_syscalln(nr, narg, 0, before, after, udata); } KP_EXPORT_SYMBOL(hook_syscalln); void unhook_syscalln(int nr, void *before, void *after) { - if (sys_call_table) return __fp_unhook_syscalln(nr, 0, before, after); - return __inline_unhook_syscalln(nr, 0, before, after); + if (sys_call_table) return fp_unwrap_syscalln(nr, 0, before, after); + return inline_unwrap_syscalln(nr, 0, before, after); } KP_EXPORT_SYMBOL(unhook_syscalln); hook_err_t hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) { - if (compat_sys_call_table) return __fp_hook_syscalln(nr, narg, 1, before, after, udata); - return __inline_hook_syscalln(nr, narg, 1, before, after, udata); + if (compat_sys_call_table) return fp_wrap_syscalln(nr, narg, 1, before, after, udata); + return inline_wrap_syscalln(nr, narg, 1, before, after, udata); } KP_EXPORT_SYMBOL(hook_compat_syscalln); void unhook_compat_syscalln(int nr, void *before, void *after) { - if (compat_sys_call_table) return __fp_unhook_syscalln(nr, 1, before, after); - return __inline_unhook_syscalln(nr, 1, before, after); + if (compat_sys_call_table) return fp_unwrap_syscalln(nr, 1, before, after); + return inline_unwrap_syscalln(nr, 1, before, after); } KP_EXPORT_SYMBOL(unhook_compat_syscalln); diff --git a/kernel/patch/include/accctl.h b/kernel/patch/include/accctl.h index ebc87b57..dd1f54ca 100644 --- a/kernel/patch/include/accctl.h +++ b/kernel/patch/include/accctl.h @@ -24,8 +24,8 @@ int commit_common_su(uid_t to_uid, const char *sctx); int commit_su(uid_t uid, const char *sctx); int task_su(pid_t pid, uid_t to_uid, const char *sctx); -int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext, struct su_profile_ext *ext, int async); -int su_remove_allow_uid(uid_t uid, int async); +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext); +int su_remove_allow_uid(uid_t uid); int su_allow_uid_nums(); int su_allow_uids(int is_user, uid_t *out_uids, int out_num); int su_allow_uid_profile(int is_user, uid_t uid, struct su_profile *profile); diff --git a/kernel/patch/include/kstorage.h b/kernel/patch/include/kstorage.h new file mode 100644 index 00000000..13159d2e --- /dev/null +++ b/kernel/patch/include/kstorage.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 bmax121. All Rights Reserved. + */ + +#ifndef _KP_KSTORAGE_H_ +#define _KP_KSTORAGE_H_ + +#include +#include +#include + +struct kstorage +{ + struct list_head list; + struct rcu_head rcu; + + int gid; + long did; + int dlen; + char data[0]; +}; + +int try_alloc_kstroage_group(); + +int kstorage_group_size(int gid); + +int write_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); + +// must surround with rcu read lock +const struct kstorage *get_kstorage(int gid, long did); + +typedef int (*on_kstorage_cb)(struct kstroage *kstorage, void *udata); +int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata); + +const struct kstorage *get_kstorage(int gid, long did); + +int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); + +int remove_kstorage(int gid, long did); + +#endif \ No newline at end of file diff --git a/kernel/patch/include/syscall.h b/kernel/patch/include/syscall.h index d1d1d02d..a20bfc7f 100644 --- a/kernel/patch/include/syscall.h +++ b/kernel/patch/include/syscall.h @@ -81,7 +81,7 @@ static inline void *syscall_argn_p(void *fdata_args, int n) * @param udata * @return hook_err_t */ -hook_err_t __fp_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata); +hook_err_t fp_wrap_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata); /** * @brief @@ -91,26 +91,26 @@ hook_err_t __fp_hook_syscalln(int nr, int narg, int is_compat, void *before, voi * @param before * @param after */ -void __fp_unhook_syscalln(int nr, int is_compat, void *before, void *after); +void fp_unwrap_syscalln(int nr, int is_compat, void *before, void *after); static inline hook_err_t fp_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { - return __fp_hook_syscalln(nr, narg, 0, before, after, udata); + return fp_wrap_syscalln(nr, narg, 0, before, after, udata); } static inline void fp_unhook_syscalln(int nr, void *before, void *after) { - return __fp_unhook_syscalln(nr, 0, before, after); + return fp_unwrap_syscalln(nr, 0, before, after); } static inline hook_err_t fp_hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) { - return __fp_hook_syscalln(nr, narg, 1, before, after, udata); + return fp_wrap_syscalln(nr, narg, 1, before, after, udata); } static inline void fp_unhook_compat_syscalln(int nr, void *before, void *after) { - return __fp_unhook_syscalln(nr, 1, before, after); + return fp_unwrap_syscalln(nr, 1, before, after); } /** @@ -124,7 +124,7 @@ static inline void fp_unhook_compat_syscalln(int nr, void *before, void *after) * @param udata * @return hook_err_t */ -hook_err_t __inline_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata); +hook_err_t inline_wrap_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata); /** * @brief @@ -134,26 +134,26 @@ hook_err_t __inline_hook_syscalln(int nr, int narg, int is_compat, void *before, * @param before * @param after */ -void __inline_unhook_syscalln(int nr, int is_compat, void *before, void *after); +void inline_unwrap_syscalln(int nr, int is_compat, void *before, void *after); static inline hook_err_t inline_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { - return __inline_hook_syscalln(nr, narg, 0, before, after, udata); + return inline_wrap_syscalln(nr, narg, 0, before, after, udata); } static inline void inline_unhook_syscalln(int nr, void *before, void *after) { - __inline_unhook_syscalln(nr, 0, before, after); + inline_unwrap_syscalln(nr, 0, before, after); } static inline hook_err_t inline_hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) { - return __inline_hook_syscalln(nr, narg, 1, before, after, udata); + return inline_wrap_syscalln(nr, narg, 1, before, after, udata); } static inline void inline_unhook_compat_syscalln(int nr, void *before, void *after) { - __inline_unhook_syscalln(nr, 0, before, after); + inline_unwrap_syscalln(nr, 0, before, after); } // diff --git a/kernel/patch/include/uapi/scdefs.h b/kernel/patch/include/uapi/scdefs.h index 42234bb8..ff273b65 100644 --- a/kernel/patch/include/uapi/scdefs.h +++ b/kernel/patch/include/uapi/scdefs.h @@ -41,12 +41,22 @@ static inline long hash_key(const char *key) #define SUPERCALL_KPM_LIST 0x1031 #define SUPERCALL_KPM_INFO 0x1032 -#define SUPERCALL_MEM_PHYS 0x1041 -#define SUPERCALL_MEM_KERNEL_PHYS 0x1042 -#define SUPERCALL_MEM_MAP_KERNEL 0x1048 -#define SUPERCALL_MEM_MAP_USER 0x1049 -#define SUPERCALL_MEM_PROT 0x1049 -#define SUPERCALL_MEM_CACHE_FLUSH 0x1049 +struct kernel_storage +{ + void *data; + int len; +}; + +#define SUPERCALL_KSTORAGE_ALLOC_GROUP 0x1040 +#define SUPERCALL_KSTORAGE_SET 0x1041 +#define SUPERCALL_KSTORAGE_GET 0x1042 +#define SUPERCALL_KSTORAGE_REMOVE 0x1043 +#define SUPERCALL_KSTORAGE_REMOVE_GROUP 0x1044 + +#define KSTORAGE_SU_LIST_GROUP 0 +#define KSTORAGE_EXCLUDE_LIST_GROUP 1 +#define KSTORAGE_UNUSED_GROUP_2 2 +#define KSTORAGE_UNUSED_GROUP_3 3 #define SUPERCALL_BOOTLOG 0x10fd #define SUPERCALL_PANIC 0x10fe @@ -55,23 +65,6 @@ static inline long hash_key(const char *key) #define SUPERCALL_KEY_MAX_LEN 0x40 #define SUPERCALL_SCONTEXT_LEN 0x60 -struct su_profile_ext -{ - union - { - bool exclude; - }; - char _[32]; -}; - -struct su_profile -{ - uid_t uid; - uid_t to_uid; - char scontext[SUPERCALL_SCONTEXT_LEN]; - struct su_profile_ext ext; -}; - #ifdef ANDROID #define SH_PATH "/system/bin/sh" #define SU_PATH "/system/bin/kp" diff --git a/kernel/patch/patch.c b/kernel/patch/patch.c index 9f30d866..44260e80 100644 --- a/kernel/patch/patch.c +++ b/kernel/patch/patch.c @@ -50,6 +50,7 @@ void linux_misc_symbol_init(); void linux_libs_symbol_init(); void module_init(); void syscall_init(); +int kstorage_init(); #ifdef ANDROID int android_user_init(); @@ -76,6 +77,9 @@ static void before_rest_init(hook_fargs4_t *args, void *udata) rc = supercall_install(); log_boot("supercall_install done: %d\n", rc); + rc = kstorage_init(); + log_boot("kstorage_init done: %d\n", rc); + rc = su_compat_init(); log_boot("su_compat_init done: %d\n", rc);