From 3b139f43d2962630d36828fc05f9a5b14a7c566f Mon Sep 17 00:00:00 2001 From: Kitty Cat Date: Fri, 28 Nov 2025 12:25:04 -0500 Subject: [PATCH] add susfs patch to track changes --- 50_add_susfs_in_gki-android15-6.6.patch | 2288 +++++++++++++++++++++++ 1 file changed, 2288 insertions(+) create mode 100644 50_add_susfs_in_gki-android15-6.6.patch diff --git a/50_add_susfs_in_gki-android15-6.6.patch b/50_add_susfs_in_gki-android15-6.6.patch new file mode 100644 index 0000000..0a1cef1 --- /dev/null +++ b/50_add_susfs_in_gki-android15-6.6.patch @@ -0,0 +1,2288 @@ + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 9bb1d3de723e..820d16cb2dae 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -391,6 +391,12 @@ static void input_event_dispose(struct input_dev *dev, int disposition, + } + } + ++#ifdef CONFIG_KSU_SUSFS ++extern bool ksu_input_hook __read_mostly; ++extern __attribute__((cold)) int ksu_handle_input_handle_event( ++ unsigned int *type, unsigned int *code, int *value); ++#endif ++ + void input_handle_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) + { +@@ -399,6 +405,10 @@ void input_handle_event(struct input_dev *dev, + lockdep_assert_held(&dev->event_lock); + + disposition = input_get_disposition(dev, type, code, &value); ++#ifdef CONFIG_KSU_SUSFS ++ if (unlikely(ksu_input_hook)) ++ ksu_handle_input_handle_event(&type, &code, &value); ++#endif + if (disposition != INPUT_IGNORE_EVENT) { + if (type != EV_SYN) + add_input_randomness(type, code, value); +diff --git a/fs/Makefile b/fs/Makefile +index c6963a9a4d0a..e27ac368bbb4 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -22,6 +22,8 @@ obj-y := open.o read_write.o file_table.o super.o \ + fs_types.o fs_context.o fs_parser.o fsopen.o init.o \ + kernel_read_file.o mnt_idmapping.o remap_range.o + ++obj-$(CONFIG_KSU_SUSFS) += susfs.o ++ + obj-$(CONFIG_BUFFER_HEAD) += buffer.o mpage.o + obj-$(CONFIG_PROC_FS) += proc_namespace.o + obj-$(CONFIG_LEGACY_DIRECT_IO) += direct-io.o +diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c +index 299c295a27a0..d27b3d4e7874 100644 +--- a/fs/devpts/inode.c ++++ b/fs/devpts/inode.c +@@ -24,6 +24,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS ++#include ++#endif + + #define DEVPTS_DEFAULT_MODE 0600 + /* +@@ -578,6 +581,10 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) + return dentry; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern int ksu_handle_devpts(struct inode*); ++#endif ++ + /** + * devpts_get_priv -- get private data for a slave + * @dentry: dentry of the slave +@@ -586,6 +593,14 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) + */ + void *devpts_get_priv(struct dentry *dentry) + { ++#ifdef CONFIG_KSU_SUSFS ++ if (likely(susfs_is_current_proc_umounted())) { ++ goto orig_flow; ++ } ++ ksu_handle_devpts(dentry->d_inode); ++orig_flow: ++#endif ++ + if (dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC) + return NULL; + return dentry->d_fsdata; +diff --git a/fs/exec.c b/fs/exec.c +index cf487b0e49dd..a7179de288d8 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -67,6 +67,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS ++#include ++#endif + + #include + #include +@@ -1901,6 +1904,15 @@ static int bprm_execve(struct linux_binprm *bprm, + return retval; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern bool ksu_execveat_hook __read_mostly; ++extern bool __ksu_is_allow_uid_for_current(uid_t uid); ++extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, ++ void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, void *argv, ++ void *envp, int *flags); ++#endif ++ + static int do_execveat_common(int fd, struct filename *filename, + struct user_arg_ptr argv, + struct user_arg_ptr envp, +@@ -1912,6 +1924,20 @@ static int do_execveat_common(int fd, struct filename *filename, + if (IS_ERR(filename)) + return PTR_ERR(filename); + ++#ifdef CONFIG_KSU_SUSFS ++ if (likely(susfs_is_current_proc_umounted())) { ++ goto orig_flow; ++ } ++ ++ if (unlikely(ksu_execveat_hook)) { ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ } else if ((__ksu_is_allow_uid_for_current(current_uid().val))) { ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); ++ } ++ ++orig_flow: ++#endif ++ + /* + * We move the actual failure in case of RLIMIT_NPROC excess from + * set*uid() to execve() because too many poorly written programs +diff --git a/fs/namei.c b/fs/namei.c +index 5f45d9b2f84d..7bbc0b94067f 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -41,10 +41,22 @@ + #include + #include + #include ++#if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT) ++#include ++#endif + + #include "internal.h" + #include "mount.h" + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++extern bool susfs_is_sus_android_data_d_name_found(const char *d_name); ++extern bool susfs_is_sus_sdcard_d_name_found(const char *d_name); ++extern bool susfs_is_inode_sus_path(struct mnt_idmap *idmap, struct inode *inode); ++extern bool susfs_is_base_dentry_android_data_dir(struct dentry* base); ++extern bool susfs_is_base_dentry_sdcard_dir(struct dentry* base); ++extern const struct qstr susfs_fake_qstr_name; ++#endif ++ + /* [Feb-1997 T. Schoebel-Theuer] + * Fundamental changes in the pathname lookup mechanisms (namei) + * were necessary because of omirr. The reason is that omirr needs +@@ -1619,6 +1631,11 @@ static struct dentry *lookup_fast(struct nameidata *nd) + { + struct dentry *dentry, *parent = nd->path.dentry; + int status = 1; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct vfsmount *mnt = nd->path.mnt; ++ unsigned int backup_next_seq = nd->next_seq; ++ bool is_nd_state_lookup_last_and_open_last = (nd->state & ND_STATE_LOOKUP_LAST || nd->state & ND_STATE_OPEN_LAST); ++#endif + + /* + * Rename seqlock is not required here because in the off chance +@@ -1626,7 +1643,31 @@ static struct dentry *lookup_fast(struct nameidata *nd) + * going to fall back to non-racy lookup. + */ + if (nd->flags & LOOKUP_RCU) { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last_and_open_last && parent->d_inode) { ++ if (susfs_is_base_dentry_android_data_dir(parent) && ++ susfs_is_sus_android_data_d_name_found(nd->last.name)) ++ { ++ dentry = __d_lookup_rcu(parent, &susfs_fake_qstr_name, &nd->next_seq); ++ goto skip_orig_flow1; ++ } else if (susfs_is_base_dentry_sdcard_dir(parent) && ++ susfs_is_sus_sdcard_d_name_found(nd->last.name)) ++ { ++ dentry = __d_lookup_rcu(parent, &susfs_fake_qstr_name, &nd->next_seq); ++ goto skip_orig_flow1; ++ } ++ } ++#endif + dentry = __d_lookup_rcu(parent, &nd->last, &nd->next_seq); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last_and_open_last && dentry && !IS_ERR(dentry) && dentry->d_inode && parent->d_inode && mnt) { ++ if (susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) { ++ dput(dentry); ++ dentry = __d_lookup_rcu(parent, &susfs_fake_qstr_name, &backup_next_seq); ++ } ++ } ++skip_orig_flow1: ++#endif + if (unlikely(!dentry)) { + if (!try_to_unlazy(nd)) + return ERR_PTR(-ECHILD); +@@ -1649,7 +1690,31 @@ static struct dentry *lookup_fast(struct nameidata *nd) + /* we'd been told to redo it in non-rcu mode */ + status = d_revalidate(dentry, nd->flags); + } else { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last_and_open_last && parent->d_inode) { ++ if (susfs_is_base_dentry_android_data_dir(parent) && ++ susfs_is_sus_android_data_d_name_found(nd->last.name)) ++ { ++ dentry = __d_lookup(parent, &susfs_fake_qstr_name); ++ goto skip_orig_flow2; ++ } else if (susfs_is_base_dentry_sdcard_dir(parent) && ++ susfs_is_sus_sdcard_d_name_found(nd->last.name)) ++ { ++ dentry = __d_lookup(parent, &susfs_fake_qstr_name); ++ goto skip_orig_flow2; ++ } ++ } ++#endif + dentry = __d_lookup(parent, &nd->last); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last_and_open_last && dentry && !IS_ERR(dentry) && dentry->d_inode && parent->d_inode && mnt) { ++ if (susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) { ++ dput(dentry); ++ dentry = __d_lookup(parent, &susfs_fake_qstr_name); ++ } ++ } ++skip_orig_flow2: ++#endif + if (unlikely(!dentry)) + return NULL; + status = d_revalidate(dentry, nd->flags); +@@ -1985,6 +2050,10 @@ static const char *handle_dots(struct nameidata *nd, int type) + static const char *walk_component(struct nameidata *nd, int flags) + { + struct dentry *dentry; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *base = nd->path.dentry; ++ bool is_nd_state_lookup_last = (nd->state & ND_STATE_LOOKUP_LAST); ++#endif + /* + * "." and ".." are special - ".." especially so because it has + * to be able to know about the current root directory and +@@ -1999,7 +2068,31 @@ static const char *walk_component(struct nameidata *nd, int flags) + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + if (unlikely(!dentry)) { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last && base->d_inode) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(nd->last.name)) ++ { ++ dentry = lookup_slow(&susfs_fake_qstr_name, base, nd->flags); ++ goto skip_orig_flow; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(nd->last.name)) ++ { ++ dentry = lookup_slow(&susfs_fake_qstr_name, base, nd->flags); ++ goto skip_orig_flow; ++ } ++ } ++#endif + dentry = lookup_slow(&nd->last, nd->path.dentry, nd->flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_lookup_last && dentry && !IS_ERR(dentry) && dentry->d_inode && base->d_inode && ++ susfs_is_inode_sus_path(mnt_idmap(nd->path.mnt), dentry->d_inode)) ++ { ++ dput(dentry); ++ dentry = lookup_slow(&susfs_fake_qstr_name, base, nd->flags); ++ } ++skip_orig_flow: ++#endif + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + } +@@ -2266,11 +2359,22 @@ static int link_path_walk(const char *name, struct nameidata *nd) + const char *link; + u64 hash_len; + int type; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *dentry; ++#endif + + idmap = mnt_idmap(nd->path.mnt); + err = may_lookup(idmap, nd); + if (err) + return err; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ dentry = nd->path.dentry; ++ if (dentry->d_inode && susfs_is_inode_sus_path(idmap, dentry->d_inode)) { ++ // - No need to dput() here ++ // - return -ENOENT here since it is walking the sub path of sus path ++ return -ENOENT; ++ } ++#endif + + hash_len = hash_name(nd->path.dentry, name); + +@@ -2296,6 +2400,23 @@ static int link_path_walk(const char *name, struct nameidata *nd) + hash_len = this.hash_len; + name = this.name; + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (nd->state & ND_STATE_LAST_SDCARD_SUS_PATH) { ++ // return -ENOENT here since it is walking the sub path of sus sdcard path ++ return -ENOENT; ++ } ++ if (parent->d_inode) { ++ if (susfs_is_base_dentry_android_data_dir(parent) && ++ susfs_is_sus_android_data_d_name_found(name)) ++ { ++ nd->state |= ND_STATE_LAST_SDCARD_SUS_PATH; ++ } else if (susfs_is_base_dentry_sdcard_dir(parent) && ++ susfs_is_sus_sdcard_d_name_found(name)) ++ { ++ nd->state |= ND_STATE_LAST_SDCARD_SUS_PATH; ++ } ++ } ++#endif + } + + nd->last.hash_len = hash_len; +@@ -2455,6 +2576,9 @@ static inline const char *lookup_last(struct nameidata *nd) + { + if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) + nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ nd->state |= ND_STATE_LOOKUP_LAST; ++#endif + + return walk_component(nd, WALK_TRAILING); + } +@@ -3402,15 +3526,57 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, + int error, create_error = 0; + umode_t mode = op->mode; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct vfsmount *mnt; ++ bool found_sus_path = false; ++ bool is_nd_state_open_last = (nd->state & ND_STATE_OPEN_LAST); ++#endif + + if (unlikely(IS_DEADDIR(dir_inode))) + return ERR_PTR(-ENOENT); + + file->f_mode &= ~FMODE_CREATED; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ mnt = nd->path.mnt; ++ if (is_nd_state_open_last) { ++ if (susfs_is_base_dentry_android_data_dir(dir) && ++ susfs_is_sus_android_data_d_name_found(nd->last.name)) ++ { ++ dentry = d_lookup(dir, &susfs_fake_qstr_name); ++ found_sus_path = true; ++ goto skip_orig_flow1; ++ } else if (susfs_is_base_dentry_sdcard_dir(dir) && ++ susfs_is_sus_sdcard_d_name_found(nd->last.name)) ++ { ++ dentry = d_lookup(dir, &susfs_fake_qstr_name); ++ found_sus_path = true; ++ goto skip_orig_flow1; ++ } ++ } ++#endif + dentry = d_lookup(dir, &nd->last); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (is_nd_state_open_last && dentry && !IS_ERR(dentry) && dentry->d_inode && mnt) { ++ if (susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) { ++ dput(dentry); ++ dentry = d_lookup(dir, &susfs_fake_qstr_name); ++ found_sus_path = true; ++ } ++ } ++skip_orig_flow1: ++#endif + for (;;) { + if (!dentry) { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (found_sus_path) { ++ dentry = d_alloc_parallel(dir, &susfs_fake_qstr_name, &wq); ++ goto skip_orig_flow2; ++ } ++#endif + dentry = d_alloc_parallel(dir, &nd->last, &wq); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++skip_orig_flow2: ++#endif + if (IS_ERR(dentry)) + return dentry; + } +@@ -3509,6 +3675,9 @@ static const char *open_last_lookups(struct nameidata *nd, + bool got_write = false; + struct dentry *dentry; + const char *res; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ nd->state |= ND_STATE_OPEN_LAST; ++#endif + + nd->flags |= op->intent; + +@@ -3805,12 +3974,19 @@ static struct file *path_openat(struct nameidata *nd, + return ERR_PTR(error); + } + ++#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT ++extern struct filename* susfs_get_redirected_path(unsigned long ino); ++#endif ++ + struct file *do_filp_open(int dfd, struct filename *pathname, + const struct open_flags *op) + { + struct nameidata nd; + int flags = op->lookup_flags; + struct file *filp; ++#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT ++ struct filename *fake_pathname; ++#endif + + set_nameidata(&nd, dfd, pathname, NULL); + filp = path_openat(&nd, op, flags | LOOKUP_RCU); +@@ -3818,6 +3994,25 @@ struct file *do_filp_open(int dfd, struct filename *pathname, + filp = path_openat(&nd, op, flags); + if (unlikely(filp == ERR_PTR(-ESTALE))) + filp = path_openat(&nd, op, flags | LOOKUP_REVAL); ++#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT ++ if (!IS_ERR(filp) && unlikely(filp->f_inode->i_mapping->flags & BIT_OPEN_REDIRECT) && current_uid().val < 2000) { ++ fake_pathname = susfs_get_redirected_path(filp->f_inode->i_ino); ++ if (!IS_ERR(fake_pathname)) { ++ restore_nameidata(); ++ filp_close(filp, NULL); ++ // no need to do `putname(pathname);` here as it will be done by calling process ++ set_nameidata(&nd, dfd, fake_pathname, NULL); ++ filp = path_openat(&nd, op, flags | LOOKUP_RCU); ++ if (unlikely(filp == ERR_PTR(-ECHILD))) ++ filp = path_openat(&nd, op, flags); ++ if (unlikely(filp == ERR_PTR(-ESTALE))) ++ filp = path_openat(&nd, op, flags | LOOKUP_REVAL); ++ restore_nameidata(); ++ putname(fake_pathname); ++ return filp; ++ } ++ } ++#endif + restore_nameidata(); + return filp; + } +@@ -3859,6 +4054,10 @@ static struct dentry *filename_create(int dfd, struct filename *name, + int type; + int err2; + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *base; ++ struct vfsmount *mnt; ++#endif + + error = filename_parentat(dfd, name, reval_flag, path, &last, &type); + if (error) +@@ -3880,8 +4079,37 @@ static struct dentry *filename_create(int dfd, struct filename *name, + if (last.name[last.len] && !want_dir) + create_flags = 0; + inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ base = path->dentry; ++ mnt = path->mnt; ++ if (base->d_inode && mnt) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, ++ reval_flag | create_flags); ++ goto skip_orig_flow; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, ++ reval_flag | create_flags); ++ goto skip_orig_flow; ++ } ++ } ++#endif + dentry = lookup_one_qstr_excl(&last, path->dentry, + reval_flag | create_flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry && !IS_ERR(dentry) && dentry->d_inode && base->d_inode && mnt && ++ susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) ++ { ++ dput(dentry); ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, ++ reval_flag | create_flags); ++ } ++skip_orig_flow: ++#endif + if (IS_ERR(dentry)) + goto unlock; + +@@ -4219,6 +4447,10 @@ int do_rmdir(int dfd, struct filename *name) + struct qstr last; + int type; + unsigned int lookup_flags = 0; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *base; ++ struct vfsmount *mnt; ++#endif + retry: + error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); + if (error) +@@ -4241,7 +4473,33 @@ int do_rmdir(int dfd, struct filename *name) + goto exit2; + + inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ base = path.dentry; ++ mnt = path.mnt; ++ if (base->d_inode && mnt) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow; ++ } ++ } ++#endif + dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry && !IS_ERR(dentry) && dentry->d_inode && base->d_inode && mnt && ++ susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) ++ { ++ dput(dentry); ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ } ++skip_orig_flow: ++#endif + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto exit3; +@@ -4360,6 +4618,10 @@ int do_unlinkat(int dfd, struct filename *name) + struct inode *inode = NULL; + struct inode *delegated_inode = NULL; + unsigned int lookup_flags = 0; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *base; ++ struct vfsmount *mnt; ++#endif + retry: + error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); + if (error) +@@ -4374,7 +4636,33 @@ int do_unlinkat(int dfd, struct filename *name) + goto exit2; + retry_deleg: + inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ base = path.dentry; ++ mnt = path.mnt; ++ if (base->d_inode && mnt) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(last.name)) ++ { ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow; ++ } ++ } ++#endif + dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry && !IS_ERR(dentry) && dentry->d_inode && base->d_inode && mnt && ++ susfs_is_inode_sus_path(mnt_idmap(mnt), dentry->d_inode)) ++ { ++ dput(dentry); ++ dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ } ++skip_orig_flow: ++#endif + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + +@@ -4921,6 +5209,10 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, + unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET; + bool should_retry = false; + int error = -EINVAL; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct dentry *base; ++ struct vfsmount *mnt; ++#endif + + if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) + goto put_names; +@@ -4962,9 +5254,35 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, + + retry_deleg: + trap = lock_rename(new_path.dentry, old_path.dentry); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ base = old_path.dentry; ++ mnt = old_path.mnt; ++ if (base->d_inode && mnt) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(old_last.name)) ++ { ++ old_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow1; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(old_last.name)) ++ { ++ old_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow1; ++ } ++ } ++#endif + + old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry, + lookup_flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (old_dentry && !IS_ERR(old_dentry) && old_dentry->d_inode && base->d_inode && mnt && ++ susfs_is_inode_sus_path(mnt_idmap(mnt), old_dentry->d_inode)) ++ { ++ dput(old_dentry); ++ old_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ } ++skip_orig_flow1: ++#endif + error = PTR_ERR(old_dentry); + if (IS_ERR(old_dentry)) + goto exit3; +@@ -4972,8 +5290,34 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, + error = -ENOENT; + if (d_is_negative(old_dentry)) + goto exit4; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ base = new_path.dentry; ++ mnt = new_path.mnt; ++ if (base->d_inode && mnt) { ++ if (susfs_is_base_dentry_android_data_dir(base) && ++ susfs_is_sus_android_data_d_name_found(new_last.name)) ++ { ++ new_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow2; ++ } else if (susfs_is_base_dentry_sdcard_dir(base) && ++ susfs_is_sus_sdcard_d_name_found(new_last.name)) ++ { ++ new_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ goto skip_orig_flow2; ++ } ++ } ++#endif + new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry, + lookup_flags | target_flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (new_dentry && !IS_ERR(new_dentry) && new_dentry->d_inode && base->d_inode && mnt && ++ susfs_is_inode_sus_path(mnt_idmap(mnt), new_dentry->d_inode)) ++ { ++ dput(new_dentry); ++ new_dentry = lookup_one_qstr_excl(&susfs_fake_qstr_name, base, lookup_flags); ++ } ++skip_orig_flow2: ++#endif + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto exit4; +diff --git a/fs/namespace.c b/fs/namespace.c +index 2d0231797d0d..9296c8a1e0b5 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -32,12 +32,25 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + + #include "pnode.h" + #include "internal.h" + #include + #include + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++extern bool susfs_is_current_ksu_domain(void); ++extern bool susfs_is_boot_completed_triggered; ++ ++static DEFINE_IDA(susfs_ksu_mnt_group_ida); ++static atomic64_t susfs_ksu_mounts = ATOMIC64_INIT(0); ++ ++#define CL_COPY_MNT_NS BIT(25) /* used by copy_mnt_ns() */ ++#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ + /* Maximum number of mounts in a mount namespace */ + static unsigned int sysctl_mount_max __read_mostly = 100000; + +@@ -138,6 +151,20 @@ static int mnt_alloc_id(struct mount *mnt) + + static void mnt_free_id(struct mount *mnt) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // First we have to check if susfs_mnt_id_backup == DEFAULT_KSU_MNT_ID, ++ // if so, no need to free. ++ if (mnt->mnt.susfs_mnt_id_backup == DEFAULT_KSU_MNT_ID) { ++ return; ++ } ++ ++ // Second if susfs_mnt_id_backup was set after mnt_id reorder, free it if so. ++ if (likely(mnt->mnt.susfs_mnt_id_backup)) { ++ ida_free(&mnt_id_ida, mnt->mnt.susfs_mnt_id_backup); ++ return; ++ } ++ ++#endif + ida_free(&mnt_id_ida, mnt->mnt_id); + } + +@@ -146,7 +173,23 @@ static void mnt_free_id(struct mount *mnt) + */ + static int mnt_alloc_group_id(struct mount *mnt) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ int res; ++ ++ /* - At frist susfs_is_boot_completed_triggered is set to false in kernel, ++ * and it is still allowed to assign our custom mnt_group_id via susfs_ksu_mnt_group_ida ++ * if it is ksu mounts, until susfs_is_boot_completed_triggered is set to true ++ * when boot-completed stage is triggered in core_hook.c ++ */ ++ if (!susfs_is_boot_completed_triggered && mnt->mnt_id >= DEFAULT_KSU_MNT_ID) { ++ res = ida_alloc_min(&susfs_ksu_mnt_group_ida, DEFAULT_KSU_MNT_GROUP_ID, GFP_KERNEL); ++ goto bypass_orig_flow; ++ } ++ res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL); ++bypass_orig_flow: ++#else + int res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL); ++#endif + + if (res < 0) + return res; +@@ -159,6 +202,22 @@ static int mnt_alloc_group_id(struct mount *mnt) + */ + void mnt_release_group_id(struct mount *mnt) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ /* - when boot-completed stage is triggered in core_hook.c, ++ * susfs_is_boot_completed_triggered will be set to true. ++ * - Please note that if susfs_is_boot_completed_triggered is true, then ++ * it no longer checks for the sus mnt_group_id, and the allocated ++ * sus mnt_group_id will stay in kernel memory forever, and if user ++ * suddenly umounts the sus mount in global mnt namespace, the ida_free() ++ * function will throw error to kernel log, but it won't affect the system, ++ * so it is fine. ++ */ ++ if (!susfs_is_boot_completed_triggered && mnt->mnt_group_id >= DEFAULT_KSU_MNT_GROUP_ID) { ++ ida_free(&susfs_ksu_mnt_group_ida, mnt->mnt_group_id); ++ mnt->mnt_group_id = 0; ++ return; ++ } ++#endif + ida_free(&mnt_group_ida, mnt->mnt_group_id); + mnt->mnt_group_id = 0; + } +@@ -196,6 +255,112 @@ int mnt_get_count(struct mount *mnt) + #endif + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++/* A copy of alloc_vfsmnt() but reuse the original mnt_id to mnt */ ++static struct mount *susfs_reuse_sus_vfsmnt(const char *name, int orig_mnt_id) ++{ ++ struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); ++ if (mnt) { ++ mnt->mnt_id = orig_mnt_id; ++ ++ if (name) { ++ mnt->mnt_devname = kstrdup_const(name, ++ GFP_KERNEL_ACCOUNT); ++ if (!mnt->mnt_devname) ++ goto out_free_cache; ++ } ++ ++#ifdef CONFIG_SMP ++ mnt->mnt_pcp = alloc_percpu(struct mnt_pcp); ++ if (!mnt->mnt_pcp) ++ goto out_free_devname; ++ ++ this_cpu_add(mnt->mnt_pcp->mnt_count, 1); ++#else ++ mnt->mnt_count = 1; ++ mnt->mnt_writers = 0; ++#endif ++ // Makes ida_free() easier to determine whether it should free the mnt_id or not ++ mnt->mnt.susfs_mnt_id_backup = DEFAULT_KSU_MNT_ID; ++ ++ INIT_HLIST_NODE(&mnt->mnt_hash); ++ INIT_LIST_HEAD(&mnt->mnt_child); ++ INIT_LIST_HEAD(&mnt->mnt_mounts); ++ INIT_LIST_HEAD(&mnt->mnt_list); ++ INIT_LIST_HEAD(&mnt->mnt_expire); ++ INIT_LIST_HEAD(&mnt->mnt_share); ++ INIT_LIST_HEAD(&mnt->mnt_slave_list); ++ INIT_LIST_HEAD(&mnt->mnt_slave); ++ INIT_HLIST_NODE(&mnt->mnt_mp_list); ++ INIT_LIST_HEAD(&mnt->mnt_umounting); ++ INIT_HLIST_HEAD(&mnt->mnt_stuck_children); ++ mnt->mnt.mnt_idmap = &nop_mnt_idmap; ++ } ++ return mnt; ++ ++#ifdef CONFIG_SMP ++out_free_devname: ++ kfree_const(mnt->mnt_devname); ++#endif ++out_free_cache: ++ kmem_cache_free(mnt_cache, mnt); ++ return NULL; ++} ++#endif ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++/* A copy of alloc_vfsmnt() but allocates the fake mnt_id to mnt */ ++static struct mount *susfs_alloc_sus_vfsmnt(const char *name) ++{ ++ struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); ++ if (mnt) { ++ mnt->mnt_id = DEFAULT_KSU_MNT_ID; ++ ++ if (name) { ++ mnt->mnt_devname = kstrdup_const(name, ++ GFP_KERNEL_ACCOUNT); ++ if (!mnt->mnt_devname) ++ goto out_free_cache; ++ } ++ ++#ifdef CONFIG_SMP ++ mnt->mnt_pcp = alloc_percpu(struct mnt_pcp); ++ if (!mnt->mnt_pcp) ++ goto out_free_devname; ++ ++ this_cpu_add(mnt->mnt_pcp->mnt_count, 1); ++#else ++ mnt->mnt_count = 1; ++ mnt->mnt_writers = 0; ++#endif ++ // Makes ida_free() easier to determine whether it should free the mnt_id or not ++ mnt->mnt.susfs_mnt_id_backup = DEFAULT_KSU_MNT_ID; ++ ++ INIT_HLIST_NODE(&mnt->mnt_hash); ++ INIT_LIST_HEAD(&mnt->mnt_child); ++ INIT_LIST_HEAD(&mnt->mnt_mounts); ++ INIT_LIST_HEAD(&mnt->mnt_list); ++ INIT_LIST_HEAD(&mnt->mnt_expire); ++ INIT_LIST_HEAD(&mnt->mnt_share); ++ INIT_LIST_HEAD(&mnt->mnt_slave_list); ++ INIT_LIST_HEAD(&mnt->mnt_slave); ++ INIT_HLIST_NODE(&mnt->mnt_mp_list); ++ INIT_LIST_HEAD(&mnt->mnt_umounting); ++ INIT_HLIST_HEAD(&mnt->mnt_stuck_children); ++ mnt->mnt.mnt_idmap = &nop_mnt_idmap; ++ } ++ return mnt; ++ ++#ifdef CONFIG_SMP ++out_free_devname: ++ kfree_const(mnt->mnt_devname); ++#endif ++out_free_cache: ++ kmem_cache_free(mnt_cache, mnt); ++ return NULL; ++} ++#endif ++ + static struct mount *alloc_vfsmnt(const char *name) + { + struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); +@@ -223,6 +388,10 @@ static struct mount *alloc_vfsmnt(const char *name) + mnt->mnt_count = 1; + mnt->mnt_writers = 0; + #endif ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // Make sure mnt->mnt.susfs_mnt_id_backup is initialized every time. ++ mnt->mnt.susfs_mnt_id_backup = 0; ++#endif + + INIT_HLIST_NODE(&mnt->mnt_hash); + INIT_LIST_HEAD(&mnt->mnt_child); +@@ -1085,7 +1254,19 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) + if (!fc->root) + return ERR_PTR(-EINVAL); + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // We keep checking for ksu process only until boot-completed stage is triggered ++ if (!susfs_is_boot_completed_triggered && susfs_is_current_ksu_domain()) { ++ mnt = susfs_alloc_sus_vfsmnt(fc->source ?: "none"); ++ atomic64_add(1, &susfs_ksu_mounts); ++ goto bypass_orig_flow; ++ } ++#endif ++ + mnt = alloc_vfsmnt(fc->source ?: "none"); ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++bypass_orig_flow: ++#endif + if (!mnt) + return ERR_PTR(-ENOMEM); + +@@ -1168,7 +1349,37 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, + struct mount *mnt; + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // - We do not check anymore for ksu process if boot-completed stage is triggered ++ // just to stop the performance loss ++ if (susfs_is_boot_completed_triggered) { ++ goto skip_checking_for_ksu_proc; ++ } ++ ++ // First we must check for ksu process because of magic mount ++ if (susfs_is_current_ksu_domain()) { ++ // if it is unsharing, we reuse the old->mnt_id ++ if (flag & CL_COPY_MNT_NS) { ++ mnt = susfs_reuse_sus_vfsmnt(old->mnt_devname, old->mnt_id); ++ goto bypass_orig_flow; ++ } ++ // else we just go assign fake mnt_id ++ mnt = susfs_alloc_sus_vfsmnt(old->mnt_devname); ++ goto bypass_orig_flow; ++ } ++ ++skip_checking_for_ksu_proc: ++ // Lastly for other processes of which old->mnt_id == DEFAULT_KSU_MNT_ID, go assign fake mnt_id ++ if (old->mnt_id == DEFAULT_KSU_MNT_ID) { ++ mnt = susfs_alloc_sus_vfsmnt(old->mnt_devname); ++ goto bypass_orig_flow; ++ } ++#endif ++ + mnt = alloc_vfsmnt(old->mnt_devname); ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++bypass_orig_flow: ++#endif + if (!mnt) + return ERR_PTR(-ENOMEM); + +@@ -3805,6 +4016,9 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, + copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE; + if (user_ns != ns->user_ns) + copy_flags |= CL_SHARED_TO_SLAVE; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ copy_flags |= CL_COPY_MNT_NS; ++#endif + new = copy_tree(old, old->mnt.mnt_root, copy_flags); + if (IS_ERR(new)) { + namespace_unlock(); +@@ -5060,3 +5274,36 @@ static int __init init_fs_namespace_sysctls(void) + fs_initcall(init_fs_namespace_sysctls); + + #endif /* CONFIG_SYSCTL */ ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++/* Reorder the mnt_id after all sus mounts are umounted during ksu_handle_setuid() */ ++void susfs_reorder_mnt_id(void) { ++ struct mnt_namespace *mnt_ns = current->nsproxy->mnt_ns; ++ struct mount *mnt; ++ int first_mnt_id = 0; ++ ++ if (!mnt_ns) { ++ return; ++ } ++ ++ // Do not reorder the mnt_id if there is no any ksu mount at all ++ if (atomic64_read(&susfs_ksu_mounts) == 0) { ++ return; ++ } ++ ++ get_mnt_ns(mnt_ns); ++ ++ first_mnt_id = list_first_entry(&mnt_ns->list, struct mount, mnt_list)->mnt_id; ++ list_for_each_entry(mnt, &mnt_ns->list, mnt_list) { ++ // It is very important that we don't reorder the sus mount if it is not umounted ++ if (mnt->mnt_id == DEFAULT_KSU_MNT_ID) { ++ continue; ++ } ++ WRITE_ONCE(mnt->mnt.susfs_mnt_id_backup, READ_ONCE(mnt->mnt_id)); ++ WRITE_ONCE(mnt->mnt_id, first_mnt_id++); ++ } ++ ++ put_mnt_ns(mnt_ns); ++} ++#endif ++ +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 26655572975d..dcd8f4e9035c 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -12,6 +12,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#endif + + #include "inotify/inotify.h" + #include "fanotify/fanotify.h" +@@ -22,16 +25,27 @@ + + #if defined(CONFIG_INOTIFY_USER) || defined(CONFIG_FANOTIFY) + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++static void show_fdinfo(struct seq_file *m, struct file *f, ++ void (*show)(struct seq_file *m, ++ struct fsnotify_mark *mark, ++ struct file *file)) ++#else + static void show_fdinfo(struct seq_file *m, struct file *f, + void (*show)(struct seq_file *m, + struct fsnotify_mark *mark)) ++#endif + { + struct fsnotify_group *group = f->private_data; + struct fsnotify_mark *mark; + + fsnotify_group_lock(group); + list_for_each_entry(mark, &group->marks_list, g_list) { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ show(m, mark, f); ++#else + show(m, mark); ++#endif + if (seq_has_overflowed(m)) + break; + } +@@ -71,10 +85,17 @@ static void show_mark_fhandle(struct seq_file *m, struct inode *inode) + + #ifdef CONFIG_INOTIFY_USER + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark, struct file *file) ++#else + static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) ++#endif + { + struct inotify_inode_mark *inode_mark; + struct inode *inode; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ struct mount *mnt = NULL; ++#endif + + if (mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE) + return; +@@ -82,6 +103,38 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) + inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); + inode = igrab(fsnotify_conn_inode(mark->connector)); + if (inode) { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ mnt = real_mount(file->f_path.mnt); ++ if (likely(susfs_is_current_proc_umounted()) && ++ mnt->mnt_id >= DEFAULT_KSU_MNT_ID) ++ { ++ struct path path; ++ char *pathname = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ char *dpath; ++ if (!pathname) { ++ goto out_seq_printf; ++ } ++ dpath = d_path(&file->f_path, pathname, PAGE_SIZE); ++ if (!dpath) { ++ goto out_free_pathname; ++ } ++ if (kern_path(dpath, 0, &path)) { ++ goto out_free_pathname; ++ } ++ seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:0 ", ++ inode_mark->wd, path.dentry->d_inode->i_ino, path.dentry->d_inode->i_sb->s_dev, ++ inotify_mark_user_mask(mark)); ++ show_mark_fhandle(m, path.dentry->d_inode); ++ seq_putc(m, '\n'); ++ iput(inode); ++ path_put(&path); ++ kfree(pathname); ++ return; ++out_free_pathname: ++ kfree(pathname); ++ } ++out_seq_printf: ++#endif + seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:0 ", + inode_mark->wd, inode->i_ino, inode->i_sb->s_dev, + inotify_mark_user_mask(mark)); +diff --git a/fs/open.c b/fs/open.c +index f69210a888fd..d2aa8b058d85 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -34,6 +34,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS ++#include ++#endif + + #include "internal.h" + #include +@@ -455,6 +458,12 @@ static const struct cred *access_override_creds(void) + return old_cred; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern bool __ksu_is_allow_uid_for_current(uid_t uid); ++extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, ++ int *flags); ++#endif ++ + static long do_faccessat(int dfd, const char __user *filename, int mode, int flags) + { + struct path path; +@@ -463,6 +472,18 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla + unsigned int lookup_flags = LOOKUP_FOLLOW; + const struct cred *old_cred = NULL; + ++#ifdef CONFIG_KSU_SUSFS ++ if (likely(susfs_is_current_proc_umounted())) { ++ goto orig_flow; ++ } ++ ++ if (unlikely(__ksu_is_allow_uid_for_current(current_uid().val))) { ++ ksu_handle_faccessat(&dfd, &filename, &mode, NULL); ++ } ++ ++orig_flow: ++#endif ++ + if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ + return -EINVAL; + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 7cff02bc816e..9c9fa2259610 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -100,6 +100,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++#include ++#endif + #include + #include + #include "internal.h" +@@ -913,6 +916,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf, + ssize_t copied; + char *page; + unsigned int flags; ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ struct vm_area_struct *vma; ++#endif + + if (!mm) + return 0; +@@ -931,6 +937,22 @@ static ssize_t mem_rw(struct file *file, char __user *buf, + + while (count > 0) { + size_t this_len = min_t(size_t, count, PAGE_SIZE); ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ vma = find_vma(mm, addr); ++ if (vma && vma->vm_file) { ++ struct inode *inode = file_inode(vma->vm_file); ++ if (unlikely(inode->i_mapping->flags & BIT_SUS_MAPS) && susfs_is_current_proc_umounted()) { ++ if (write) { ++ copied = -EFAULT; ++ } else { ++ copied = -EIO; ++ } ++ *ppos = addr; ++ mmput(mm); ++ goto free; ++ } ++ } ++#endif + + if (write && copy_from_user(page, buf, this_len)) { + copied = -EFAULT; +@@ -2465,6 +2487,13 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx) + for_each_vma(vmi, vma) { + if (!vma->vm_file) + continue; ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ if (unlikely(file_inode(vma->vm_file)->i_mapping->flags & BIT_SUS_MAPS) && ++ susfs_is_current_proc_umounted()) ++ { ++ continue; ++ } ++#endif + if (++pos <= ctx->pos) + continue; + +diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c +index 2e244ada1f97..792e1cb04b11 100644 +--- a/fs/proc/bootconfig.c ++++ b/fs/proc/bootconfig.c +@@ -12,8 +12,19 @@ + + static char *saved_boot_config; + ++#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG ++extern int susfs_spoof_cmdline_or_bootconfig(struct seq_file *m); ++#endif ++ + static int boot_config_proc_show(struct seq_file *m, void *v) + { ++#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG ++ if (saved_boot_config) { ++ if (!susfs_spoof_cmdline_or_bootconfig(m)) { ++ return 0; ++ } ++ } ++#endif + if (saved_boot_config) + seq_puts(m, saved_boot_config); + return 0; +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index 4297287f6ca0..61daf2b3b778 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -15,6 +15,9 @@ + #include + + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#endif + + #include "../mount.h" + #include "internal.h" +@@ -26,6 +29,9 @@ static int seq_show(struct seq_file *m, void *v) + int f_flags = 0, ret = -ENOENT; + struct file *file = NULL; + struct task_struct *task; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ struct mount *mnt = NULL; ++#endif + + task = get_proc_task(m->private); + if (!task) +@@ -56,11 +62,50 @@ static int seq_show(struct seq_file *m, void *v) + if (ret) + return ret; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ mnt = real_mount(file->f_path.mnt); ++ if (likely(susfs_is_current_proc_umounted()) && ++ mnt->mnt_id >= DEFAULT_KSU_MNT_ID) ++ { ++ struct path path; ++ char *pathname = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ char *dpath; ++ ++ for (; mnt->mnt_id >= DEFAULT_KSU_MNT_ID; mnt = mnt->mnt_parent) { } ++ ++ if (!pathname) { ++ goto out_seq_printf; ++ } ++ dpath = d_path(&file->f_path, pathname, PAGE_SIZE); ++ if (!dpath) { ++ goto out_free_pathname; ++ } ++ if (kern_path(dpath, 0, &path)) { ++ goto out_free_pathname; ++ } ++ seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", ++ (long long)file->f_pos, f_flags, ++ mnt->mnt_id, ++ path.dentry->d_inode->i_ino); ++ path_put(&path); ++ kfree(pathname); ++ goto bypass_orig_flow; ++out_free_pathname: ++ kfree(pathname); ++ } ++out_seq_printf: ++ seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", ++ (long long)file->f_pos, f_flags, ++ mnt->mnt_id, ++ file_inode(file)->i_ino); ++bypass_orig_flow: ++#else + seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", + (long long)file->f_pos, f_flags, + real_mount(file->f_path.mnt)->mnt_id, + file_inode(file)->i_ino); + ++#endif + /* show_fd_locks() never deferences files so a stale value is safe */ + show_fd_locks(m, file, files); + if (seq_has_overflowed(m)) +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index ad94f3ee623d..abb9d6b4cf23 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -23,6 +23,9 @@ + #include + #include + #include ++#if defined(CONFIG_KSU_SUSFS_SUS_KSTAT) || defined(CONFIG_KSU_SUSFS_SUS_MAP) ++#include ++#endif + + #include + #include +@@ -260,6 +263,10 @@ static void show_vma_header_prefix(struct seq_file *m, + seq_putc(m, ' '); + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++extern void susfs_sus_ino_for_show_map_vma(unsigned long ino, dev_t *out_dev, unsigned long *out_ino); ++#endif ++ + static void + show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + { +@@ -275,8 +282,35 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + + if (file) { + struct inode *inode = file_inode(vma->vm_file); ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ if (unlikely(inode->i_mapping->flags & BIT_SUS_MAPS) && susfs_is_current_proc_umounted()) { ++ seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); ++ seq_put_hex_ll(m, NULL, vma->vm_start, 8); ++ seq_put_hex_ll(m, "-", vma->vm_end, 8); ++ seq_putc(m, ' '); ++ seq_putc(m, '-'); ++ seq_putc(m, '-'); ++ seq_putc(m, '-'); ++ seq_putc(m, 'p'); ++ seq_put_hex_ll(m, " ", pgoff, 8); ++ seq_put_hex_ll(m, " ", MAJOR(dev), 2); ++ seq_put_hex_ll(m, ":", MINOR(dev), 2); ++ seq_put_decimal_ull(m, " ", ino); ++ seq_putc(m, ' '); ++ goto done; ++ } ++#endif ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++ if (unlikely(inode->i_mapping->flags & BIT_SUS_KSTAT)) { ++ susfs_sus_ino_for_show_map_vma(inode->i_ino, &dev, &ino); ++ goto bypass_orig_flow; ++ } ++#endif + dev = inode->i_sb->s_dev; + ino = inode->i_ino; ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++bypass_orig_flow: ++#endif + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; + } + +@@ -897,6 +931,26 @@ static int show_smap(struct seq_file *m, void *v) + if (!vma_pages(vma)) + goto show_pad; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ if (vma->vm_file && ++ unlikely(file_inode(vma->vm_file)->i_mapping->flags & BIT_SUS_MAPS) && ++ susfs_is_current_proc_umounted()) ++ { ++ show_map_vma(m, vma); ++ SEQ_PUT_DEC("Size: ", vma->vm_end - vma->vm_start); ++ SEQ_PUT_DEC(" kB\nKernelPageSize: ", vma_kernel_pagesize(vma)); ++ SEQ_PUT_DEC(" kB\nMMUPageSize: ", vma_mmu_pagesize(vma)); ++ seq_puts(m, " kB\n"); ++ __show_smap(m, &mss, false); ++ seq_printf(m, "THPeligible: %d\n", 0); ++ if (arch_pkeys_enabled()) ++ seq_printf(m, "ProtectionKey: %8u\n", vma_pkey(vma)); ++ seq_puts(m, "VmFlags: mr mw me"); ++ seq_putc(m, '\n'); ++ goto show_pad; ++ } ++#endif ++ + smap_gather_stats(vma, &mss, 0); + + show_map_vma(m, vma); +@@ -955,7 +1009,20 @@ static int show_smaps_rollup(struct seq_file *m, void *v) + + vma_start = vma->vm_start; + do { ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ if (vma->vm_file && ++ unlikely(file_inode(vma->vm_file)->i_mapping->flags & BIT_SUS_MAPS) && ++ susfs_is_current_proc_umounted()) ++ { ++ memset(&mss, 0, sizeof(mss)); ++ goto bypass_orig_flow; ++ } ++#endif ++ + smap_gather_stats(vma, &mss, 0); ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++bypass_orig_flow: ++#endif + last_vma_end = vma->vm_end; + + /* +@@ -1735,6 +1802,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, + int ret = 0, copied = 0; + unsigned int nr_subpages = __PAGE_SIZE / PAGE_SIZE; + pagemap_entry_t *res = NULL; ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ struct vm_area_struct *vma; ++#endif + + if (!mm || !mmget_not_zero(mm)) + goto out; +@@ -1811,6 +1881,15 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, + goto out_free; + ret = walk_page_range(mm, start_vaddr, end, &pagemap_ops, &pm); + mmap_read_unlock(mm); ++#ifdef CONFIG_KSU_SUSFS_SUS_MAP ++ vma = find_vma(mm, start_vaddr); ++ if (vma && vma->vm_file) { ++ struct inode *inode = file_inode(vma->vm_file); ++ if (unlikely(inode->i_mapping->flags & BIT_SUS_MAPS) && susfs_is_current_proc_umounted()) { ++ pm.buffer->pme = 0; ++ } ++ } ++#endif + start_vaddr = end; + + len = min(count, PM_ENTRY_BYTES * pm.pos); +diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c +index 250eb5bf7b52..f2a2649f2796 100644 +--- a/fs/proc_namespace.c ++++ b/fs/proc_namespace.c +@@ -12,12 +12,19 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#endif + + #include "proc/internal.h" /* only for get_proc_task() in ->open() */ + + #include "pnode.h" + #include "internal.h" + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++extern bool susfs_hide_sus_mnts_for_all_procs; ++#endif ++ + static __poll_t mounts_poll(struct file *file, poll_table *wait) + { + struct seq_file *m = file->private_data; +@@ -106,6 +113,12 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) + struct super_block *sb = mnt_path.dentry->d_sb; + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { ++ return 0; ++ } ++#endif ++ + if (sb->s_op->show_devname) { + err = sb->s_op->show_devname(m, mnt_path.dentry); + if (err) +@@ -140,6 +153,11 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { ++ return 0; ++ } ++#endif + seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id, + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + if (sb->s_op->show_path) { +@@ -202,6 +220,12 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) + struct super_block *sb = mnt_path.dentry->d_sb; + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ if (susfs_hide_sus_mnts_for_all_procs && r->mnt_id >= DEFAULT_KSU_MNT_ID) { ++ return 0; ++ } ++#endif ++ + /* device */ + if (sb->s_op->show_devname) { + seq_puts(m, "device "); +diff --git a/fs/read_write.c b/fs/read_write.c +index 06649023585c..443cc17ee8e7 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -619,8 +619,19 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count) + return ret; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern bool ksu_vfs_read_hook __read_mostly; ++extern __attribute__((cold)) int ksu_handle_sys_read(unsigned int fd, ++ char __user **buf_ptr, size_t *count_ptr); ++#endif ++ + SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) + { ++#ifdef CONFIG_KSU_SUSFS ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_sys_read(fd, &buf, &count); ++#endif ++ + return ksys_read(fd, buf, count); + } + +diff --git a/fs/readdir.c b/fs/readdir.c +index c8c46e294431..121909714b15 100644 +--- a/fs/readdir.c ++++ b/fs/readdir.c +@@ -24,6 +24,14 @@ + + #include + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++#include ++extern bool susfs_is_inode_sus_path(struct mnt_idmap *idmap, struct inode *inode); ++extern bool susfs_is_sus_android_data_d_name_found(const char *d_name); ++extern bool susfs_is_sus_sdcard_d_name_found(const char *d_name); ++extern bool susfs_is_base_dentry_android_data_dir(struct dentry* base); ++extern bool susfs_is_base_dentry_sdcard_dir(struct dentry* base); ++#endif + /* + * Some filesystems were never converted to '->iterate_shared()' + * and their directory iterators want the inode lock held for +@@ -173,6 +181,12 @@ struct old_linux_dirent { + struct readdir_callback { + struct dir_context ctx; + struct old_linux_dirent __user * dirent; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct super_block *sb; ++ struct mnt_idmap *idmap; ++ bool is_base_dentry_android_data_root_dir; ++ bool is_base_dentry_sdcard_root_dir; ++#endif + int result; + }; + +@@ -183,6 +197,9 @@ static bool fillonedir(struct dir_context *ctx, const char *name, int namlen, + container_of(ctx, struct readdir_callback, ctx); + struct old_linux_dirent __user * dirent; + unsigned long d_ino; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + if (buf->result) + return false; +@@ -194,6 +211,28 @@ static bool fillonedir(struct dir_context *ctx, const char *name, int namlen, + buf->result = -EOVERFLOW; + return false; + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (buf->is_base_dentry_android_data_root_dir) { ++ if (susfs_is_sus_android_data_d_name_found(name)) { ++ return true; ++ } ++ } else if (buf->is_base_dentry_sdcard_root_dir) { ++ if (susfs_is_sus_sdcard_d_name_found(name)) { ++ return true; ++ } ++ } ++ ++ inode = ilookup(buf->sb, ino); ++ if (!inode) { ++ goto orig_flow; ++ } ++ if (susfs_is_inode_sus_path(buf->idmap, inode)) { ++ iput(inode); ++ return true; ++ } ++ iput(inode); ++orig_flow: ++#endif + buf->result++; + dirent = buf->dirent; + if (!user_write_access_begin(dirent, +@@ -222,10 +261,35 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, + .ctx.actor = fillonedir, + .dirent = dirent + }; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + if (!f.file) + return -EBADF; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ buf.sb = f.file->f_inode->i_sb; ++ inode = f.file->f_path.dentry->d_inode; ++ if (f.file->f_path.dentry && inode) { ++ if (susfs_is_base_dentry_android_data_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_android_data_root_dir = true; ++ buf.is_base_dentry_sdcard_root_dir = false; ++ goto orig_flow; ++ } ++ if (susfs_is_base_dentry_sdcard_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_sdcard_root_dir = true; ++ buf.is_base_dentry_android_data_root_dir = false; ++ goto orig_flow; ++ } ++ } ++ buf.is_base_dentry_android_data_root_dir = false; ++ buf.is_base_dentry_sdcard_root_dir = false; ++orig_flow: ++ buf.idmap = mnt_idmap(f.file->f_path.mnt); ++#endif + error = iterate_dir(f.file, &buf.ctx); + if (buf.result) + error = buf.result; +@@ -250,6 +314,12 @@ struct linux_dirent { + struct getdents_callback { + struct dir_context ctx; + struct linux_dirent __user * current_dir; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct super_block *sb; ++ struct mnt_idmap *idmap; ++ bool is_base_dentry_android_data_root_dir; ++ bool is_base_dentry_sdcard_root_dir; ++#endif + int prev_reclen; + int count; + int error; +@@ -265,6 +335,9 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen, + int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, + sizeof(long)); + int prev_reclen; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + buf->error = verify_dirent_name(name, namlen); + if (unlikely(buf->error)) +@@ -280,6 +353,29 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen, + prev_reclen = buf->prev_reclen; + if (prev_reclen && signal_pending(current)) + return false; ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (buf->is_base_dentry_android_data_root_dir) { ++ if (susfs_is_sus_android_data_d_name_found(name)) { ++ return true; ++ } ++ } else if (buf->is_base_dentry_sdcard_root_dir) { ++ if (susfs_is_sus_sdcard_d_name_found(name)) { ++ return true; ++ } ++ } ++ ++ inode = ilookup(buf->sb, ino); ++ if (!inode) { ++ goto orig_flow; ++ } ++ if (susfs_is_inode_sus_path(buf->idmap, inode)) { ++ iput(inode); ++ return true; ++ } ++ iput(inode); ++orig_flow: ++#endif + dirent = buf->current_dir; + prev = (void __user *) dirent - prev_reclen; + if (!user_write_access_begin(prev, reclen + prev_reclen)) +@@ -314,11 +410,36 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, + .current_dir = dirent + }; + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + f = fdget_pos(fd); + if (!f.file) + return -EBADF; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ buf.sb = f.file->f_inode->i_sb; ++ inode = f.file->f_path.dentry->d_inode; ++ if (f.file->f_path.dentry && inode) { ++ if (susfs_is_base_dentry_android_data_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_android_data_root_dir = true; ++ buf.is_base_dentry_sdcard_root_dir = false; ++ goto orig_flow; ++ } ++ if (susfs_is_base_dentry_sdcard_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_sdcard_root_dir = true; ++ buf.is_base_dentry_android_data_root_dir = false; ++ goto orig_flow; ++ } ++ } ++ buf.is_base_dentry_android_data_root_dir = false; ++ buf.is_base_dentry_sdcard_root_dir = false; ++orig_flow: ++ buf.idmap = mnt_idmap(f.file->f_path.mnt); ++#endif + error = iterate_dir(f.file, &buf.ctx); + if (error >= 0) + error = buf.error; +@@ -338,6 +459,12 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, + struct getdents_callback64 { + struct dir_context ctx; + struct linux_dirent64 __user * current_dir; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct super_block *sb; ++ struct mnt_idmap *idmap; ++ bool is_base_dentry_android_data_root_dir; ++ bool is_base_dentry_sdcard_root_dir; ++#endif + int prev_reclen; + int count; + int error; +@@ -352,6 +479,9 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen, + int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, + sizeof(u64)); + int prev_reclen; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + buf->error = verify_dirent_name(name, namlen); + if (unlikely(buf->error)) +@@ -362,6 +492,29 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen, + prev_reclen = buf->prev_reclen; + if (prev_reclen && signal_pending(current)) + return false; ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (buf->is_base_dentry_android_data_root_dir) { ++ if (susfs_is_sus_android_data_d_name_found(name)) { ++ return true; ++ } ++ } else if (buf->is_base_dentry_sdcard_root_dir) { ++ if (susfs_is_sus_sdcard_d_name_found(name)) { ++ return true; ++ } ++ } ++ ++ inode = ilookup(buf->sb, ino); ++ if (!inode) { ++ goto orig_flow; ++ } ++ if (susfs_is_inode_sus_path(buf->idmap, inode)) { ++ iput(inode); ++ return true; ++ } ++ iput(inode); ++orig_flow: ++#endif + dirent = buf->current_dir; + prev = (void __user *)dirent - prev_reclen; + if (!user_write_access_begin(prev, reclen + prev_reclen)) +@@ -397,11 +550,36 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, + .current_dir = dirent + }; + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + f = fdget_pos(fd); + if (!f.file) + return -EBADF; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ buf.sb = f.file->f_inode->i_sb; ++ inode = f.file->f_path.dentry->d_inode; ++ if (f.file->f_path.dentry && inode) { ++ if (susfs_is_base_dentry_android_data_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_android_data_root_dir = true; ++ buf.is_base_dentry_sdcard_root_dir = false; ++ goto orig_flow; ++ } ++ if (susfs_is_base_dentry_sdcard_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_sdcard_root_dir = true; ++ buf.is_base_dentry_android_data_root_dir = false; ++ goto orig_flow; ++ } ++ } ++ buf.is_base_dentry_android_data_root_dir = false; ++ buf.is_base_dentry_sdcard_root_dir = false; ++orig_flow: ++ buf.idmap = mnt_idmap(f.file->f_path.mnt); ++#endif + error = iterate_dir(f.file, &buf.ctx); + if (error >= 0) + error = buf.error; +@@ -430,6 +608,12 @@ struct compat_old_linux_dirent { + struct compat_readdir_callback { + struct dir_context ctx; + struct compat_old_linux_dirent __user *dirent; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct super_block *sb; ++ struct mnt_idmap *idmap; ++ bool is_base_dentry_android_data_root_dir; ++ bool is_base_dentry_sdcard_root_dir; ++#endif + int result; + }; + +@@ -441,6 +625,9 @@ static bool compat_fillonedir(struct dir_context *ctx, const char *name, + container_of(ctx, struct compat_readdir_callback, ctx); + struct compat_old_linux_dirent __user *dirent; + compat_ulong_t d_ino; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + if (buf->result) + return false; +@@ -452,6 +639,28 @@ static bool compat_fillonedir(struct dir_context *ctx, const char *name, + buf->result = -EOVERFLOW; + return false; + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (buf->is_base_dentry_android_data_root_dir) { ++ if (susfs_is_sus_android_data_d_name_found(name)) { ++ return true; ++ } ++ } else if (buf->is_base_dentry_sdcard_root_dir) { ++ if (susfs_is_sus_sdcard_d_name_found(name)) { ++ return true; ++ } ++ } ++ ++ inode = ilookup(buf->sb, ino); ++ if (!inode) { ++ goto orig_flow; ++ } ++ if (susfs_is_inode_sus_path(buf->idmap, inode)) { ++ iput(inode); ++ return true; ++ } ++ iput(inode); ++orig_flow: ++#endif + buf->result++; + dirent = buf->dirent; + if (!user_write_access_begin(dirent, +@@ -480,10 +689,35 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, + .ctx.actor = compat_fillonedir, + .dirent = dirent + }; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + if (!f.file) + return -EBADF; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ buf.sb = f.file->f_inode->i_sb; ++ inode = f.file->f_path.dentry->d_inode; ++ if (f.file->f_path.dentry && inode) { ++ if (susfs_is_base_dentry_android_data_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_android_data_root_dir = true; ++ buf.is_base_dentry_sdcard_root_dir = false; ++ goto orig_flow; ++ } ++ if (susfs_is_base_dentry_sdcard_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_sdcard_root_dir = true; ++ buf.is_base_dentry_android_data_root_dir = false; ++ goto orig_flow; ++ } ++ } ++ buf.is_base_dentry_android_data_root_dir = false; ++ buf.is_base_dentry_sdcard_root_dir = false; ++orig_flow: ++ buf.idmap = mnt_idmap(f.file->f_path.mnt); ++#endif + error = iterate_dir(f.file, &buf.ctx); + if (buf.result) + error = buf.result; +@@ -502,6 +736,12 @@ struct compat_linux_dirent { + struct compat_getdents_callback { + struct dir_context ctx; + struct compat_linux_dirent __user *current_dir; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct super_block *sb; ++ struct mnt_idmap *idmap; ++ bool is_base_dentry_android_data_root_dir; ++ bool is_base_dentry_sdcard_root_dir; ++#endif + int prev_reclen; + int count; + int error; +@@ -517,6 +757,9 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen + int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + + namlen + 2, sizeof(compat_long_t)); + int prev_reclen; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + buf->error = verify_dirent_name(name, namlen); + if (unlikely(buf->error)) +@@ -532,6 +775,28 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen + prev_reclen = buf->prev_reclen; + if (prev_reclen && signal_pending(current)) + return false; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (buf->is_base_dentry_android_data_root_dir) { ++ if (susfs_is_sus_android_data_d_name_found(name)) { ++ return true; ++ } ++ } else if (buf->is_base_dentry_sdcard_root_dir) { ++ if (susfs_is_sus_sdcard_d_name_found(name)) { ++ return true; ++ } ++ } ++ ++ inode = ilookup(buf->sb, ino); ++ if (!inode) { ++ goto orig_flow; ++ } ++ if (susfs_is_inode_sus_path(buf->idmap, inode)) { ++ iput(inode); ++ return true; ++ } ++ iput(inode); ++orig_flow: ++#endif + dirent = buf->current_dir; + prev = (void __user *) dirent - prev_reclen; + if (!user_write_access_begin(prev, reclen + prev_reclen)) +@@ -565,11 +830,36 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, + .count = count + }; + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ struct inode *inode; ++#endif + + f = fdget_pos(fd); + if (!f.file) + return -EBADF; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ buf.sb = f.file->f_inode->i_sb; ++ inode = f.file->f_path.dentry->d_inode; ++ if (f.file->f_path.dentry && inode) { ++ if (susfs_is_base_dentry_android_data_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_android_data_root_dir = true; ++ buf.is_base_dentry_sdcard_root_dir = false; ++ goto orig_flow; ++ } ++ if (susfs_is_base_dentry_sdcard_dir(f.file->f_path.dentry)) ++ { ++ buf.is_base_dentry_sdcard_root_dir = true; ++ buf.is_base_dentry_android_data_root_dir = false; ++ goto orig_flow; ++ } ++ } ++ buf.is_base_dentry_android_data_root_dir = false; ++ buf.is_base_dentry_sdcard_root_dir = false; ++orig_flow: ++ buf.idmap = mnt_idmap(f.file->f_path.mnt); ++#endif + error = iterate_dir(f.file, &buf.ctx); + if (error >= 0) + error = buf.error; +diff --git a/fs/stat.c b/fs/stat.c +index 517fa4ed885e..095a324f1396 100644 +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -20,12 +20,20 @@ + #include + #include + ++#ifdef CONFIG_KSU_SUSFS ++#include ++#include ++#endif + #include + #include + + #include "internal.h" + #include "mount.h" + ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++extern void susfs_sus_ino_for_generic_fillattr(unsigned long ino, struct kstat *stat); ++#endif ++ + /** + * generic_fillattr - Fill in the basic attributes from the inode struct + * @idmap: idmap of the mount the inode was found from +@@ -49,6 +57,19 @@ void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask, + vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); + vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); + ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++ if (likely(susfs_is_current_proc_umounted()) && ++ unlikely(inode->i_mapping->flags & BIT_SUS_KSTAT)) ++ { ++ susfs_sus_ino_for_generic_fillattr(inode->i_ino, stat); ++ stat->mode = inode->i_mode; ++ stat->rdev = inode->i_rdev; ++ stat->uid = vfsuid_into_kuid(vfsuid); ++ stat->gid = vfsgid_into_kgid(vfsgid); ++ return; ++ } ++#endif ++ + stat->dev = inode->i_sb->s_dev; + stat->ino = inode->i_ino; + stat->mode = inode->i_mode; +@@ -214,6 +235,15 @@ int getname_statx_lookup_flags(int flags) + return lookup_flags; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern bool __ksu_is_allow_uid_for_current(uid_t uid); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++extern int ksu_handle_stat(int *dfd, struct filename **filename, int *flags); ++#else ++extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); ++#endif ++#endif ++ + /** + * vfs_statx - Get basic and extra attributes by filename + * @dfd: A file descriptor representing the base dir for a relative filename +@@ -236,6 +266,19 @@ static int vfs_statx(int dfd, struct filename *filename, int flags, + unsigned int lookup_flags = getname_statx_lookup_flags(flags); + int error; + ++#ifdef CONFIG_KSU_SUSFS ++ if (likely(susfs_is_current_proc_umounted())) { ++ goto orig_flow; ++ } ++ ++ if (unlikely(__ksu_is_allow_uid_for_current(current_uid().val))) { ++ ksu_handle_stat(&dfd, &filename, &flags); ++ } ++ ++orig_flow: ++#endif ++ ++ + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | + AT_STATX_SYNC_TYPE)) + return -EINVAL; +diff --git a/fs/statfs.c b/fs/statfs.c +index 2a37f9f3dba1..056b171a848e 100644 +--- a/fs/statfs.c ++++ b/fs/statfs.c +@@ -9,6 +9,10 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#include "mount.h" ++#endif + #include "internal.h" + + static int flags_by_mnt(int mnt_flags) +@@ -86,11 +90,23 @@ EXPORT_SYMBOL(vfs_get_fsid); + int vfs_statfs(const struct path *path, struct kstatfs *buf) + { + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ struct mount *mnt; + ++ mnt = real_mount(path->mnt); ++ if (likely(susfs_is_current_proc_umounted())) { ++ for (; mnt->mnt_id >= DEFAULT_KSU_MNT_ID; mnt = mnt->mnt_parent) {} ++ } ++ error = statfs_by_dentry(mnt->mnt.mnt_root, buf); ++ if (!error) ++ buf->f_flags = calculate_f_flags(&mnt->mnt); ++ return error; ++#else + error = statfs_by_dentry(path->dentry, buf); + if (!error) + buf->f_flags = calculate_f_flags(path->mnt); + return error; ++#endif + } + EXPORT_SYMBOL_NS(vfs_statfs, ANDROID_GKI_VFS_EXPORT_ONLY); + +diff --git a/include/linux/mount.h b/include/linux/mount.h +index 4e1f330f101c..c2386e5a5458 100644 +--- a/include/linux/mount.h ++++ b/include/linux/mount.h +@@ -77,7 +77,11 @@ struct vfsmount { + ANDROID_KABI_RESERVE(1); + ANDROID_KABI_RESERVE(2); + ANDROID_KABI_RESERVE(3); ++#ifdef CONFIG_KSU_SUSFS ++ ANDROID_KABI_USE(4, u64 susfs_mnt_id_backup); ++#else + ANDROID_KABI_RESERVE(4); ++#endif + } __randomize_layout; + + static inline struct mnt_idmap *mnt_idmap(const struct vfsmount *mnt) +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 18edd57b5fe8..5719b0ca344d 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -776,6 +776,10 @@ static void s_stop(struct seq_file *m, void *p) + { + } + ++#ifdef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS ++extern bool susfs_starts_with(const char *str, const char *prefix); ++#endif ++ + static int s_show(struct seq_file *m, void *p) + { + void *value; +@@ -799,8 +803,36 @@ static int s_show(struct seq_file *m, void *p) + seq_printf(m, "%px %c %s\t[%s]\n", value, + type, iter->name, iter->module_name); + } else ++#ifndef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS + seq_printf(m, "%px %c %s\n", value, + iter->type, iter->name); ++#else ++ { ++ if (susfs_starts_with(iter->name, "ksu_") || ++ susfs_starts_with(iter->name, "__ksu_") || ++ susfs_starts_with(iter->name, "susfs_") || ++ susfs_starts_with(iter->name, "ksud") || ++ susfs_starts_with(iter->name, "is_ksu_") || ++ susfs_starts_with(iter->name, "is_manager_") || ++ susfs_starts_with(iter->name, "escape_to_") || ++ susfs_starts_with(iter->name, "setup_selinux") || ++ susfs_starts_with(iter->name, "track_throne") || ++ susfs_starts_with(iter->name, "on_post_fs_data") || ++ susfs_starts_with(iter->name, "try_umount") || ++ susfs_starts_with(iter->name, "kernelsu") || ++ susfs_starts_with(iter->name, "__initcall__kmod_kernelsu") || ++ susfs_starts_with(iter->name, "apply_kernelsu") || ++ susfs_starts_with(iter->name, "handle_sepolicy") || ++ susfs_starts_with(iter->name, "getenforce") || ++ susfs_starts_with(iter->name, "setenforce") || ++ susfs_starts_with(iter->name, "is_zygote")) ++ { ++ return 0; ++ } ++ seq_printf(m, "%px %c %s\n", value, ++ iter->type, iter->name); ++ } ++#endif + return 0; + } + +diff --git a/kernel/reboot.c b/kernel/reboot.c +index 344ceaf5ed13..c2d1a782d5a5 100644 +--- a/kernel/reboot.c ++++ b/kernel/reboot.c +@@ -693,6 +693,9 @@ EXPORT_SYMBOL_GPL(kernel_power_off); + + DEFINE_MUTEX(system_transition_mutex); + ++#ifdef CONFIG_KSU_SUSFS ++extern int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg); ++#endif + /* + * Reboot system call: for obvious reasons only root may call it, + * and even root needs to set up some magic numbers in the registers +@@ -708,6 +711,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, + char buffer[256]; + int ret = 0; + ++#ifdef CONFIG_KSU_SUSFS ++ ret = ksu_handle_sys_reboot(magic1, magic2, cmd, &arg); ++ if (ret) { ++ goto orig_flow; ++ } ++ return ret; ++orig_flow: ++#endif ++ + /* We only trust the superuser with rebooting the system. */ + if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) + return -EPERM; +diff --git a/kernel/sys.c b/kernel/sys.c +index 74bed736f6a8..0d297c0dc2aa 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -741,8 +741,17 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) + return retval; + } + ++#ifdef CONFIG_KSU_SUSFS ++extern int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid); ++#endif ++ + SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) + { ++#ifdef CONFIG_KSU_SUSFS ++ if (ksu_handle_setresuid(ruid, euid, suid)) { ++ pr_info("Something wrong with ksu_handle_setresuid()\n"); ++ } ++#endif + return __sys_setresuid(ruid, euid, suid); + } + +@@ -1305,12 +1314,18 @@ static int override_release(char __user *release, size_t len) + return ret; + } + ++#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME ++extern void susfs_spoof_uname(struct new_utsname* tmp); ++#endif + SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) + { + struct new_utsname tmp; + + down_read(&uts_sem); + memcpy(&tmp, utsname(), sizeof(tmp)); ++#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME ++ susfs_spoof_uname(&tmp); ++#endif + up_read(&uts_sem); + if (copy_to_user(name, &tmp, sizeof(tmp))) + return -EFAULT; +diff --git a/security/selinux/avc.c b/security/selinux/avc.c +index 9f44a0f446ec..ef307839a90b 100644 +--- a/security/selinux/avc.c ++++ b/security/selinux/avc.c +@@ -47,6 +47,12 @@ + #undef CREATE_TRACE_POINTS + #include + ++#ifdef CONFIG_KSU_SUSFS ++extern u32 susfs_ksu_sid; ++extern u32 susfs_priv_app_sid; ++bool susfs_is_avc_log_spoofing_enabled = false; ++#endif ++ + struct avc_entry { + u32 ssid; + u32 tsid; +@@ -719,11 +725,22 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) + + rc = security_sid_to_context(sad->tsid, &tcontext, + &tcontext_len); ++#ifdef CONFIG_KSU_SUSFS ++ if (unlikely(sad->tsid == susfs_ksu_sid && susfs_is_avc_log_spoofing_enabled)) { ++ if (rc) ++ audit_log_format(ab, " tsid=%d", susfs_priv_app_sid); ++ else ++ audit_log_format(ab, " tcontext=%s", "u:r:priv_app:s0:c512,c768"); ++ goto bypass_orig_flow; ++ } ++#endif + if (rc) + audit_log_format(ab, " tsid=%d", sad->tsid); + else + audit_log_format(ab, " tcontext=%s", tcontext); +- ++#ifdef CONFIG_KSU_SUSFS ++bypass_orig_flow: ++#endif + tclass = secclass_map[sad->tclass-1].name; + audit_log_format(ab, " tclass=%s", tclass); +