2289 lines
68 KiB
Diff
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);
|
|
|