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); @@ -3816,6 +4027,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(); @@ -5071,3 +5285,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 @@ -914,6 +917,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; @@ -932,6 +938,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; @@ -2466,6 +2488,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 @@ -48,6 +48,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; @@ -720,11 +726,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);