diff --git a/50_add_susfs_in_gki-android12-5.10.patch b/50_add_susfs_in_gki-android12-5.10.patch new file mode 100644 index 000000000..cf2421b46 --- /dev/null +++ b/50_add_susfs_in_gki-android12-5.10.patch @@ -0,0 +1,1495 @@ +diff --git a/fs/Makefile b/fs/Makefile +index c7851875b668..bb53b87308d6 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -18,6 +18,9 @@ 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 remap_range.o + ++obj-$(CONFIG_KSU_SUSFS) += susfs.o ++obj-$(CONFIG_KSU_SUSFS_SUS_SU) += sus_su.o ++ + ifeq ($(CONFIG_BLOCK),y) + obj-y += buffer.o block_dev.o direct-io.o mpage.o + else +diff --git a/fs/dcache.c b/fs/dcache.c +index dd74ce596fd7..b8de7caf9dad 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++#include ++#endif + #include "internal.h" + #include "mount.h" + +@@ -2308,6 +2311,12 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, + continue; + if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0) + continue; ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ continue; ++ } ++#endif + } + *seqp = seq; + return dentry; +@@ -2391,6 +2400,12 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) + if (dentry->d_name.hash != hash) + continue; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ continue; ++ } ++#endif ++ + spin_lock(&dentry->d_lock); + if (dentry->d_parent != parent) + goto next; +diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c +index 4f25015aa534..555e4cb31e65 100644 +--- a/fs/devpts/inode.c ++++ b/fs/devpts/inode.c +@@ -596,6 +596,11 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) + return dentry; + } + ++#if defined(CONFIG_KSU_SUSFS_SUS_SU) ++extern bool ksu_devpts_hook; ++extern int ksu_handle_devpts(struct inode*); ++#endif ++ + /** + * devpts_get_priv -- get private data for a slave + * @pts_inode: inode of the slave +@@ -604,6 +609,12 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) + */ + void *devpts_get_priv(struct dentry *dentry) + { ++#if defined(CONFIG_KSU_SUSFS_SUS_SU) ++ if (likely(ksu_devpts_hook)) { ++ ksu_handle_devpts(dentry->d_inode); ++ } ++#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 4edc932a7dce..c2eb63462e30 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1867,6 +1867,12 @@ static int bprm_execve(struct linux_binprm *bprm, + return retval; + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++extern bool susfs_is_sus_su_hooks_enabled __read_mostly; ++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, +@@ -1878,6 +1884,11 @@ static int do_execveat_common(int fd, struct filename *filename, + if (IS_ERR(filename)) + return PTR_ERR(filename); + ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ if (susfs_is_sus_su_hooks_enabled) ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); ++#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 8cea84ecbf56..cbd2bbcc6da5 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -39,6 +39,9 @@ + #include + #include + #include ++#if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT) ++#include ++#endif + + #include "internal.h" + #include "mount.h" +@@ -1048,6 +1051,12 @@ int sysctl_protected_regular __read_mostly; + */ + static inline int may_follow_link(struct nameidata *nd, const struct inode *inode) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (nd->inode && unlikely(nd->inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif ++ + if (!sysctl_protected_symlinks) + return 0; + +@@ -1122,6 +1131,12 @@ int may_linkat(struct path *link) + { + struct inode *inode = link->dentry->d_inode; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (inode && unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif ++ + /* Inode writeback is not safe when the uid or gid are invalid. */ + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) + return -EOVERFLOW; +@@ -1163,6 +1178,12 @@ int may_linkat(struct path *link) + static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid, + struct inode * const inode) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif ++ + if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || + (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || + likely(!(dir_mode & S_ISVTX)) || +@@ -1526,6 +1547,9 @@ static struct dentry *__lookup_hash(const struct qstr *name, + struct dentry *dentry = lookup_dcache(name, base, flags); + struct dentry *old; + struct inode *dir = base->d_inode; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ int error; ++#endif + + if (dentry) + return dentry; +@@ -1543,6 +1567,19 @@ static struct dentry *__lookup_hash(const struct qstr *name, + dput(dentry); + dentry = old; + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ if ((flags & (LOOKUP_CREATE | LOOKUP_EXCL))) { ++ error = inode_permission(dir, MAY_WRITE | MAY_EXEC); ++ if (error) { ++ dput(dentry); ++ return ERR_PTR(error); ++ } ++ } ++ dput(dentry); ++ return ERR_PTR(-ENOENT); ++ } ++#endif + return dentry; + } + +@@ -1644,6 +1681,12 @@ static struct dentry *__lookup_slow(const struct qstr *name, + dentry = old; + } + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ dput(dentry); ++ return ERR_PTR(-ENOENT); ++ } ++#endif + return dentry; + } + +@@ -2289,6 +2332,12 @@ static int link_path_walk(const char *name, struct nameidata *nd) + } + return -ENOTDIR; + } ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ // we deal with sus sub path here ++ if (nd->inode && unlikely(nd->inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return 0; ++ } ++#endif + } + } + +@@ -2468,6 +2517,11 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags, + flags & LOOKUP_MOUNTPOINT ? AUDIT_INODE_NOEVAL : 0); + restore_nameidata(); + putname(name); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (!retval && path->dentry->d_inode && unlikely(path->dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif + return retval; + } + +@@ -2797,6 +2851,12 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) + if (IS_APPEND(dir)) + return -EPERM; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif ++ + if (check_sticky(dir, inode) || IS_APPEND(inode) || + IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) + return -EPERM; +@@ -2825,8 +2885,22 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) + */ + static inline int may_create(struct inode *dir, struct dentry *child) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ int error; ++#endif ++ + struct user_namespace *s_user_ns; + audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (child->d_inode && unlikely(child->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ error = inode_permission(dir, MAY_WRITE | MAY_EXEC); ++ if (error) { ++ return error; ++ } ++ return -ENOENT; ++ } ++#endif ++ + if (child->d_inode) + return -EEXIST; + if (IS_DEADDIR(dir)) +@@ -2990,6 +3064,12 @@ static int may_open(const struct path *path, int acc_mode, int flag) + if (!inode) + return -ENOENT; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ return -ENOENT; ++ } ++#endif ++ + switch (inode->i_mode & S_IFMT) { + case S_IFLNK: + return -ELOOP; +@@ -3069,7 +3149,20 @@ static inline int open_to_namei_flags(int flag) + static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode) + { + struct user_namespace *s_user_ns; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ int error; ++ ++ if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); ++ if (error) { ++ return error; ++ } ++ return -ENOENT; ++ } ++ error = security_path_mknod(dir, dentry, mode, 0); ++#else + int error = security_path_mknod(dir, dentry, mode, 0); ++#endif + if (error) + return error; + +@@ -3190,6 +3283,12 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, + } + if (dentry->d_inode) { + /* Cached positive dentry: will open in f_op->open */ ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ dput(dentry); ++ return ERR_PTR(-ENOENT); ++ } ++#endif + return dentry; + } + +@@ -3219,6 +3318,16 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, + dentry = atomic_open(nd, dentry, file, open_flag, mode); + if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT)) + dentry = ERR_PTR(create_error); ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ if (create_error) { ++ dput(dentry); ++ return ERR_PTR(create_error); ++ } ++ dput(dentry); ++ return ERR_PTR(-ENOENT); ++ } ++#endif + return dentry; + } + +@@ -3233,6 +3342,12 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, + } + dput(dentry); + dentry = res; ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ dput(dentry); ++ return ERR_PTR(-ENOENT); ++ } ++#endif + } + } + +@@ -3525,12 +3640,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); + filp = path_openat(&nd, op, flags | LOOKUP_RCU); +@@ -3538,6 +3660,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_state & INODE_STATE_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); ++ 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; + } +diff --git a/fs/namespace.c b/fs/namespace.c +index 5d5a426aa495..306f10926d80 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -30,10 +30,37 @@ + #include + #include + #include ++#if defined(CONFIG_KSU_SUSFS_SUS_MOUNT) || defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) ++#include ++#endif + + #include "pnode.h" + #include "internal.h" + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++extern bool susfs_is_current_ksu_domain(void); ++extern bool susfs_is_current_zygote_domain(void); ++ ++static DEFINE_IDA(susfs_mnt_id_ida); ++static DEFINE_IDA(susfs_mnt_group_ida); ++ ++#define CL_ZYGOTE_COPY_MNT_NS BIT(24) /* used by copy_mnt_ns() */ ++#define CL_COPY_MNT_NS BIT(25) /* used by copy_mnt_ns() */ ++#endif ++ ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT ++extern void susfs_auto_add_sus_ksu_default_mount(const char __user *to_pathname); ++bool susfs_is_auto_add_sus_ksu_default_mount_enabled = true; ++#endif ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT ++extern int susfs_auto_add_sus_bind_mount(const char *pathname, struct path *path_target); ++bool susfs_is_auto_add_sus_bind_mount_enabled = true; ++#endif ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT ++extern void susfs_auto_add_try_umount_for_bind_mount(struct path *path); ++bool susfs_is_auto_add_try_umount_for_bind_mount_enabled = true; ++#endif ++ + /* Maximum number of mounts in a mount namespace */ + unsigned int sysctl_mount_max __read_mostly = 100000; + +@@ -102,6 +129,18 @@ static inline struct hlist_head *mp_hash(struct dentry *dentry) + return &mountpoint_hashtable[tmp & mp_hash_mask]; + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++// Our own mnt_alloc_id() that assigns mnt_id starting from DEFAULT_SUS_MNT_ID ++static int susfs_mnt_alloc_id(struct mount *mnt) ++{ ++ int res = ida_alloc_min(&susfs_mnt_id_ida, DEFAULT_SUS_MNT_ID, GFP_KERNEL); ++ ++ if (res < 0) ++ return res; ++ mnt->mnt_id = res; ++ return 0; ++} ++#endif + static int mnt_alloc_id(struct mount *mnt) + { + int res = ida_alloc(&mnt_id_ida, GFP_KERNEL); +@@ -114,6 +153,26 @@ static int mnt_alloc_id(struct mount *mnt) + + static void mnt_free_id(struct mount *mnt) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // We should first check the 'mnt->mnt.susfs_mnt_id_backup', see if it is DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE ++ // if so, these mnt_id were not assigned by mnt_alloc_id() so we don't need to free it. ++ if (unlikely(mnt->mnt.susfs_mnt_id_backup == DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE)) { ++ return; ++ } ++ // Now we can check if its mnt_id is sus ++ if (unlikely(mnt->mnt_id >= DEFAULT_SUS_MNT_ID)) { ++ ida_free(&susfs_mnt_id_ida, mnt->mnt_id); ++ return; ++ } ++ // Lastly if 'mnt->mnt.susfs_mnt_id_backup' is not 0, then it contains a backup origin mnt_id ++ // so we free it in the original way ++ if (likely(mnt->mnt.susfs_mnt_id_backup)) { ++ // If mnt->mnt.susfs_mnt_id_backup is not zero, it means mnt->mnt_id is spoofed, ++ // so here we return the original mnt_id for being freed. ++ ida_free(&mnt_id_ida, mnt->mnt.susfs_mnt_id_backup); ++ return; ++ } ++#endif + ida_free(&mnt_id_ida, mnt->mnt_id); + } + +@@ -122,7 +181,20 @@ 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; ++ ++ // Check if mnt has sus mnt_id ++ if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { ++ // If so, assign a sus mnt_group id DEFAULT_SUS_MNT_GROUP_ID from susfs_mnt_group_ida ++ res = ida_alloc_min(&susfs_mnt_group_ida, DEFAULT_SUS_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; +@@ -135,6 +207,15 @@ static int mnt_alloc_group_id(struct mount *mnt) + */ + void mnt_release_group_id(struct mount *mnt) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // If mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID, it means 'mnt' is also sus mount, ++ // then we free the mnt->mnt_group_id from susfs_mnt_group_ida ++ if (mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID) { ++ ida_free(&susfs_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; + } +@@ -172,13 +253,31 @@ int mnt_get_count(struct mount *mnt) + #endif + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++static struct mount *alloc_vfsmnt(const char *name, bool should_spoof, int custom_mnt_id) ++#else + static struct mount *alloc_vfsmnt(const char *name) ++#endif + { + struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); + if (mnt) { + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ if (should_spoof) { ++ if (!custom_mnt_id) { ++ err = susfs_mnt_alloc_id(mnt); ++ } else { ++ mnt->mnt_id = custom_mnt_id; ++ err = 0; ++ } ++ goto bypass_orig_flow; ++ } ++#endif + err = mnt_alloc_id(mnt); ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++bypass_orig_flow: ++#endif + if (err) + goto out_free_cache; + +@@ -953,7 +1052,17 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) + if (!fc->root) + return ERR_PTR(-EINVAL); + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // For newly created mounts, the only caller process we care is KSU ++ if (unlikely(susfs_is_current_ksu_domain())) { ++ mnt = alloc_vfsmnt(fc->source ?: "none", true, 0); ++ goto bypass_orig_flow; ++ } ++ mnt = alloc_vfsmnt(fc->source ?: "none", false, 0); ++bypass_orig_flow: ++#else + mnt = alloc_vfsmnt(fc->source ?: "none"); ++#endif + if (!mnt) + return ERR_PTR(-ENOMEM); + +@@ -966,6 +1075,13 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) + mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_parent = mnt; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // If caller process is zygote, then it is a normal mount, so we just reorder the mnt_id ++ if (susfs_is_current_zygote_domain()) { ++ mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id; ++ mnt->mnt_id = current->susfs_last_fake_mnt_id++; ++ } ++#endif + lock_mount_hash(); + list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts); + unlock_mount_hash(); +@@ -1035,8 +1151,52 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, + struct super_block *sb = old->mnt.mnt_sb; + struct mount *mnt; + int err; +- ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ bool is_current_ksu_domain = susfs_is_current_ksu_domain(); ++ bool is_current_zygote_domain = susfs_is_current_zygote_domain(); ++ ++ /* - It is very important that we need to use CL_COPY_MNT_NS to identify whether ++ * the clone is a copy_tree() or single mount like called by __do_loopback() ++ * - if caller process is KSU, consider the following situation: ++ * 1. it is NOT doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id ++ * 2. it is doing unshare => spoof the new mnt_id with the old mnt_id ++ * - If caller process is zygote and old mnt_id is sus => call alloc_vfsmnt() to assign a new sus mnt_id ++ * - For the rest of caller process that doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id only for old sus mount ++ */ ++ // Firstly, check if it is KSU process ++ if (unlikely(is_current_ksu_domain)) { ++ // if it is doing single clone ++ if (!(flag & CL_COPY_MNT_NS)) { ++ mnt = alloc_vfsmnt(old->mnt_devname, true, 0); ++ goto bypass_orig_flow; ++ } ++ // if it is doing unshare ++ mnt = alloc_vfsmnt(old->mnt_devname, true, old->mnt_id); ++ if (mnt) { ++ mnt->mnt.susfs_mnt_id_backup = DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE; ++ } ++ goto bypass_orig_flow; ++ } ++ // Secondly, check if it is zygote process and no matter it is doing unshare or not ++ if (likely(is_current_zygote_domain) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) { ++ /* Important Note: ++ * - Here we can't determine whether the unshare is called zygisk or not, ++ * so we can only patch out the unshare code in zygisk source code for now ++ * - But at least we can deal with old sus mounts using alloc_vfsmnt() ++ */ ++ mnt = alloc_vfsmnt(old->mnt_devname, true, 0); ++ goto bypass_orig_flow; ++ } ++ // Lastly, for other process that is doing unshare operation, but only deal with old sus mount ++ if ((flag & CL_COPY_MNT_NS) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) { ++ mnt = alloc_vfsmnt(old->mnt_devname, true, 0); ++ goto bypass_orig_flow; ++ } ++ mnt = alloc_vfsmnt(old->mnt_devname, false, 0); ++bypass_orig_flow: ++#else + mnt = alloc_vfsmnt(old->mnt_devname); ++#endif + if (!mnt) + return ERR_PTR(-ENOMEM); + +@@ -1059,6 +1219,15 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, + mnt->mnt.mnt_root = dget(root); + mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_parent = mnt; ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // If caller process is zygote and not doing unshare, so we just reorder the mnt_id ++ if (likely(is_current_zygote_domain) && !(flag & CL_ZYGOTE_COPY_MNT_NS)) { ++ mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id; ++ mnt->mnt_id = current->susfs_last_fake_mnt_id++; ++ } ++#endif ++ + lock_mount_hash(); + list_add_tail(&mnt->mnt_instance, &sb->s_mounts); + unlock_mount_hash(); +@@ -2392,6 +2561,27 @@ static int do_loopback(struct path *path, const char *old_name, + umount_tree(mnt, UMOUNT_SYNC); + unlock_mount_hash(); + } ++#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) || defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT) ++ // Check if bind mounted path should be hidden and umounted automatically. ++ // And we target only process with ksu domain. ++ if (susfs_is_current_ksu_domain()) { ++#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) ++ if (susfs_is_auto_add_sus_bind_mount_enabled && ++ susfs_auto_add_sus_bind_mount(old_name, &old_path)) { ++ goto orig_flow; ++ } ++#endif ++#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT) ++ if (susfs_is_auto_add_try_umount_for_bind_mount_enabled) { ++ susfs_auto_add_try_umount_for_bind_mount(path); ++ } ++#endif ++ } ++#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) ++orig_flow: ++#endif ++#endif // #if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) || defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT) ++ + out2: + unlock_mount(mp); + out: +@@ -3328,6 +3518,10 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, + struct mount *old; + struct mount *new; + int copy_flags; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ bool is_zygote_pid = susfs_is_current_zygote_domain(); ++ int last_entry_mnt_id = 0; ++#endif + + BUG_ON(!ns); + +@@ -3347,6 +3541,15 @@ 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 ++ // Always let clone_mnt() in copy_tree() know it is from copy_mnt_ns() ++ copy_flags |= CL_COPY_MNT_NS; ++ if (is_zygote_pid) { ++ // Let clone_mnt() in copy_tree() know copy_mnt_ns() is run by zygote process ++ copy_flags |= CL_ZYGOTE_COPY_MNT_NS; ++ } ++#endif + new = copy_tree(old, old->mnt.mnt_root, copy_flags); + if (IS_ERR(new)) { + namespace_unlock(); +@@ -3388,6 +3591,29 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, + while (p->mnt.mnt_root != q->mnt.mnt_root) + p = next_mnt(p, old); + } ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ // current->susfs_last_fake_mnt_id -> to record last valid fake mnt_id to zygote pid ++ // q->mnt.susfs_mnt_id_backup -> original mnt_id ++ // q->mnt_id -> will be modified to the fake mnt_id ++ ++ // Here We are only interested in processes of which original mnt namespace belongs to zygote ++ // Also we just make use of existing 'q' mount pointer, no need to delcare extra mount pointer ++ if (is_zygote_pid) { ++ last_entry_mnt_id = list_first_entry(&new_ns->list, struct mount, mnt_list)->mnt_id; ++ list_for_each_entry(q, &new_ns->list, mnt_list) { ++ if (unlikely(q->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) { ++ continue; ++ } ++ q->mnt.susfs_mnt_id_backup = q->mnt_id; ++ q->mnt_id = last_entry_mnt_id++; ++ } ++ } ++ // Assign the 'last_entry_mnt_id' to 'current->susfs_last_fake_mnt_id' for later use. ++ // should be fine here assuming zygote is forking/unsharing app in one single thread. ++ // Or should we put a lock here? ++ current->susfs_last_fake_mnt_id = last_entry_mnt_id; ++#endif ++ + namespace_unlock(); + + if (rootmnt) +@@ -3460,6 +3686,13 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, + + ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options); + ++#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT) && defined(CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT) ++ // Just for the compatibility of Magic Mount KernelSU ++ if (!ret && susfs_is_auto_add_sus_ksu_default_mount_enabled && susfs_is_current_ksu_domain()) { ++ susfs_auto_add_sus_ksu_default_mount(dir_name); ++ } ++#endif ++ + kfree(options); + out_data: + kfree(kernel_dev); +@@ -3664,6 +3897,13 @@ SYSCALL_DEFINE5(move_mount, + path_put(&to_path); + out_from: + path_put(&from_path); ++#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT ++ // For Legacy KSU mount scheme ++ if (!ret && susfs_is_auto_add_sus_ksu_default_mount_enabled && susfs_is_current_ksu_domain()) { ++ susfs_auto_add_sus_ksu_default_mount(to_pathname); ++ } ++#endif ++ + return ret; + } + +@@ -4140,3 +4380,37 @@ const struct proc_ns_operations mntns_operations = { + .install = mntns_install, + .owner = mntns_owner, + }; ++ ++#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT ++extern void susfs_try_umount_all(uid_t uid); ++void susfs_run_try_umount_for_current_mnt_ns(void) { ++ struct mount *mnt; ++ struct mnt_namespace *mnt_ns; ++ ++ mnt_ns = current->nsproxy->mnt_ns; ++ // Lock the namespace ++ namespace_lock(); ++ list_for_each_entry(mnt, &mnt_ns->list, mnt_list) { ++ // Change the sus mount to be private ++ if (mnt->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) { ++ change_mnt_propagation(mnt, MS_PRIVATE); ++ } ++ } ++ // Unlock the namespace ++ namespace_unlock(); ++ susfs_try_umount_all(current_uid().val); ++} ++#endif ++#ifdef CONFIG_KSU_SUSFS ++bool susfs_is_mnt_devname_ksu(struct path *path) { ++ struct mount *mnt; ++ ++ if (path && path->mnt) { ++ mnt = real_mount(path->mnt); ++ if (mnt && mnt->mnt_devname && !strcmp(mnt->mnt_devname, "KSU")) { ++ return true; ++ } ++ } ++ return false; ++} ++#endif +\ No newline at end of file +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 765b50aeadd2..9032f23855d2 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 "fdinfo.h" +@@ -21,16 +24,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; + + mutex_lock(&group->mark_mutex); + 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; + } +@@ -72,7 +86,11 @@ 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; +@@ -83,6 +101,36 @@ 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 ++ if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && ++ unlikely(inode->i_state & INODE_STATE_SUS_KSTAT)) { ++ 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 965230a0710c..26c7eeaa9182 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -395,6 +395,12 @@ static const struct cred *access_override_creds(void) + return old_cred; + } + ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++extern bool susfs_is_sus_su_hooks_enabled __read_mostly; ++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; +@@ -403,6 +409,12 @@ 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_SUS_SU ++ if (susfs_is_sus_su_hooks_enabled) { ++ ksu_handle_faccessat(&dfd, &filename, &mode, NULL); ++ } ++#endif ++ + if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ + return -EINVAL; + +diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c +index df35954d73d2..f784def63476 100644 +--- a/fs/overlayfs/inode.c ++++ b/fs/overlayfs/inode.c +@@ -168,6 +168,15 @@ int ovl_getattr(const struct path *path, struct kstat *stat, + + metacopy_blocks = ovl_is_metacopy_dentry(dentry); + ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ ovl_path_lowerdata(dentry, &realpath); ++ if (likely(realpath.mnt && realpath.dentry)) { ++ old_cred = ovl_override_creds(dentry->d_sb); ++ err = vfs_getattr(&realpath, stat, request_mask, flags); ++ goto out; ++ } ++#endif ++ + type = ovl_path_real(dentry, &realpath); + old_cred = ovl_override_creds(dentry->d_sb); + err = vfs_getattr(&realpath, stat, request_mask, flags); +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +index 5a35f87dd66f..2688730b168a 100644 +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -930,7 +930,19 @@ static int ovl_dir_open(struct inode *inode, struct file *file) + if (!od) + return -ENOMEM; + ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ ovl_path_lowerdata(file->f_path.dentry, &realpath); ++ if (likely(realpath.mnt && realpath.dentry)) { ++ // We still use '__OVL_PATH_UPPER' here which should be fine. ++ type = __OVL_PATH_UPPER; ++ goto bypass_orig_flow; ++ } ++#endif ++ + type = ovl_path_real(file->f_path.dentry, &realpath); ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++bypass_orig_flow: ++#endif + realfile = ovl_dir_open_realfile(file, &realpath); + if (IS_ERR(realfile)) { + kfree(od); +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +index d59624b439f9..0622a660b0c6 100644 +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -324,6 +324,18 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) + struct path path; + int err; + ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ ovl_path_lowerdata(root_dentry, &path); ++ if (likely(path.mnt && path.dentry)) { ++ err = vfs_statfs(&path, buf); ++ if (!err) { ++ buf->f_namelen = 255; // 255 for erofs, ext2/4, f2fs ++ buf->f_type = path.dentry->d_sb->s_magic; ++ } ++ return err; ++ } ++#endif ++ + ovl_path_real(root_dentry, &path); + + err = vfs_statfs(&path, buf); +diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c +index 2e244ada1f97..239616b8a296 100644 +--- a/fs/proc/bootconfig.c ++++ b/fs/proc/bootconfig.c +@@ -12,8 +12,19 @@ + + static char *saved_boot_config; + ++#ifdef 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 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 6b634c0a9b6e..1bf6ca564248 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -13,6 +13,9 @@ + #include + + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++#include ++#endif + + #include "../mount.h" + #include "internal.h" +@@ -24,6 +27,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) +@@ -54,10 +60,48 @@ 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(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && ++ mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { ++ struct path path; ++ char *pathname = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ char *dpath; ++ ++ for (; mnt->mnt_id >= DEFAULT_SUS_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(m, file, files); + if (seq_has_overflowed(m)) +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index d92d1ee75930..e6375add2553 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -20,6 +20,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++#include ++#endif + + #include + #include +@@ -318,6 +321,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) + { +@@ -332,8 +339,17 @@ 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_KSTAT ++ if (unlikely(inode->i_state & INODE_STATE_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; + } + +diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c +index eafb75755fa3..91beb33e4fa7 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_is_current_ksu_domain(void); ++#endif ++ + static __poll_t mounts_poll(struct file *file, poll_table *wait) + { + struct seq_file *m = file->private_data; +@@ -103,6 +110,11 @@ 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 (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) ++ return 0; ++#endif ++ + if (sb->s_op->show_devname) { + err = sb->s_op->show_devname(m, mnt_path.dentry); + if (err) +@@ -137,6 +149,10 @@ 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 (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) ++ 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) { +@@ -199,6 +215,11 @@ 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 (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) ++ return 0; ++#endif ++ + /* device */ + if (sb->s_op->show_devname) { + seq_puts(m, "device "); +diff --git a/fs/readdir.c b/fs/readdir.c +index 09e8ed7d4161..6d27edfeae1c 100644 +--- a/fs/readdir.c ++++ b/fs/readdir.c +@@ -21,6 +21,9 @@ + #include + #include + #include ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++#include ++#endif + + #include + +@@ -36,6 +39,9 @@ + unsafe_copy_to_user(dst, src, len, label); \ + } while (0) + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++extern int susfs_sus_ino_for_filldir64(unsigned long ino); ++#endif + + int iterate_dir(struct file *file, struct dir_context *ctx) + { +@@ -230,6 +236,11 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, + sizeof(long)); + int prev_reclen; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && susfs_sus_ino_for_filldir64(ino)) { ++ return 0; ++ } ++#endif + buf->error = verify_dirent_name(name, namlen); + if (unlikely(buf->error)) + return buf->error; +@@ -317,6 +328,11 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, + sizeof(u64)); + int prev_reclen; + ++#ifdef CONFIG_KSU_SUSFS_SUS_PATH ++ if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && susfs_sus_ino_for_filldir64(ino)) { ++ return 0; ++ } ++#endif + buf->error = verify_dirent_name(name, namlen); + if (unlikely(buf->error)) + return buf->error; +diff --git a/fs/stat.c b/fs/stat.c +index c6a2e10983f8..f1529c90442d 100644 +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -17,6 +17,9 @@ + #include + #include + #include ++#if defined(CONFIG_KSU_SUSFS_SUS_KSTAT) || defined(CONFIG_KSU_SUSFS_SUS_MOUNT) ++#include ++#endif + + #include + #include +@@ -24,6 +27,10 @@ + #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 + * @inode: Inode to use as the source +@@ -35,6 +42,17 @@ + */ + void generic_fillattr(struct inode *inode, struct kstat *stat) + { ++#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT ++ if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && ++ unlikely(inode->i_state & INODE_STATE_SUS_KSTAT)) { ++ susfs_sus_ino_for_generic_fillattr(inode->i_ino, stat); ++ stat->mode = inode->i_mode; ++ stat->rdev = inode->i_rdev; ++ stat->uid = inode->i_uid; ++ stat->gid = inode->i_gid; ++ return; ++ } ++#endif + stat->dev = inode->i_sb->s_dev; + stat->ino = inode->i_ino; + stat->mode = inode->i_mode; +@@ -171,12 +189,27 @@ int vfs_fstat(int fd, struct kstat *stat) + * + * 0 will be returned on success, and a -ve error code if unsuccessful. + */ ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++extern bool susfs_is_sus_su_hooks_enabled __read_mostly; ++extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); ++#endif ++ + static int vfs_statx(int dfd, const char __user *filename, int flags, + struct kstat *stat, u32 request_mask) + { + struct path path; + unsigned lookup_flags = 0; + int error; ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ struct mount *mnt; ++#endif ++ ++#ifdef CONFIG_KSU_SUSFS_SUS_SU ++ if (susfs_is_sus_su_hooks_enabled) { ++ ksu_handle_stat(&dfd, &filename, &flags); ++ } ++#endif + + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | + AT_STATX_SYNC_TYPE)) +@@ -195,7 +228,15 @@ static int vfs_statx(int dfd, const char __user *filename, int flags, + goto out; + + error = vfs_getattr(&path, stat, request_mask, flags); ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ mnt = real_mount(path.mnt); ++ if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ for (; mnt->mnt_id >= DEFAULT_SUS_MNT_ID; mnt = mnt->mnt_parent) {} ++ } ++ stat->mnt_id = mnt->mnt_id; ++#else + stat->mnt_id = real_mount(path.mnt)->mnt_id; ++#endif + stat->result_mask |= STATX_MNT_ID; + if (path.mnt->mnt_root == path.dentry) + stat->attributes |= STATX_ATTR_MOUNT_ROOT; +diff --git a/fs/statfs.c b/fs/statfs.c +index d42b44dc0e49..2abb6b67f011 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(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { ++ for (; mnt->mnt_id >= DEFAULT_SUS_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(vfs_statfs); + +@@ -109,6 +125,22 @@ int user_statfs(const char __user *pathname, struct kstatfs *st) + goto retry; + } + } ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ /* - When mounting overlay, the f_flags are set with 'ro' and 'relatime', ++ * but this is an abnormal status, as when we inspect the output from mountinfo, ++ * we will find that all partitions set with 'ro' will have 'noatime' set as well. ++ * - But what is strange here is that the vfsmnt f_flags of the lowest layer has corrent f_flags set, ++ * and still it is always changed to 'relatime' instead of 'noatime' for the final result, ++ * I can't think of any other reason to explain about this, maybe the f_flags is set by its own ++ * filesystem implementation but not the one from overlayfs. ++ * - Anyway we just cannot use the retrieved f_flags from ovl_getattr() of overlayfs, ++ * we need to run one more check for user_statfs() and fd_statfs() by ourselves. ++ */ ++ if (unlikely((st->f_flags & ST_RDONLY) && (st->f_flags & ST_RELATIME))) { ++ st->f_flags &= ~ST_RELATIME; ++ st->f_flags |= ST_NOATIME; ++ } ++#endif + return error; + } + +@@ -120,6 +152,12 @@ int fd_statfs(int fd, struct kstatfs *st) + error = vfs_statfs(&f.file->f_path, st); + fdput(f); + } ++#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ++ if (unlikely((st->f_flags & ST_RDONLY) && (st->f_flags & ST_RELATIME))) { ++ st->f_flags &= ~ST_RELATIME; ++ st->f_flags |= ST_NOATIME; ++ } ++#endif + return error; + } + +@@ -240,6 +278,11 @@ static int vfs_ustat(dev_t dev, struct kstatfs *sbuf) + if (!s) + return -EINVAL; + ++#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT ++ if (unlikely(s->s_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) { ++ return -EINVAL; ++ } ++#endif + err = statfs_by_dentry(s->s_root, sbuf); + drop_super(s); + return err; +diff --git a/include/linux/mount.h b/include/linux/mount.h +index 2f64e66f9c8c..591bca2a690b 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; + + struct file; /* forward dec */ +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 331ec7988028..3a32047b2095 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1383,8 +1383,16 @@ struct task_struct { + ANDROID_KABI_RESERVE(4); + ANDROID_KABI_RESERVE(5); + ANDROID_KABI_RESERVE(6); ++#ifdef CONFIG_KSU_SUSFS ++ ANDROID_KABI_USE(7, u64 susfs_task_state); ++#else + ANDROID_KABI_RESERVE(7); ++#endif ++#ifdef CONFIG_KSU_SUSFS ++ ANDROID_KABI_USE(8, u64 susfs_last_fake_mnt_id); ++#else + ANDROID_KABI_RESERVE(8); ++#endif + + /* + * New fields for task_struct should be added above here, so that +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 96505113b907..de70a3b01324 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -692,8 +692,18 @@ 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 (strstr(iter->name, "ksu_") || !strncmp(iter->name, "susfs_", 6) || !strncmp(iter->name, "ksud", 4)) { ++ return 0; ++ } ++ seq_printf(m, "%px %c %s\n", value, ++ iter->type, iter->name); ++ } ++#endif + return 0; + } + +diff --git a/kernel/sys.c b/kernel/sys.c +index 1de01fab5788..bd2220acc6f5 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1271,12 +1271,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/fs/Makefile b/fs/Makefile index 499ce7d8a..4bef27f35 100755 --- a/fs/Makefile +++ b/fs/Makefile @@ -21,6 +21,9 @@ obj-y := open.o read_write.o file_table.o super.o \ obj-$(CONFIG_KSU_SUSFS) += susfs.o obj-$(CONFIG_KSU_SUSFS_SUS_SU) += sus_su.o +obj-$(CONFIG_KSU_SUSFS) += susfs.o +obj-$(CONFIG_KSU_SUSFS_SUS_SU) += sus_su.o + ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o else diff --git a/fs/dcache.c b/fs/dcache.c index 4c1065e69..3ae620fc1 100755 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2410,6 +2410,12 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) if (dentry->d_name.hash != hash) continue; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + continue; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_PATH if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { continue; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c6fabad8e..74f33bf9b 100755 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -601,6 +601,11 @@ extern bool ksu_devpts_hook; extern int ksu_handle_devpts(struct inode*); #endif +#if defined(CONFIG_KSU_SUSFS_SUS_SU) +extern bool ksu_devpts_hook; +extern int ksu_handle_devpts(struct inode*); +#endif + /** * devpts_get_priv -- get private data for a slave * @pts_inode: inode of the slave diff --git a/fs/exec.c b/fs/exec.c index 22d2ed577..59f2d6866 100755 --- a/fs/exec.c +++ b/fs/exec.c @@ -1882,6 +1882,12 @@ extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, void *envp, int *flags); #endif +#ifdef CONFIG_KSU_SUSFS_SUS_SU +extern bool susfs_is_sus_su_hooks_enabled __read_mostly; +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, @@ -1893,6 +1899,11 @@ static int do_execveat_common(int fd, struct filename *filename, if (IS_ERR(filename)) return PTR_ERR(filename); +#ifdef CONFIG_KSU_SUSFS_SUS_SU + if (susfs_is_sus_su_hooks_enabled) + ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_SU if (susfs_is_sus_su_hooks_enabled) ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); diff --git a/fs/namei.c b/fs/namei.c index b0a4d7cc6..d5ffab76a 100755 --- a/fs/namei.c +++ b/fs/namei.c @@ -39,6 +39,9 @@ #include #include #include +#if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT) +#include +#endif #if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT) #include @@ -1136,6 +1139,12 @@ int may_linkat(struct path *link) { struct inode *inode = link->dentry->d_inode; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (inode && unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + return -ENOENT; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_PATH if (inode && unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { return -ENOENT; @@ -1561,6 +1570,19 @@ static struct dentry *lookup_dcache(const struct qstr *name, return ERR_PTR(error); } } +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + if ((flags & (LOOKUP_CREATE | LOOKUP_EXCL))) { + error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + if (error) { + dput(dentry); + return ERR_PTR(error); + } + } + dput(dentry); + return ERR_PTR(-ENOENT); + } +#endif return dentry; } @@ -1673,6 +1695,12 @@ static struct dentry *lookup_fast(struct nameidata *nd, dput(dentry); return ERR_PTR(status); } +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + dput(dentry); + return ERR_PTR(-ENOENT); + } +#endif return dentry; } @@ -2470,6 +2498,12 @@ static const char *path_init(struct nameidata *nd, unsigned flags) path_get(&nd->root); nd->flags |= LOOKUP_ROOT_GRABBED; } +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + // we deal with sus sub path here + if (nd->inode && unlikely(nd->inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + return 0; + } +#endif } return s; } @@ -2881,6 +2915,12 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) if (IS_APPEND(dir)) return -EPERM; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + return -ENOENT; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_PATH if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { return -ENOENT; @@ -3094,6 +3134,12 @@ static int may_open(const struct path *path, int acc_mode, int flag) if (!inode) return -ENOENT; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + return -ENOENT; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_PATH if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { return -ENOENT; diff --git a/fs/namespace.c b/fs/namespace.c index 44f776c64..7a3824e22 100755 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -190,6 +190,18 @@ static inline struct hlist_head *mp_hash(struct dentry *dentry) return &mountpoint_hashtable[tmp & mp_hash_mask]; } +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +// Our own mnt_alloc_id() that assigns mnt_id starting from DEFAULT_SUS_MNT_ID +static int susfs_mnt_alloc_id(struct mount *mnt) +{ + int res = ida_alloc_min(&susfs_mnt_id_ida, DEFAULT_SUS_MNT_ID, GFP_KERNEL); + + if (res < 0) + return res; + mnt->mnt_id = res; + return 0; +} +#endif static int mnt_alloc_id(struct mount *mnt) { int res = ida_alloc(&mnt_id_ida, GFP_KERNEL); @@ -226,7 +238,20 @@ static void susfs_mnt_alloc_group_id(struct mount *mnt) */ static int mnt_alloc_group_id(struct mount *mnt) { +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + int res; + + // Check if mnt has sus mnt_id + if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { + // If so, assign a sus mnt_group id DEFAULT_SUS_MNT_GROUP_ID from susfs_mnt_group_ida + res = ida_alloc_min(&susfs_mnt_group_ida, DEFAULT_SUS_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; @@ -284,13 +309,31 @@ int mnt_get_count(struct mount *mnt) #endif } +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +static struct mount *alloc_vfsmnt(const char *name, bool should_spoof, int custom_mnt_id) +#else static struct mount *alloc_vfsmnt(const char *name) +#endif { struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { int err; +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + if (should_spoof) { + if (!custom_mnt_id) { + err = susfs_mnt_alloc_id(mnt); + } else { + mnt->mnt_id = custom_mnt_id; + err = 0; + } + goto bypass_orig_flow; + } +#endif err = mnt_alloc_id(mnt); +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +bypass_orig_flow: +#endif if (err) goto out_free_cache; #ifdef CONFIG_KDP_NS @@ -1121,7 +1164,17 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) if (!fc->root) return ERR_PTR(-EINVAL); +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + // For newly created mounts, the only caller process we care is KSU + if (unlikely(susfs_is_current_ksu_domain())) { + mnt = alloc_vfsmnt(fc->source ?: "none", true, 0); + goto bypass_orig_flow; + } + mnt = alloc_vfsmnt(fc->source ?: "none", false, 0); +bypass_orig_flow: +#else mnt = alloc_vfsmnt(fc->source ?: "none"); +#endif if (!mnt) return ERR_PTR(-ENOMEM); @@ -1150,6 +1203,13 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) } #endif +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + // If caller process is zygote, then it is a normal mount, so we just reorder the mnt_id + if (susfs_is_current_zygote_domain()) { + mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id; + mnt->mnt_id = current->susfs_last_fake_mnt_id++; + } +#endif lock_mount_hash(); #ifdef CONFIG_KDP_NS list_add_tail(&mnt->mnt_instance, &((struct kdp_mount *)mnt)->mnt->mnt_sb->s_mounts); @@ -1232,8 +1292,52 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, #endif struct mount *mnt; int err; +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + bool is_current_ksu_domain = susfs_is_current_ksu_domain(); + bool is_current_zygote_domain = susfs_is_current_zygote_domain(); + /* - It is very important that we need to use CL_COPY_MNT_NS to identify whether + * the clone is a copy_tree() or single mount like called by __do_loopback() + * - if caller process is KSU, consider the following situation: + * 1. it is NOT doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id + * 2. it is doing unshare => spoof the new mnt_id with the old mnt_id + * - If caller process is zygote and old mnt_id is sus => call alloc_vfsmnt() to assign a new sus mnt_id + * - For the rest of caller process that doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id only for old sus mount + */ + // Firstly, check if it is KSU process + if (unlikely(is_current_ksu_domain)) { + // if it is doing single clone + if (!(flag & CL_COPY_MNT_NS)) { + mnt = alloc_vfsmnt(old->mnt_devname, true, 0); + goto bypass_orig_flow; + } + // if it is doing unshare + mnt = alloc_vfsmnt(old->mnt_devname, true, old->mnt_id); + if (mnt) { + mnt->mnt.susfs_mnt_id_backup = DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE; + } + goto bypass_orig_flow; + } + // Secondly, check if it is zygote process and no matter it is doing unshare or not + if (likely(is_current_zygote_domain) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) { + /* Important Note: + * - Here we can't determine whether the unshare is called zygisk or not, + * so we can only patch out the unshare code in zygisk source code for now + * - But at least we can deal with old sus mounts using alloc_vfsmnt() + */ + mnt = alloc_vfsmnt(old->mnt_devname, true, 0); + goto bypass_orig_flow; + } + // Lastly, for other process that is doing unshare operation, but only deal with old sus mount + if ((flag & CL_COPY_MNT_NS) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) { + mnt = alloc_vfsmnt(old->mnt_devname, true, 0); + goto bypass_orig_flow; + } + mnt = alloc_vfsmnt(old->mnt_devname, false, 0); +bypass_orig_flow: +#else mnt = alloc_vfsmnt(old->mnt_devname); +#endif if (!mnt) return ERR_PTR(-ENOMEM); @@ -2610,6 +2714,29 @@ retry: } return mp; } +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + // current->susfs_last_fake_mnt_id -> to record last valid fake mnt_id to zygote pid + // q->mnt.susfs_mnt_id_backup -> original mnt_id + // q->mnt_id -> will be modified to the fake mnt_id + + // Here We are only interested in processes of which original mnt namespace belongs to zygote + // Also we just make use of existing 'q' mount pointer, no need to delcare extra mount pointer + if (is_zygote_pid) { + last_entry_mnt_id = list_first_entry(&new_ns->list, struct mount, mnt_list)->mnt_id; + list_for_each_entry(q, &new_ns->list, mnt_list) { + if (unlikely(q->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) { + continue; + } + q->mnt.susfs_mnt_id_backup = q->mnt_id; + q->mnt_id = last_entry_mnt_id++; + } + } + // Assign the 'last_entry_mnt_id' to 'current->susfs_last_fake_mnt_id' for later use. + // should be fine here assuming zygote is forking/unsharing app in one single thread. + // Or should we put a lock here? + current->susfs_last_fake_mnt_id = last_entry_mnt_id; +#endif + namespace_unlock(); inode_unlock(path->dentry->d_inode); path_put(path); @@ -3986,6 +4113,13 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, } #endif +#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT) && defined(CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT) + // Just for the compatibility of Magic Mount KernelSU + if (!ret && susfs_is_auto_add_sus_ksu_default_mount_enabled && susfs_is_current_ksu_domain()) { + susfs_auto_add_sus_ksu_default_mount(dir_name); + } +#endif + kfree(options); out_data: kfree(kernel_dev); diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 55081ae3a..ad66bd89d 100755 --- 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" @@ -73,7 +76,11 @@ 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; @@ -84,6 +91,36 @@ 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 + if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && + unlikely(inode->i_state & INODE_STATE_SUS_KSTAT)) { + 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 157aac135..8ae084f93 100755 --- a/fs/open.c +++ b/fs/open.c @@ -401,6 +401,12 @@ extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int int *flags); #endif +#ifdef CONFIG_KSU_SUSFS_SUS_SU +extern bool susfs_is_sus_su_hooks_enabled __read_mostly; +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; @@ -409,6 +415,12 @@ 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_SUS_SU + if (susfs_is_sus_su_hooks_enabled) { + ksu_handle_faccessat(&dfd, &filename, &mode, NULL); + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_SU if (susfs_is_sus_su_hooks_enabled) { ksu_handle_faccessat(&dfd, &filename, &mode, NULL); diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index f784def63..178c0f7a2 100755 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -168,6 +168,15 @@ int ovl_getattr(const struct path *path, struct kstat *stat, metacopy_blocks = ovl_is_metacopy_dentry(dentry); +#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS + ovl_path_lowerdata(dentry, &realpath); + if (likely(realpath.mnt && realpath.dentry)) { + old_cred = ovl_override_creds(dentry->d_sb); + err = vfs_getattr(&realpath, stat, request_mask, flags); + goto out; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ovl_path_lowerdata(dentry, &realpath); if (likely(realpath.mnt && realpath.dentry)) { diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index e099f64ea..6d85e4186 100755 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -327,6 +327,18 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) struct path path; int err; +#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS + ovl_path_lowerdata(root_dentry, &path); + if (likely(path.mnt && path.dentry)) { + err = vfs_statfs(&path, buf); + if (!err) { + buf->f_namelen = 255; // 255 for erofs, ext2/4, f2fs + buf->f_type = path.dentry->d_sb->s_magic; + } + return err; + } +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS ovl_path_lowerdata(root_dentry, &path); if (likely(path.mnt && path.dentry)) { diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 35b92009c..90c27120f 100755 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -13,6 +13,9 @@ #include #include +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT +#include +#endif #include "../mount.h" #include "internal.h" @@ -24,6 +27,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) @@ -54,10 +60,48 @@ 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(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && + mnt->mnt_id >= DEFAULT_SUS_MNT_ID) { + struct path path; + char *pathname = kmalloc(PAGE_SIZE, GFP_KERNEL); + char *dpath; + + for (; mnt->mnt_id >= DEFAULT_SUS_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); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 416711ea1..1d310dfa7 100755 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -324,6 +324,10 @@ static void show_vma_header_prefix(struct seq_file *m, extern void susfs_sus_ino_for_show_map_vma(unsigned long ino, dev_t *out_dev, unsigned long *out_ino); #endif +#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) { diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 91beb33e4..72c4b074a 100755 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -110,6 +110,11 @@ 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 (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) + return 0; +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT if (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) return 0; @@ -215,6 +220,11 @@ 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 (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) + return 0; +#endif + #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT if (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain())) return 0; diff --git a/fs/readdir.c b/fs/readdir.c index 6d27edfea..df2bc8cc6 100755 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -498,6 +498,11 @@ static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, namlen + 2, sizeof(compat_long_t)); int prev_reclen; +#ifdef CONFIG_KSU_SUSFS_SUS_PATH + if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && susfs_sus_ino_for_filldir64(ino)) { + return 0; + } +#endif buf->error = verify_dirent_name(name, namlen); if (unlikely(buf->error)) return buf->error; diff --git a/fs/stat.c b/fs/stat.c index 6d5acc73e..d22e63fa3 100755 --- a/fs/stat.c +++ b/fs/stat.c @@ -31,6 +31,10 @@ extern void susfs_sus_ino_for_generic_fillattr(unsigned long ino, struct kstat *stat); #endif +#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 * @inode: Inode to use as the source @@ -224,7 +228,15 @@ retry: goto out; error = vfs_getattr(&path, stat, request_mask, flags); +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + mnt = real_mount(path.mnt); + if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + for (; mnt->mnt_id >= DEFAULT_SUS_MNT_ID; mnt = mnt->mnt_parent) {} + } + stat->mnt_id = mnt->mnt_id; +#else stat->mnt_id = real_mount(path.mnt)->mnt_id; +#endif stat->result_mask |= STATX_MNT_ID; if (path.mnt->mnt_root == path.dentry) stat->attributes |= STATX_ATTR_MOUNT_ROOT; diff --git a/fs/statfs.c b/fs/statfs.c index 553f995a0..2abb6b67f 100755 --- 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(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) { + for (; mnt->mnt_id >= DEFAULT_SUS_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(vfs_statfs); @@ -262,6 +278,11 @@ static int vfs_ustat(dev_t dev, struct kstatfs *sbuf) if (!s) return -EINVAL; +#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT + if (unlikely(s->s_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) { + return -EINVAL; + } +#endif err = statfs_by_dentry(s->s_root, sbuf); drop_super(s); return err;