diff --git a/kernel/Makefile b/kernel/Makefile index 1641425e..7f6137cc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -141,6 +141,11 @@ ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_ ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR endif +# Function proc_ops check +ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0) +ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS +endif + ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat ccflags-y += -Wno-declaration-after-statement -Wno-unused-function diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index ef57c291..4f3fba0d 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -23,35 +23,6 @@ #error "LKM mode is not supported on Linux 6.8+, aborting build." #endif -/** - * list_count_nodes - count the number of nodes in a list - * @head: the head of the list - * - * This function iterates over the list starting from @head and counts - * the number of nodes in the list. It does not modify the list. - * - * Context: Any context. The function is safe to call in any context, - * including interrupt context, as it does not sleep or allocate - * memory. - * - * Return: the number of nodes in the list (excluding the head) - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) -static inline __maybe_unused size_t list_count_nodes(const struct list_head *head) -{ - const struct list_head *pos; - size_t count = 0; - - if (!head) - return 0; - - list_for_each(pos, head) - count++; - - return count; -} -#endif - /* * Adapt to Huawei HISI kernel without affecting other kernels , * Huawei Hisi Kernel EBITMAP Enable or Disable Flag , diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index e0e4d230..47e2c371 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -22,8 +22,7 @@ static uid_t locked_manager_uid = KSU_INVALID_UID; static uid_t locked_dynamic_manager_uid = KSU_INVALID_UID; #define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_list" -#define USER_DATA_PATH "/data/user_de/0" -#define USER_DATA_PATH_LEN 288 +#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list" struct uid_data { struct list_head list; @@ -236,152 +235,6 @@ struct my_dir_context { #define FILLDIR_ACTOR_STOP -EINVAL #endif -struct uid_scan_stats { - size_t total_found; - size_t errors_encountered; -}; - -struct user_data_context { - struct dir_context ctx; - struct list_head *uid_list; - struct uid_scan_stats *stats; -}; - -FILLDIR_RETURN_TYPE user_data_actor(struct dir_context *ctx, const char *name, - int namelen, loff_t off, u64 ino, - unsigned int d_type) -{ - struct user_data_context *my_ctx = - container_of(ctx, struct user_data_context, ctx); - - if (!my_ctx || !my_ctx->uid_list) { - return FILLDIR_ACTOR_STOP; - } - - if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen)) - return FILLDIR_ACTOR_CONTINUE; - - if (d_type != DT_DIR) - return FILLDIR_ACTOR_CONTINUE; - - if (namelen >= KSU_MAX_PACKAGE_NAME) { - pr_warn("Package name too long: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - char package_path[USER_DATA_PATH_LEN]; - if (snprintf(package_path, sizeof(package_path), "%s/%.*s", - USER_DATA_PATH, namelen, name) >= sizeof(package_path)) { - pr_err("Path too long for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - struct path path; - int err = kern_path(package_path, LOOKUP_FOLLOW, &path); - if (err) { - pr_debug("Package path lookup failed: %s (err: %d)\n", package_path, err); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - -/* -4.11, also backported on lineage common kernel 4.9 !! -int vfs_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) - -4.10 -int vfs_getattr(struct path *path, struct kstat *stat) - -basically no mask and flags for =< 4.10 - -*/ - struct kstat stat; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) || defined(KSU_HAS_NEW_VFS_GETATTR) - err = vfs_getattr(&path, &stat, STATX_UID, AT_STATX_SYNC_AS_STAT); -#else - err = vfs_getattr(&path, &stat); -#endif - path_put(&path); - - if (err) { - pr_info("Failed to get attributes for: %s (err: %d)\n", package_path, err); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - uid_t uid = from_kuid(&init_user_ns, stat.uid); - if (uid == (uid_t)-1) { - pr_warn("Invalid UID for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC); - if (!data) { - pr_err("Failed to allocate memory for package: %.*s\n", namelen, name); - if (my_ctx->stats) - my_ctx->stats->errors_encountered++; - return FILLDIR_ACTOR_CONTINUE; - } - - data->uid = uid; - size_t copy_len = min(namelen, KSU_MAX_PACKAGE_NAME - 1); - strncpy(data->package, name, copy_len); - data->package[copy_len] = '\0'; - - list_add_tail(&data->list, my_ctx->uid_list); - - if (my_ctx->stats) - my_ctx->stats->total_found++; - - pr_info("UserDE UID: Found package: %s, uid: %u\n", data->package, data->uid); - - return FILLDIR_ACTOR_CONTINUE; -} - -static int scan_user_data_for_uids(struct list_head *uid_list) -{ - struct file *dir_file; - struct uid_scan_stats stats = {0}; - int ret = 0; - - if (!uid_list) { - return -EINVAL; - } - - dir_file = ksu_filp_open_compat(USER_DATA_PATH, O_RDONLY, 0); - if (IS_ERR(dir_file)) { - pr_err("UserDE UID: Failed to open %s, err: (%ld)\n", USER_DATA_PATH, PTR_ERR(dir_file)); - return PTR_ERR(dir_file); - } - - struct user_data_context ctx = { - .ctx.actor = user_data_actor, - .uid_list = uid_list, - .stats = &stats - }; - - ret = iterate_dir(dir_file, &ctx.ctx); - filp_close(dir_file, NULL); - - if (stats.errors_encountered > 0) { - pr_warn("Encountered %zu errors while scanning user data directory\n", - stats.errors_encountered); - } - - pr_info("UserDE UID: Scanned %s directory with %zu errors\n", - USER_DATA_PATH, stats.errors_encountered); - - return ret; -} - FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, int namelen, loff_t off, u64 ino, unsigned int d_type) @@ -577,29 +430,80 @@ void track_throne(void) { struct list_head uid_list; struct uid_data *np, *n; + __maybe_unused struct file *fp; + __maybe_unused char chr = 0; + __maybe_unused loff_t pos = 0; + __maybe_unused loff_t line_start = 0; + __maybe_unused char buf[KSU_MAX_PACKAGE_NAME]; + static bool manager_exist = false; + static bool dynamic_manager_exist = false; + int current_manager_uid = ksu_get_manager_uid() % 100000; // init uid list head INIT_LIST_HEAD(&uid_list); if (ksu_uid_scanner_enabled) { pr_info("Scanning %s directory..\n", KSU_UID_LIST_PATH); + if (uid_from_um_list(&uid_list) == 0) { pr_info("Loaded UIDs from %s success\n", KSU_UID_LIST_PATH); - } else { - pr_warn("%s read failed, falling back to %s\n", KSU_UID_LIST_PATH, USER_DATA_PATH); - if (scan_user_data_for_uids(&uid_list) < 0) - goto out; + goto uid_ready; } - } else { - pr_info("User mode scan disabled, scanning %s\n", USER_DATA_PATH); - if (scan_user_data_for_uids(&uid_list) < 0) - goto out; + + pr_warn("%s read failed, fallback to %s\n", + KSU_UID_LIST_PATH, SYSTEM_PACKAGES_LIST_PATH); } - // check if manager UID exists - bool manager_exist = false; - int current_manager_uid = ksu_get_manager_uid() % 100000; + { + fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp)); + return; + } + for (;;) { + ssize_t count = + ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); + if (count != sizeof(chr)) + break; + if (chr != '\n') + continue; + + count = ksu_kernel_read_compat(fp, buf, sizeof(buf), + &line_start); + struct uid_data *data = + kzalloc(sizeof(struct uid_data), GFP_ATOMIC); + if (!data) { + filp_close(fp, 0); + goto out; + } + + char *tmp = buf; + const char *delim = " "; + char *package = strsep(&tmp, delim); + char *uid = strsep(&tmp, delim); + if (!uid || !package) { + pr_err("update_uid: package or uid is NULL!\n"); + break; + } + + u32 res; + if (kstrtou32(uid, 10, &res)) { + pr_err("update_uid: uid parse err\n"); + break; + } + data->uid = res; + strncpy(data->package, package, KSU_MAX_PACKAGE_NAME); + list_add_tail(&data->list, &uid_list); + // reset line start + line_start = pos; + } + + filp_close(fp, 0); + } + +uid_ready: + // first, check if manager_uid exist! list_for_each_entry(np, &uid_list, list) { if (np->uid == current_manager_uid) { manager_exist = true; @@ -608,14 +512,15 @@ void track_throne(void) } if (!manager_exist && locked_manager_uid != KSU_INVALID_UID) { - pr_info("Manager APK removed, unlocking previous UID: %d\n", locked_manager_uid); + pr_info("Manager APK removed, unlock previous UID: %d\n", + locked_manager_uid); ksu_invalidate_manager_uid(); locked_manager_uid = KSU_INVALID_UID; } // Check if the Dynamic Manager exists (only check locked UIDs) - bool dynamic_manager_exist = false; - if (ksu_is_dynamic_manager_enabled() && locked_dynamic_manager_uid != KSU_INVALID_UID) { + if (ksu_is_dynamic_manager_enabled() && + locked_dynamic_manager_uid != KSU_INVALID_UID) { list_for_each_entry(np, &uid_list, list) { if (np->uid == locked_dynamic_manager_uid) { dynamic_manager_exist = true; @@ -624,16 +529,16 @@ void track_throne(void) } if (!dynamic_manager_exist) { - pr_info("Dynamic manager APK removed, unlocking previous UID: %d\n", locked_dynamic_manager_uid); + pr_info("Dynamic manager APK removed, unlock previous UID: %d\n", + locked_dynamic_manager_uid); ksu_remove_manager(locked_dynamic_manager_uid); locked_dynamic_manager_uid = KSU_INVALID_UID; } } bool need_search = !manager_exist; - if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) { + if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) need_search = true; - } if (need_search) { pr_info("Searching for manager(s)...\n");