From 124f704dc9ff0278a51b6873b44d36ef0621707d Mon Sep 17 00:00:00 2001 From: bmax Date: Sat, 5 Oct 2024 12:08:08 +0800 Subject: [PATCH] add kstorage list interface, android exclude list interface --- kernel/patch/common/kstorage.c | 80 ++++++++++++++++++++++-------- kernel/patch/common/sucompat.c | 27 +++++++--- kernel/patch/common/supercall.c | 7 +++ kernel/patch/common/supercmd.c | 24 ++++++++- kernel/patch/include/kstorage.h | 4 +- kernel/patch/include/sucompat.h | 1 + kernel/patch/include/uapi/scdefs.h | 5 +- user/supercall.h | 24 +++++++-- 8 files changed, 136 insertions(+), 36 deletions(-) diff --git a/kernel/patch/common/kstorage.c b/kernel/patch/common/kstorage.c index bf50d39..cbced6c 100644 --- a/kernel/patch/common/kstorage.c +++ b/kernel/patch/common/kstorage.c @@ -19,23 +19,23 @@ #define KSTRORAGE_MAX_GROUP_NUM 4 // static atomic64_t used_max_group = ATOMIC_INIT(0); -static int used_max_group = 0; +static int used_max_group = -1; 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); -// } +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; + if (used_max_group < 0 || used_max_group >= KSTRORAGE_MAX_GROUP_NUM) return -1; spin_unlock(&used_max_group_lock); return used_max_group; } @@ -96,12 +96,13 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data rcu_read_unlock(); if (old) { - // if (async) { - // call_rcu(&old->rcu, reclaim_callback); - // } else { - synchronize_rcu(); - kvfree(old); - // } + bool async = true; + if (async) { + call_rcu(&old->rcu, reclaim_callback); + } else { + synchronize_rcu(); + kvfree(old); + } } return 0; } @@ -127,7 +128,7 @@ 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 0; + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; int rc = 0; @@ -155,7 +156,10 @@ int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_ const struct kstorage *pos = get_kstorage(gid, did); - if (IS_ERR(pos)) return PTR_ERR(pos); + if (IS_ERR(pos)) { + rcu_read_unlock(); + return PTR_ERR(pos); + } int min_len = pos->dlen - offset > len ? len : pos->dlen - offset; @@ -176,6 +180,39 @@ int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_ } KP_EXPORT_SYMBOL(read_kstorage); +int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; + + 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) { + logkfd("compat_copy_to_user error: %d", cplen); + cnt = cplen; + } + } else { + memcpy(ids + cnt, &pos->did, sizeof(pos->did)); + } + cnt++; + } + + rcu_read_unlock(); + + return cnt; +} +KP_EXPORT_SYMBOL(list_kstorage_ids); + int remove_kstorage(int gid, long did) { int rc = -ENOENT; @@ -197,12 +234,13 @@ int remove_kstorage(int gid, long did) logkfi("%d %ld\n", gid, did); - // if (async) { - // call_rcu(&pos->rcu, reclaim_callback); - // } else { - synchronize_rcu(); - kvfree(pos); - // } + bool async = true; + if (async) { + call_rcu(&pos->rcu, reclaim_callback); + } else { + synchronize_rcu(); + kvfree(pos); + } return 0; } } diff --git a/kernel/patch/common/sucompat.c b/kernel/patch/common/sucompat.c index b06c30f..9a00f10 100644 --- a/kernel/patch/common/sucompat.c +++ b/kernel/patch/common/sucompat.c @@ -336,13 +336,32 @@ int get_ap_mod_exclude(uid_t uid) } KP_EXPORT_SYMBOL(get_ap_mod_exclude); +int list_ap_mod_exclude(uid_t *uids, int len) +{ + long ids[len]; + int cnt = list_kstorage_ids(exclude_kstorage_gid, ids, len, false); + for (int i = 0; i < len; i++) { + uids[i] = (uid_t)ids[i]; + } + return cnt; +} +KP_EXPORT_SYMBOL(list_ap_mod_exclude); + int su_compat_init() { current_su_path = default_su_path; + su_kstorage_gid = try_alloc_kstroage_group(); + if (su_kstorage_gid != KSTORAGE_SU_LIST_GROUP) return -ENOMEM; + + exclude_kstorage_gid = try_alloc_kstroage_group(); + if (exclude_kstorage_gid != KSTORAGE_EXCLUDE_LIST_GROUP) return -ENOMEM; + #ifdef ANDROID // default shell - if (!all_allow_sctx[0]) strcpy(all_allow_sctx, ALL_ALLOW_SCONTEXT_MAGISK); + if (!all_allow_sctx[0]) { + strcpy(all_allow_sctx, ALL_ALLOW_SCONTEXT_MAGISK); + } su_add_allow_uid(2000, 0, all_allow_sctx); su_add_allow_uid(0, 0, all_allow_sctx); #endif @@ -356,12 +375,6 @@ int su_compat_init() // if (!enable) return; - su_kstorage_gid = try_alloc_kstroage_group(); - if (su_kstorage_gid < 0) return -ENOMEM; - - exclude_kstorage_gid = try_alloc_kstroage_group(); - if (exclude_kstorage_gid < 0) return -ENOMEM; - rc = hook_syscalln(__NR_execve, 3, before_execve, 0, (void *)0); log_boot("hook __NR_execve rc: %d\n", rc); diff --git a/kernel/patch/common/supercall.c b/kernel/patch/common/supercall.c index 926c6d3..5a6f5bc 100644 --- a/kernel/patch/common/supercall.c +++ b/kernel/patch/common/supercall.c @@ -241,6 +241,11 @@ static long call_kstorage_write(int gid, long did, void *data, int offset, int d return write_kstorage(gid, did, data, offset, dlen, true); } +static long call_list_kstorage_ids(int gid, long *ids, int ids_len) +{ + return list_kstorage_ids(gid, ids, ids_len, false); +} + static long call_kstorage_remove(int gid, long did) { return remove_kstorage(gid, did); @@ -290,6 +295,8 @@ static long supercall(int is_key_auth, long cmd, long arg1, long arg2, long arg3 case SUPERCALL_KSTORAGE_WRITE: return call_kstorage_write((int)arg1, (long)arg2, (void *)arg3, (int)((long)arg4 >> 32), (long)arg4 << 32 >> 32); + case SUPERCALL_KSTORAGE_LIST_IDS: + return call_list_kstorage_ids((int)arg1, (long *)arg2, (int)arg3); case SUPERCALL_KSTORAGE_REMOVE: return call_kstorage_remove((int)arg1, (long)arg2); diff --git a/kernel/patch/common/supercmd.c b/kernel/patch/common/supercmd.c index 1316c4b..cf5c143 100644 --- a/kernel/patch/common/supercmd.c +++ b/kernel/patch/common/supercmd.c @@ -81,7 +81,10 @@ static const char supercmd_help[] = " 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" +#ifdef ANDROID + " exclude_list List all exclude UIDs.\n" " exclude [1|0] Get or Reset exclude policy for UID.\n" +#endif " event Report EVENT.\n" "\n" "The command below requires superkey authentication.\n" @@ -180,7 +183,9 @@ static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char } else { cmd_res->msg = all_allow_sctx; } - } else if (!strcmp(sub_cmd, "exclude")) { + } +#ifdef ANDROID + else if (!strcmp(sub_cmd, "exclude")) { unsigned long long uid; if (!carr[2] || kstrtoull(carr[2], 10, &uid)) { cmd_res->err_msg = "invalid uid"; @@ -200,7 +205,22 @@ static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char } } } - } else { + } else if (!strcmp(sub_cmd, "exclude_list")) { + uid_t uids[128]; + int offset = 0; + int cnt = list_ap_mod_exclude(uids, sizeof(uids) / sizeof(uids[0])); + if (cnt < 0) { + cmd_res->rc = cnt; + } else { + for (int i = 0; i < cnt; i++) { + offset += sprintf(buffer + offset, "%d\n", uids[i]); + }; + if (offset > 0) buffer[offset - 1] = '\0'; + cmd_res->msg = buffer; + } + } +#endif + else { cmd_res->err_msg = "invalid subcommand"; } } diff --git a/kernel/patch/include/kstorage.h b/kernel/patch/include/kstorage.h index b011c11..fca8c68 100644 --- a/kernel/patch/include/kstorage.h +++ b/kernel/patch/include/kstorage.h @@ -27,7 +27,7 @@ int kstorage_group_size(int gid); int write_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); -// must within rcu read lock +/// must within rcu read lock const struct kstorage *get_kstorage(int gid, long did); typedef int (*on_kstorage_cb)(struct kstorage *kstorage, void *udata); @@ -35,6 +35,8 @@ int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata); int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); +int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user); + int remove_kstorage(int gid, long did); #endif \ No newline at end of file diff --git a/kernel/patch/include/sucompat.h b/kernel/patch/include/sucompat.h index 0dc6a90..f09a95e 100644 --- a/kernel/patch/include/sucompat.h +++ b/kernel/patch/include/sucompat.h @@ -34,5 +34,6 @@ const char *su_get_path(); int get_ap_mod_exclude(uid_t uid); int set_ap_mod_exclude(uid_t uid, int exclude); +int list_ap_mod_exclude(uid_t *uids, int len); #endif diff --git a/kernel/patch/include/uapi/scdefs.h b/kernel/patch/include/uapi/scdefs.h index 7629145..1752e76 100644 --- a/kernel/patch/include/uapi/scdefs.h +++ b/kernel/patch/include/uapi/scdefs.h @@ -50,8 +50,9 @@ struct kernel_storage #define SUPERCALL_KSTORAGE_ALLOC_GROUP 0x1040 #define SUPERCALL_KSTORAGE_WRITE 0x1041 #define SUPERCALL_KSTORAGE_READ 0x1042 -#define SUPERCALL_KSTORAGE_REMOVE 0x1043 -#define SUPERCALL_KSTORAGE_REMOVE_GROUP 0x1044 +#define SUPERCALL_KSTORAGE_LIST_IDS 0x1043 +#define SUPERCALL_KSTORAGE_REMOVE 0x1044 +#define SUPERCALL_KSTORAGE_REMOVE_GROUP 0x1045 #define KSTORAGE_SU_LIST_GROUP 0 #define KSTORAGE_EXCLUDE_LIST_GROUP 1 diff --git a/user/supercall.h b/user/supercall.h index 2484c4b..8959141 100644 --- a/user/supercall.h +++ b/user/supercall.h @@ -134,7 +134,7 @@ static inline long sc_su_task(const char *key, pid_t tid, struct su_profile *pro static inline long sc_kstorage_write(const char *key, int gid, long did, void *data, int offset, int dlen) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_WRITE), gid, did, data, ((offset << 32) | dlen)); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_WRITE), gid, did, data, (((long)offset << 32) | dlen)); return ret; } @@ -151,10 +151,28 @@ static inline long sc_kstorage_write(const char *key, int gid, long did, void *d static inline long sc_kstorage_read(const char *key, int gid, long did, void *out_data, int offset, int dlen) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_READ), gid, did, out_data, ((offset << 32) | dlen)); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_READ), gid, did, out_data, (((long)offset << 32) | dlen)); return ret; } + +/** + * @brief + * + * @param key + * @param gid + * @param ids + * @param ids_len + * @return long numbers of listed ids + */ +static inline long sc_kstorage_list_ids(const char *key, int gid, long *ids, int ids_len) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_LIST_IDS), gid, ids, ids_len); + return ret; +} + + /** * @brief * @@ -166,7 +184,7 @@ static inline long sc_kstorage_read(const char *key, int gid, long did, void *ou static inline long sc_kstorage_remove(const char *key, int gid, long did) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_REMOVE), gid, did); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_REMOVE), gid); return ret; }