Files
los-kernel-dodge-sukisu-susfs/50_add_susfs_in_gki-android15-6.6.patch

2289 lines
68 KiB
Diff

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 <linux/parser.h>
#include <linux/fsnotify.h>
#include <linux/seq_file.h>
+#ifdef CONFIG_KSU_SUSFS
+#include <linux/susfs_def.h>
+#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 <linux/time_namespace.h>
#include <linux/user_events.h>
#include <linux/page_size_compat.h>
+#ifdef CONFIG_KSU_SUSFS
+#include <linux/susfs_def.h>
+#endif
#include <linux/uaccess.h>
#include <asm/mmu_context.h>
@@ -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 <linux/bitops.h>
#include <linux/init_task.h>
#include <linux/uaccess.h>
+#if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT)
+#include <linux/susfs_def.h>
+#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 <linux/fs_context.h>
#include <linux/shmem_fs.h>
#include <linux/mnt_idmapping.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+#include <linux/susfs_def.h>
+#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
#include "pnode.h"
#include "internal.h"
#include <trace/hooks/blk.h>
#include <trace/hooks/fs.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+extern bool susfs_is_current_ksu_domain(void);
+extern bool susfs_is_boot_completed_triggered;
+
+static DEFINE_IDA(susfs_ksu_mnt_group_ida);
+static atomic64_t susfs_ksu_mounts = ATOMIC64_INIT(0);
+
+#define CL_COPY_MNT_NS BIT(25) /* used by copy_mnt_ns() */
+#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+
/* Maximum number of mounts in a mount namespace */
static unsigned int sysctl_mount_max __read_mostly = 100000;
@@ -138,6 +151,20 @@ static int mnt_alloc_id(struct mount *mnt)
static void mnt_free_id(struct mount *mnt)
{
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ // First we have to check if susfs_mnt_id_backup == DEFAULT_KSU_MNT_ID,
+ // if so, no need to free.
+ if (mnt->mnt.susfs_mnt_id_backup == DEFAULT_KSU_MNT_ID) {
+ return;
+ }
+
+ // Second if susfs_mnt_id_backup was set after mnt_id reorder, free it if so.
+ if (likely(mnt->mnt.susfs_mnt_id_backup)) {
+ ida_free(&mnt_id_ida, mnt->mnt.susfs_mnt_id_backup);
+ return;
+ }
+
+#endif
ida_free(&mnt_id_ida, mnt->mnt_id);
}
@@ -146,7 +173,23 @@ static void mnt_free_id(struct mount *mnt)
*/
static int mnt_alloc_group_id(struct mount *mnt)
{
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ int res;
+
+ /* - At frist susfs_is_boot_completed_triggered is set to false in kernel,
+ * and it is still allowed to assign our custom mnt_group_id via susfs_ksu_mnt_group_ida
+ * if it is ksu mounts, until susfs_is_boot_completed_triggered is set to true
+ * when boot-completed stage is triggered in core_hook.c
+ */
+ if (!susfs_is_boot_completed_triggered && mnt->mnt_id >= DEFAULT_KSU_MNT_ID) {
+ res = ida_alloc_min(&susfs_ksu_mnt_group_ida, DEFAULT_KSU_MNT_GROUP_ID, GFP_KERNEL);
+ goto bypass_orig_flow;
+ }
+ res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL);
+bypass_orig_flow:
+#else
int res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL);
+#endif
if (res < 0)
return res;
@@ -159,6 +202,22 @@ static int mnt_alloc_group_id(struct mount *mnt)
*/
void mnt_release_group_id(struct mount *mnt)
{
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ /* - when boot-completed stage is triggered in core_hook.c,
+ * susfs_is_boot_completed_triggered will be set to true.
+ * - Please note that if susfs_is_boot_completed_triggered is true, then
+ * it no longer checks for the sus mnt_group_id, and the allocated
+ * sus mnt_group_id will stay in kernel memory forever, and if user
+ * suddenly umounts the sus mount in global mnt namespace, the ida_free()
+ * function will throw error to kernel log, but it won't affect the system,
+ * so it is fine.
+ */
+ if (!susfs_is_boot_completed_triggered && mnt->mnt_group_id >= DEFAULT_KSU_MNT_GROUP_ID) {
+ ida_free(&susfs_ksu_mnt_group_ida, mnt->mnt_group_id);
+ mnt->mnt_group_id = 0;
+ return;
+ }
+#endif
ida_free(&mnt_group_ida, mnt->mnt_group_id);
mnt->mnt_group_id = 0;
}
@@ -196,6 +255,112 @@ int mnt_get_count(struct mount *mnt)
#endif
}
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+/* A copy of alloc_vfsmnt() but reuse the original mnt_id to mnt */
+static struct mount *susfs_reuse_sus_vfsmnt(const char *name, int orig_mnt_id)
+{
+ struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
+ if (mnt) {
+ mnt->mnt_id = orig_mnt_id;
+
+ if (name) {
+ mnt->mnt_devname = kstrdup_const(name,
+ GFP_KERNEL_ACCOUNT);
+ if (!mnt->mnt_devname)
+ goto out_free_cache;
+ }
+
+#ifdef CONFIG_SMP
+ mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
+ if (!mnt->mnt_pcp)
+ goto out_free_devname;
+
+ this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
+#else
+ mnt->mnt_count = 1;
+ mnt->mnt_writers = 0;
+#endif
+ // Makes ida_free() easier to determine whether it should free the mnt_id or not
+ mnt->mnt.susfs_mnt_id_backup = DEFAULT_KSU_MNT_ID;
+
+ INIT_HLIST_NODE(&mnt->mnt_hash);
+ INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_mounts);
+ INIT_LIST_HEAD(&mnt->mnt_list);
+ INIT_LIST_HEAD(&mnt->mnt_expire);
+ INIT_LIST_HEAD(&mnt->mnt_share);
+ INIT_LIST_HEAD(&mnt->mnt_slave_list);
+ INIT_LIST_HEAD(&mnt->mnt_slave);
+ INIT_HLIST_NODE(&mnt->mnt_mp_list);
+ INIT_LIST_HEAD(&mnt->mnt_umounting);
+ INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
+ mnt->mnt.mnt_idmap = &nop_mnt_idmap;
+ }
+ return mnt;
+
+#ifdef CONFIG_SMP
+out_free_devname:
+ kfree_const(mnt->mnt_devname);
+#endif
+out_free_cache:
+ kmem_cache_free(mnt_cache, mnt);
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+/* A copy of alloc_vfsmnt() but allocates the fake mnt_id to mnt */
+static struct mount *susfs_alloc_sus_vfsmnt(const char *name)
+{
+ struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
+ if (mnt) {
+ mnt->mnt_id = DEFAULT_KSU_MNT_ID;
+
+ if (name) {
+ mnt->mnt_devname = kstrdup_const(name,
+ GFP_KERNEL_ACCOUNT);
+ if (!mnt->mnt_devname)
+ goto out_free_cache;
+ }
+
+#ifdef CONFIG_SMP
+ mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
+ if (!mnt->mnt_pcp)
+ goto out_free_devname;
+
+ this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
+#else
+ mnt->mnt_count = 1;
+ mnt->mnt_writers = 0;
+#endif
+ // Makes ida_free() easier to determine whether it should free the mnt_id or not
+ mnt->mnt.susfs_mnt_id_backup = DEFAULT_KSU_MNT_ID;
+
+ INIT_HLIST_NODE(&mnt->mnt_hash);
+ INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_mounts);
+ INIT_LIST_HEAD(&mnt->mnt_list);
+ INIT_LIST_HEAD(&mnt->mnt_expire);
+ INIT_LIST_HEAD(&mnt->mnt_share);
+ INIT_LIST_HEAD(&mnt->mnt_slave_list);
+ INIT_LIST_HEAD(&mnt->mnt_slave);
+ INIT_HLIST_NODE(&mnt->mnt_mp_list);
+ INIT_LIST_HEAD(&mnt->mnt_umounting);
+ INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
+ mnt->mnt.mnt_idmap = &nop_mnt_idmap;
+ }
+ return mnt;
+
+#ifdef CONFIG_SMP
+out_free_devname:
+ kfree_const(mnt->mnt_devname);
+#endif
+out_free_cache:
+ kmem_cache_free(mnt_cache, mnt);
+ return NULL;
+}
+#endif
+
static struct mount *alloc_vfsmnt(const char *name)
{
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
@@ -223,6 +388,10 @@ static struct mount *alloc_vfsmnt(const char *name)
mnt->mnt_count = 1;
mnt->mnt_writers = 0;
#endif
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ // Make sure mnt->mnt.susfs_mnt_id_backup is initialized every time.
+ mnt->mnt.susfs_mnt_id_backup = 0;
+#endif
INIT_HLIST_NODE(&mnt->mnt_hash);
INIT_LIST_HEAD(&mnt->mnt_child);
@@ -1085,7 +1254,19 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc)
if (!fc->root)
return ERR_PTR(-EINVAL);
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ // We keep checking for ksu process only until boot-completed stage is triggered
+ if (!susfs_is_boot_completed_triggered && susfs_is_current_ksu_domain()) {
+ mnt = susfs_alloc_sus_vfsmnt(fc->source ?: "none");
+ atomic64_add(1, &susfs_ksu_mounts);
+ goto bypass_orig_flow;
+ }
+#endif
+
mnt = alloc_vfsmnt(fc->source ?: "none");
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+bypass_orig_flow:
+#endif
if (!mnt)
return ERR_PTR(-ENOMEM);
@@ -1168,7 +1349,37 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
struct mount *mnt;
int err;
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ // - We do not check anymore for ksu process if boot-completed stage is triggered
+ // just to stop the performance loss
+ if (susfs_is_boot_completed_triggered) {
+ goto skip_checking_for_ksu_proc;
+ }
+
+ // First we must check for ksu process because of magic mount
+ if (susfs_is_current_ksu_domain()) {
+ // if it is unsharing, we reuse the old->mnt_id
+ if (flag & CL_COPY_MNT_NS) {
+ mnt = susfs_reuse_sus_vfsmnt(old->mnt_devname, old->mnt_id);
+ goto bypass_orig_flow;
+ }
+ // else we just go assign fake mnt_id
+ mnt = susfs_alloc_sus_vfsmnt(old->mnt_devname);
+ goto bypass_orig_flow;
+ }
+
+skip_checking_for_ksu_proc:
+ // Lastly for other processes of which old->mnt_id == DEFAULT_KSU_MNT_ID, go assign fake mnt_id
+ if (old->mnt_id == DEFAULT_KSU_MNT_ID) {
+ mnt = susfs_alloc_sus_vfsmnt(old->mnt_devname);
+ goto bypass_orig_flow;
+ }
+#endif
+
mnt = alloc_vfsmnt(old->mnt_devname);
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+bypass_orig_flow:
+#endif
if (!mnt)
return ERR_PTR(-ENOMEM);
@@ -3805,6 +4016,9 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
if (user_ns != ns->user_ns)
copy_flags |= CL_SHARED_TO_SLAVE;
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ copy_flags |= CL_COPY_MNT_NS;
+#endif
new = copy_tree(old, old->mnt.mnt_root, copy_flags);
if (IS_ERR(new)) {
namespace_unlock();
@@ -5060,3 +5274,36 @@ static int __init init_fs_namespace_sysctls(void)
fs_initcall(init_fs_namespace_sysctls);
#endif /* CONFIG_SYSCTL */
+
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+/* Reorder the mnt_id after all sus mounts are umounted during ksu_handle_setuid() */
+void susfs_reorder_mnt_id(void) {
+ struct mnt_namespace *mnt_ns = current->nsproxy->mnt_ns;
+ struct mount *mnt;
+ int first_mnt_id = 0;
+
+ if (!mnt_ns) {
+ return;
+ }
+
+ // Do not reorder the mnt_id if there is no any ksu mount at all
+ if (atomic64_read(&susfs_ksu_mounts) == 0) {
+ return;
+ }
+
+ get_mnt_ns(mnt_ns);
+
+ first_mnt_id = list_first_entry(&mnt_ns->list, struct mount, mnt_list)->mnt_id;
+ list_for_each_entry(mnt, &mnt_ns->list, mnt_list) {
+ // It is very important that we don't reorder the sus mount if it is not umounted
+ if (mnt->mnt_id == DEFAULT_KSU_MNT_ID) {
+ continue;
+ }
+ WRITE_ONCE(mnt->mnt.susfs_mnt_id_backup, READ_ONCE(mnt->mnt_id));
+ WRITE_ONCE(mnt->mnt_id, first_mnt_id++);
+ }
+
+ put_mnt_ns(mnt_ns);
+}
+#endif
+
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 26655572975d..dcd8f4e9035c 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -12,6 +12,9 @@
#include <linux/types.h>
#include <linux/seq_file.h>
#include <linux/exportfs.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+#include <linux/susfs_def.h>
+#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 <linux/compat.h>
#include <linux/mnt_idmapping.h>
#include <linux/filelock.h>
+#ifdef CONFIG_KSU_SUSFS
+#include <linux/susfs_def.h>
+#endif
#include "internal.h"
#include <trace/hooks/syscall_check.h>
@@ -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 <linux/cn_proc.h>
#include <linux/ksm.h>
#include <linux/cpufreq_times.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MAP
+#include <linux/susfs_def.h>
+#endif
#include <trace/events/oom.h>
#include <trace/hooks/sched.h>
#include "internal.h"
@@ -913,6 +916,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
ssize_t copied;
char *page;
unsigned int flags;
+#ifdef CONFIG_KSU_SUSFS_SUS_MAP
+ struct vm_area_struct *vma;
+#endif
if (!mm)
return 0;
@@ -931,6 +937,22 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
while (count > 0) {
size_t this_len = min_t(size_t, count, PAGE_SIZE);
+#ifdef CONFIG_KSU_SUSFS_SUS_MAP
+ vma = find_vma(mm, addr);
+ if (vma && vma->vm_file) {
+ struct inode *inode = file_inode(vma->vm_file);
+ if (unlikely(inode->i_mapping->flags & BIT_SUS_MAPS) && susfs_is_current_proc_umounted()) {
+ if (write) {
+ copied = -EFAULT;
+ } else {
+ copied = -EIO;
+ }
+ *ppos = addr;
+ mmput(mm);
+ goto free;
+ }
+ }
+#endif
if (write && copy_from_user(page, buf, this_len)) {
copied = -EFAULT;
@@ -2465,6 +2487,13 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
for_each_vma(vmi, vma) {
if (!vma->vm_file)
continue;
+#ifdef CONFIG_KSU_SUSFS_SUS_MAP
+ if (unlikely(file_inode(vma->vm_file)->i_mapping->flags & BIT_SUS_MAPS) &&
+ susfs_is_current_proc_umounted())
+ {
+ continue;
+ }
+#endif
if (++pos <= ctx->pos)
continue;
diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c
index 2e244ada1f97..792e1cb04b11 100644
--- a/fs/proc/bootconfig.c
+++ b/fs/proc/bootconfig.c
@@ -12,8 +12,19 @@
static char *saved_boot_config;
+#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
+extern int susfs_spoof_cmdline_or_bootconfig(struct seq_file *m);
+#endif
+
static int boot_config_proc_show(struct seq_file *m, void *v)
{
+#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
+ if (saved_boot_config) {
+ if (!susfs_spoof_cmdline_or_bootconfig(m)) {
+ return 0;
+ }
+ }
+#endif
if (saved_boot_config)
seq_puts(m, saved_boot_config);
return 0;
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 4297287f6ca0..61daf2b3b778 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -15,6 +15,9 @@
#include <linux/filelock.h>
#include <linux/proc_fs.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+#include <linux/susfs_def.h>
+#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 <linux/uaccess.h>
#include <linux/pkeys.h>
#include <trace/hooks/mm.h>
+#if defined(CONFIG_KSU_SUSFS_SUS_KSTAT) || defined(CONFIG_KSU_SUSFS_SUS_MAP)
+#include <linux/susfs_def.h>
+#endif
#include <asm/elf.h>
#include <asm/tlb.h>
@@ -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 <linux/security.h>
#include <linux/fs_struct.h>
#include <linux/sched/task.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+#include <linux/susfs_def.h>
+#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 <asm/unaligned.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_PATH
+#include <linux/susfs_def.h>
+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 <linux/compat.h>
#include <linux/iversion.h>
+#ifdef CONFIG_KSU_SUSFS
+#include <linux/susfs_def.h>
+#include <linux/version.h>
+#endif
#include <linux/uaccess.h>
#include <asm/unistd.h>
#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 <linux/security.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+#include <linux/susfs_def.h>
+#include "mount.h"
+#endif
#include "internal.h"
static int flags_by_mnt(int mnt_flags)
@@ -86,11 +90,23 @@ EXPORT_SYMBOL(vfs_get_fsid);
int vfs_statfs(const struct path *path, struct kstatfs *buf)
{
int error;
+#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
+ struct mount *mnt;
+ mnt = real_mount(path->mnt);
+ if (likely(susfs_is_current_proc_umounted())) {
+ for (; mnt->mnt_id >= DEFAULT_KSU_MNT_ID; mnt = mnt->mnt_parent) {}
+ }
+ error = statfs_by_dentry(mnt->mnt.mnt_root, buf);
+ if (!error)
+ buf->f_flags = calculate_f_flags(&mnt->mnt);
+ return error;
+#else
error = statfs_by_dentry(path->dentry, buf);
if (!error)
buf->f_flags = calculate_f_flags(path->mnt);
return error;
+#endif
}
EXPORT_SYMBOL_NS(vfs_statfs, ANDROID_GKI_VFS_EXPORT_ONLY);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 4e1f330f101c..c2386e5a5458 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -77,7 +77,11 @@ struct vfsmount {
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
+#ifdef CONFIG_KSU_SUSFS
+ ANDROID_KABI_USE(4, u64 susfs_mnt_id_backup);
+#else
ANDROID_KABI_RESERVE(4);
+#endif
} __randomize_layout;
static inline struct mnt_idmap *mnt_idmap(const struct vfsmount *mnt)
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 18edd57b5fe8..5719b0ca344d 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -776,6 +776,10 @@ static void s_stop(struct seq_file *m, void *p)
{
}
+#ifdef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS
+extern bool susfs_starts_with(const char *str, const char *prefix);
+#endif
+
static int s_show(struct seq_file *m, void *p)
{
void *value;
@@ -799,8 +803,36 @@ static int s_show(struct seq_file *m, void *p)
seq_printf(m, "%px %c %s\t[%s]\n", value,
type, iter->name, iter->module_name);
} else
+#ifndef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS
seq_printf(m, "%px %c %s\n", value,
iter->type, iter->name);
+#else
+ {
+ if (susfs_starts_with(iter->name, "ksu_") ||
+ susfs_starts_with(iter->name, "__ksu_") ||
+ susfs_starts_with(iter->name, "susfs_") ||
+ susfs_starts_with(iter->name, "ksud") ||
+ susfs_starts_with(iter->name, "is_ksu_") ||
+ susfs_starts_with(iter->name, "is_manager_") ||
+ susfs_starts_with(iter->name, "escape_to_") ||
+ susfs_starts_with(iter->name, "setup_selinux") ||
+ susfs_starts_with(iter->name, "track_throne") ||
+ susfs_starts_with(iter->name, "on_post_fs_data") ||
+ susfs_starts_with(iter->name, "try_umount") ||
+ susfs_starts_with(iter->name, "kernelsu") ||
+ susfs_starts_with(iter->name, "__initcall__kmod_kernelsu") ||
+ susfs_starts_with(iter->name, "apply_kernelsu") ||
+ susfs_starts_with(iter->name, "handle_sepolicy") ||
+ susfs_starts_with(iter->name, "getenforce") ||
+ susfs_starts_with(iter->name, "setenforce") ||
+ susfs_starts_with(iter->name, "is_zygote"))
+ {
+ return 0;
+ }
+ seq_printf(m, "%px %c %s\n", value,
+ iter->type, iter->name);
+ }
+#endif
return 0;
}
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 344ceaf5ed13..c2d1a782d5a5 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -693,6 +693,9 @@ EXPORT_SYMBOL_GPL(kernel_power_off);
DEFINE_MUTEX(system_transition_mutex);
+#ifdef CONFIG_KSU_SUSFS
+extern int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg);
+#endif
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
@@ -708,6 +711,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
char buffer[256];
int ret = 0;
+#ifdef CONFIG_KSU_SUSFS
+ ret = ksu_handle_sys_reboot(magic1, magic2, cmd, &arg);
+ if (ret) {
+ goto orig_flow;
+ }
+ return ret;
+orig_flow:
+#endif
+
/* We only trust the superuser with rebooting the system. */
if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
return -EPERM;
diff --git a/kernel/sys.c b/kernel/sys.c
index 74bed736f6a8..0d297c0dc2aa 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -741,8 +741,17 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
return retval;
}
+#ifdef CONFIG_KSU_SUSFS
+extern int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid);
+#endif
+
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
{
+#ifdef CONFIG_KSU_SUSFS
+ if (ksu_handle_setresuid(ruid, euid, suid)) {
+ pr_info("Something wrong with ksu_handle_setresuid()\n");
+ }
+#endif
return __sys_setresuid(ruid, euid, suid);
}
@@ -1305,12 +1314,18 @@ static int override_release(char __user *release, size_t len)
return ret;
}
+#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
+extern void susfs_spoof_uname(struct new_utsname* tmp);
+#endif
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{
struct new_utsname tmp;
down_read(&uts_sem);
memcpy(&tmp, utsname(), sizeof(tmp));
+#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
+ susfs_spoof_uname(&tmp);
+#endif
up_read(&uts_sem);
if (copy_to_user(name, &tmp, sizeof(tmp)))
return -EFAULT;
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 9f44a0f446ec..ef307839a90b 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -47,6 +47,12 @@
#undef CREATE_TRACE_POINTS
#include <trace/hooks/avc.h>
+#ifdef CONFIG_KSU_SUSFS
+extern u32 susfs_ksu_sid;
+extern u32 susfs_priv_app_sid;
+bool susfs_is_avc_log_spoofing_enabled = false;
+#endif
+
struct avc_entry {
u32 ssid;
u32 tsid;
@@ -719,11 +725,22 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
rc = security_sid_to_context(sad->tsid, &tcontext,
&tcontext_len);
+#ifdef CONFIG_KSU_SUSFS
+ if (unlikely(sad->tsid == susfs_ksu_sid && susfs_is_avc_log_spoofing_enabled)) {
+ if (rc)
+ audit_log_format(ab, " tsid=%d", susfs_priv_app_sid);
+ else
+ audit_log_format(ab, " tcontext=%s", "u:r:priv_app:s0:c512,c768");
+ goto bypass_orig_flow;
+ }
+#endif
if (rc)
audit_log_format(ab, " tsid=%d", sad->tsid);
else
audit_log_format(ab, " tcontext=%s", tcontext);
-
+#ifdef CONFIG_KSU_SUSFS
+bypass_orig_flow:
+#endif
tclass = secclass_map[sad->tclass-1].name;
audit_log_format(ab, " tclass=%s", tclass);