From d702e746e3bf8b9f0be6c9bf655492ea7c1fa260 Mon Sep 17 00:00:00 2001 From: backslashxx <118538522+backslashxx@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:30:52 +0800 Subject: [PATCH] kernel: throne_tracker: avoid cross-fs traversal using s_magic check (#2633) Skip directories that does NOT have the same magic as /data/app. This is to avoid scanning incfs and any other stacked filesystems. While this is way dumber, it's way cheaper. no kern_path(), no missable path_put(), no ref handling. This supercedes `throne_tracker: avoid cross fs access (https://github.com/tiann/KernelSU/pull/2626)` - upstream https://github.com/tiann/KernelSU/commit/0b6998b474ed00610bbf2d6679f853cef07af3b8 Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com> --- kernel/throne_tracker.c | 53 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/kernel/throne_tracker.c b/kernel/throne_tracker.c index fd8180de..fc944c55 100644 --- a/kernel/throne_tracker.c +++ b/kernel/throne_tracker.c @@ -5,7 +5,6 @@ #include #include #include -#include #include "allowlist.h" #include "klog.h" // IWYU pragma: keep @@ -116,7 +115,6 @@ struct my_dir_context { void *private_data; int depth; int *stop; - struct super_block* root_sb; }; // https://docs.kernel.org/filesystems/porting.html // filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted. @@ -137,8 +135,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, struct my_dir_context *my_ctx = container_of(ctx, struct my_dir_context, ctx); char dirpath[DATA_PATH_LEN]; - int err; - struct path path; if (!my_ctx) { pr_err("Invalid context\n"); @@ -165,18 +161,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, return FILLDIR_ACTOR_CONTINUE; } - err = kern_path(dirpath, 0, &path); - - if (err) { - pr_err("get dirpath %s err: %d\n", dirpath, err); - return FILLDIR_ACTOR_CONTINUE; - } - - if (my_ctx->root_sb != path.dentry->d_inode->i_sb) { - pr_info("skip cross fs: %s", dirpath); - return FILLDIR_ACTOR_CONTINUE; - } - if (d_type == DT_DIR && my_ctx->depth > 0 && (my_ctx->stop && !*my_ctx->stop)) { struct data_path *data = kmalloc(sizeof(struct data_path), GFP_ATOMIC); @@ -226,19 +210,11 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name, void search_manager(const char *path, int depth, struct list_head *uid_data) { - int i, stop = 0, err; + int i, stop = 0; struct list_head data_path_list; - struct path kpath; - struct super_block* root_sb; INIT_LIST_HEAD(&data_path_list); - - err = kern_path(path, 0, &kpath); - - if (err) { - pr_err("get search root %s err: %d\n", path, err); - return; - } - + unsigned long data_app_magic = 0; + // Initialize APK cache list struct apk_path_hash *pos, *n; list_for_each_entry(pos, &apk_path_hash_list, list) { @@ -251,8 +227,6 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) data.depth = depth; list_add_tail(&data.list, &data_path_list); - root_sb = kpath.dentry->d_inode->i_sb; - for (i = depth; i >= 0; i--) { struct data_path *pos, *n; @@ -262,8 +236,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) .parent_dir = pos->dirpath, .private_data = uid_data, .depth = pos->depth, - .stop = &stop, - .root_sb = root_sb }; + .stop = &stop }; struct file *file; if (!stop) { @@ -272,6 +245,24 @@ void search_manager(const char *path, int depth, struct list_head *uid_data) pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file)); goto skip_iterate; } + + // grab magic on first folder, which is /data/app + if (!data_app_magic) { + if (file->f_inode->i_sb->s_magic) { + data_app_magic = file->f_inode->i_sb->s_magic; + pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic); + } else { + filp_close(file, NULL); + goto skip_iterate; + } + } + + if (file->f_inode->i_sb->s_magic != data_app_magic) { + pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath, + file->f_inode->i_sb->s_magic, data_app_magic); + filp_close(file, NULL); + goto skip_iterate; + } iterate_dir(file, &ctx.ctx); filp_close(file, NULL);