susfs4ksu
This commit is contained in:
parent
717afbe056
commit
4311834fdc
25 changed files with 746 additions and 57 deletions
|
@ -13,6 +13,8 @@ obj-y := open.o read_write.o file_table.o super.o \
|
||||||
pnode.o splice.o sync.o utimes.o \
|
pnode.o splice.o sync.o utimes.o \
|
||||||
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
|
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_KSU_SUSFS) += susfs.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_BLOCK),y)
|
ifeq ($(CONFIG_BLOCK),y)
|
||||||
obj-y += buffer.o block_dev.o direct-io.o mpage.o
|
obj-y += buffer.o block_dev.o direct-io.o mpage.o
|
||||||
else
|
else
|
||||||
|
|
14
fs/dcache.c
14
fs/dcache.c
|
@ -39,6 +39,9 @@
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/list_lru.h>
|
#include <linux/list_lru.h>
|
||||||
#include <linux/kasan.h>
|
#include <linux/kasan.h>
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
|
@ -2220,6 +2223,11 @@ seqretry:
|
||||||
continue;
|
continue;
|
||||||
if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
|
if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
*seqp = seq;
|
*seqp = seq;
|
||||||
return dentry;
|
return dentry;
|
||||||
|
@ -2303,6 +2311,12 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
|
||||||
if (dentry->d_name.hash != hash)
|
if (dentry->d_name.hash != hash)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
spin_lock(&dentry->d_lock);
|
spin_lock(&dentry->d_lock);
|
||||||
if (dentry->d_parent != parent)
|
if (dentry->d_parent != parent)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
21
fs/inode.c
21
fs/inode.c
|
@ -23,6 +23,10 @@
|
||||||
|
|
||||||
#include <crypto/fmp.h>
|
#include <crypto/fmp.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
extern bool susfs_is_current_ksu_domain(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inode locking rules:
|
* Inode locking rules:
|
||||||
*
|
*
|
||||||
|
@ -1644,6 +1648,11 @@ int generic_update_time(struct inode *inode, struct timespec *time, int flags)
|
||||||
{
|
{
|
||||||
int iflags = I_DIRTY_TIME;
|
int iflags = I_DIRTY_TIME;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (flags & S_ATIME)
|
if (flags & S_ATIME)
|
||||||
inode->i_atime = *time;
|
inode->i_atime = *time;
|
||||||
if (flags & S_VERSION)
|
if (flags & S_VERSION)
|
||||||
|
@ -1668,6 +1677,12 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
|
||||||
{
|
{
|
||||||
int (*update_time)(struct inode *, struct timespec *, int);
|
int (*update_time)(struct inode *, struct timespec *, int);
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
update_time = inode->i_op->update_time ? inode->i_op->update_time :
|
update_time = inode->i_op->update_time ? inode->i_op->update_time :
|
||||||
generic_update_time;
|
generic_update_time;
|
||||||
|
|
||||||
|
@ -1725,6 +1740,12 @@ void touch_atime(const struct path *path)
|
||||||
struct inode *inode = d_inode(path->dentry);
|
struct inode *inode = d_inode(path->dentry);
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!__atime_needs_update(path, inode, false))
|
if (!__atime_needs_update(path, inode, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
140
fs/namei.c
140
fs/namei.c
|
@ -41,6 +41,9 @@
|
||||||
#ifdef CONFIG_FSCRYPT_SDP
|
#ifdef CONFIG_FSCRYPT_SDP
|
||||||
#include <linux/fscrypto_sdp_name.h>
|
#include <linux/fscrypto_sdp_name.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_SUS_PATH) || defined(CONFIG_KSU_SUSFS_OPEN_REDIRECT)
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
|
|
||||||
|
@ -932,6 +935,12 @@ static inline int may_follow_link(struct nameidata *nd)
|
||||||
const struct inode *parent;
|
const struct inode *parent;
|
||||||
kuid_t puid;
|
kuid_t puid;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (nd->inode && unlikely(nd->inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!sysctl_protected_symlinks)
|
if (!sysctl_protected_symlinks)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1008,6 +1017,12 @@ static int may_linkat(struct path *link)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (link->dentry->d_inode && unlikely(link->dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!sysctl_protected_hardlinks)
|
if (!sysctl_protected_hardlinks)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1047,6 +1062,12 @@ static int may_linkat(struct path *link)
|
||||||
static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid,
|
static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid,
|
||||||
struct inode * const inode)
|
struct inode * const inode)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
|
if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
|
||||||
(!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
|
(!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
|
||||||
likely(!(dir_mode & S_ISVTX)) ||
|
likely(!(dir_mode & S_ISVTX)) ||
|
||||||
|
@ -1581,6 +1602,9 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct dentry *old;
|
struct dentry *old;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
int error;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Don't create child dentry for a dead directory. */
|
/* Don't create child dentry for a dead directory. */
|
||||||
if (unlikely(IS_DEADDIR(dir))) {
|
if (unlikely(IS_DEADDIR(dir))) {
|
||||||
|
@ -1593,6 +1617,19 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = old;
|
dentry = old;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
if ((flags & (LOOKUP_CREATE | LOOKUP_EXCL))) {
|
||||||
|
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||||
|
if (error) {
|
||||||
|
dput(dentry);
|
||||||
|
return ERR_PTR(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dput(dentry);
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return dentry;
|
return dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1741,6 +1778,12 @@ again:
|
||||||
dentry = old;
|
dentry = old;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
dput(dentry);
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
out:
|
out:
|
||||||
inode_unlock_shared(inode);
|
inode_unlock_shared(inode);
|
||||||
return dentry;
|
return dentry;
|
||||||
|
@ -2213,6 +2256,12 @@ OK:
|
||||||
}
|
}
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
// we deal with sus sub path here
|
||||||
|
if (nd->inode && unlikely(nd->inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2392,6 +2441,12 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
||||||
if (likely(!retval))
|
if (likely(!retval))
|
||||||
audit_inode(name, path->dentry, flags & LOOKUP_PARENT);
|
audit_inode(name, path->dentry, flags & LOOKUP_PARENT);
|
||||||
restore_nameidata();
|
restore_nameidata();
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (!retval && path->dentry->d_inode && unlikely(path->dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
putname(name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
putname(name);
|
putname(name);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -2874,6 +2929,12 @@ static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *vi
|
||||||
if (IS_APPEND(dir))
|
if (IS_APPEND(dir))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (check_sticky(dir, inode) || IS_APPEND(inode) ||
|
if (check_sticky(dir, inode) || IS_APPEND(inode) ||
|
||||||
IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode))
|
IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
@ -2902,8 +2963,20 @@ static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *vi
|
||||||
*/
|
*/
|
||||||
static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
|
static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
int error;
|
||||||
|
#endif
|
||||||
struct user_namespace *s_user_ns;
|
struct user_namespace *s_user_ns;
|
||||||
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (child->d_inode && unlikely(child->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (child->d_inode)
|
if (child->d_inode)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
if (IS_DEADDIR(dir))
|
if (IS_DEADDIR(dir))
|
||||||
|
@ -3003,6 +3076,12 @@ static int may_open(struct path *path, int acc_mode, int flag)
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (unlikely(inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (inode->i_mode & S_IFMT) {
|
switch (inode->i_mode & S_IFMT) {
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
return -ELOOP;
|
return -ELOOP;
|
||||||
|
@ -3074,7 +3153,20 @@ static inline int open_to_namei_flags(int flag)
|
||||||
static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode)
|
static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode)
|
||||||
{
|
{
|
||||||
struct user_namespace *s_user_ns;
|
struct user_namespace *s_user_ns;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
error = security_path_mknod(dir, dentry, mode, 0);
|
||||||
|
#else
|
||||||
int error = security_path_mknod(dir, dentry, mode, 0);
|
int error = security_path_mknod(dir, dentry, mode, 0);
|
||||||
|
#endif
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -3221,6 +3313,12 @@ static int lookup_open(struct nameidata *nd, struct path *path,
|
||||||
}
|
}
|
||||||
if (dentry->d_inode) {
|
if (dentry->d_inode) {
|
||||||
/* Cached positive dentry: will open in f_op->open */
|
/* Cached positive dentry: will open in f_op->open */
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
dput(dentry);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
goto out_no_open;
|
goto out_no_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3264,6 +3362,16 @@ static int lookup_open(struct nameidata *nd, struct path *path,
|
||||||
mode, opened);
|
mode, opened);
|
||||||
if (unlikely(error == -ENOENT) && create_error)
|
if (unlikely(error == -ENOENT) && create_error)
|
||||||
error = create_error;
|
error = create_error;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (!IS_ERR(dentry) && dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
if (create_error) {
|
||||||
|
dput(dentry);
|
||||||
|
return create_error;
|
||||||
|
}
|
||||||
|
dput(dentry);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3279,6 +3387,12 @@ no_open:
|
||||||
}
|
}
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = res;
|
dentry = res;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (dentry->d_inode && unlikely(dentry->d_inode->i_state & INODE_STATE_SUS_PATH) && likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC)) {
|
||||||
|
dput(dentry);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3634,12 +3748,19 @@ out2:
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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,
|
struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||||
const struct open_flags *op)
|
const struct open_flags *op)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct nameidata nd;
|
||||||
int flags = op->lookup_flags;
|
int flags = op->lookup_flags;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
|
||||||
|
struct filename *fake_pathname;
|
||||||
|
#endif
|
||||||
|
|
||||||
set_nameidata(&nd, dfd, pathname);
|
set_nameidata(&nd, dfd, pathname);
|
||||||
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|
||||||
|
@ -3647,6 +3768,25 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||||
filp = path_openat(&nd, op, flags);
|
filp = path_openat(&nd, op, flags);
|
||||||
if (unlikely(filp == ERR_PTR(-ESTALE)))
|
if (unlikely(filp == ERR_PTR(-ESTALE)))
|
||||||
filp = path_openat(&nd, op, flags | LOOKUP_REVAL);
|
filp = path_openat(&nd, op, flags | LOOKUP_REVAL);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
|
||||||
|
if (!IS_ERR(filp) && unlikely(filp->f_inode->i_state & INODE_STATE_OPEN_REDIRECT) && current_uid().val < 2000) {
|
||||||
|
fake_pathname = susfs_get_redirected_path(filp->f_inode->i_ino);
|
||||||
|
if (!IS_ERR(fake_pathname)) {
|
||||||
|
restore_nameidata();
|
||||||
|
filp_close(filp, NULL);
|
||||||
|
// no need to do `putname(pathname);` here as it will be done by calling process
|
||||||
|
set_nameidata(&nd, dfd, fake_pathname);
|
||||||
|
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|
||||||
|
if (unlikely(filp == ERR_PTR(-ECHILD)))
|
||||||
|
filp = path_openat(&nd, op, flags);
|
||||||
|
if (unlikely(filp == ERR_PTR(-ESTALE)))
|
||||||
|
filp = path_openat(&nd, op, flags | LOOKUP_REVAL);
|
||||||
|
restore_nameidata();
|
||||||
|
putname(fake_pathname);
|
||||||
|
return filp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
restore_nameidata();
|
restore_nameidata();
|
||||||
return filp;
|
return filp;
|
||||||
}
|
}
|
||||||
|
|
169
fs/namespace.c
169
fs/namespace.c
|
@ -24,11 +24,31 @@
|
||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/task_work.h>
|
#include <linux/task_work.h>
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_SUS_MOUNT) || defined(CONFIG_KSU_SUSFS_TRY_UMOUNT)
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
#include <linux/slub_def.h>
|
#include <linux/slub_def.h>
|
||||||
#include <linux/fslog.h>
|
#include <linux/fslog.h>
|
||||||
#include "pnode.h"
|
#include "pnode.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
extern bool susfs_is_current_ksu_domain(void);
|
||||||
|
extern bool susfs_is_current_zygote_domain(void);
|
||||||
|
#define CL_SUSFS_COPY_MNT_NS 0x1000000
|
||||||
|
#define DEFAULT_SUS_MNT_GROUP_ID 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||||
|
extern int susfs_auto_add_sus_bind_mount(const char *pathname, struct path *path_target);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||||
|
extern void susfs_auto_add_try_umount_for_bind_mount(struct path *path);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||||
|
extern void susfs_auto_add_sus_ksu_default_mount(const char __user *to_pathname);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_RKP_NS_PROT
|
#ifdef CONFIG_RKP_NS_PROT
|
||||||
#define KDP_MOUNT_SYSTEM "/system"
|
#define KDP_MOUNT_SYSTEM "/system"
|
||||||
#define KDP_MOUNT_SYSTEM_LEN strlen(KDP_MOUNT_SYSTEM)
|
#define KDP_MOUNT_SYSTEM_LEN strlen(KDP_MOUNT_SYSTEM)
|
||||||
|
@ -290,6 +310,20 @@ static int mnt_alloc_vfsmount(struct mount *mnt)
|
||||||
static void mnt_free_id(struct mount *mnt)
|
static void mnt_free_id(struct mount *mnt)
|
||||||
{
|
{
|
||||||
int id = mnt->mnt_id;
|
int id = mnt->mnt_id;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
int orig_id;
|
||||||
|
// If mnt->mnt.susfs_orig_mnt_id is not zero, it means mnt->mnt_id is spoofed,
|
||||||
|
// so here we return the original mnt_id for being freed.
|
||||||
|
if (unlikely(mnt->mnt.susfs_orig_mnt_id)) {
|
||||||
|
orig_id = mnt->mnt.susfs_orig_mnt_id;
|
||||||
|
spin_lock(&mnt_id_lock);
|
||||||
|
ida_remove(&mnt_id_ida, orig_id);
|
||||||
|
if (mnt_id_start > orig_id)
|
||||||
|
mnt_id_start = orig_id;
|
||||||
|
spin_unlock(&mnt_id_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
spin_lock(&mnt_id_lock);
|
spin_lock(&mnt_id_lock);
|
||||||
ida_remove(&mnt_id_ida, id);
|
ida_remove(&mnt_id_ida, id);
|
||||||
if (mnt_id_start > id)
|
if (mnt_id_start > id)
|
||||||
|
@ -297,6 +331,14 @@ static void mnt_free_id(struct mount *mnt)
|
||||||
spin_unlock(&mnt_id_lock);
|
spin_unlock(&mnt_id_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
static void susfs_mnt_alloc_group_id(struct mount *mnt)
|
||||||
|
{
|
||||||
|
// Just assign the same default sus mount_group_id to mnt->mnt_group_id
|
||||||
|
mnt->mnt_group_id = DEFAULT_SUS_MNT_GROUP_ID;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a new peer group ID
|
* Allocate a new peer group ID
|
||||||
*
|
*
|
||||||
|
@ -324,6 +366,14 @@ static int mnt_alloc_group_id(struct mount *mnt)
|
||||||
void mnt_release_group_id(struct mount *mnt)
|
void mnt_release_group_id(struct mount *mnt)
|
||||||
{
|
{
|
||||||
int id = mnt->mnt_group_id;
|
int id = mnt->mnt_group_id;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
// If mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID, it means 'mnt' is sus mount,
|
||||||
|
// here we don't need to free the mnt_group_id and just simply return and do nothing.
|
||||||
|
if (unlikely(mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID)) {
|
||||||
|
mnt->mnt_group_id = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ida_remove(&mnt_group_ida, id);
|
ida_remove(&mnt_group_ida, id);
|
||||||
if (mnt_group_start > id)
|
if (mnt_group_start > id)
|
||||||
mnt_group_start = id;
|
mnt_group_start = id;
|
||||||
|
@ -1271,6 +1321,14 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
||||||
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
|
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
|
||||||
#endif
|
#endif
|
||||||
mnt->mnt_parent = mnt;
|
mnt->mnt_parent = mnt;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (susfs_is_current_zygote_domain()) {
|
||||||
|
mnt->mnt.susfs_orig_mnt_id = mnt->mnt_id;
|
||||||
|
mnt->mnt_id = current->susfs_last_fake_mnt_id++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
lock_mount_hash();
|
lock_mount_hash();
|
||||||
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
|
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
|
||||||
unlock_mount_hash();
|
unlock_mount_hash();
|
||||||
|
@ -1396,6 +1454,14 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
|
||||||
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
|
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
|
||||||
#endif
|
#endif
|
||||||
mnt->mnt_parent = mnt;
|
mnt->mnt_parent = mnt;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (susfs_is_current_zygote_domain() && !(flag & CL_SUSFS_COPY_MNT_NS)) {
|
||||||
|
mnt->mnt.susfs_orig_mnt_id = mnt->mnt_id;
|
||||||
|
mnt->mnt_id = current->susfs_last_fake_mnt_id++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
lock_mount_hash();
|
lock_mount_hash();
|
||||||
list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
|
list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
|
||||||
unlock_mount_hash();
|
unlock_mount_hash();
|
||||||
|
@ -2370,6 +2436,17 @@ static int invent_group_ids(struct mount *mnt, bool recurse)
|
||||||
{
|
{
|
||||||
struct mount *p;
|
struct mount *p;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
|
||||||
|
if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
|
||||||
|
susfs_mnt_alloc_group_id(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
|
for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
|
||||||
if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
|
if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
|
||||||
int err = mnt_alloc_group_id(p);
|
int err = mnt_alloc_group_id(p);
|
||||||
|
@ -2748,6 +2825,24 @@ static int do_loopback(struct path *path, const char *old_name,
|
||||||
umount_tree(mnt, UMOUNT_SYNC);
|
umount_tree(mnt, UMOUNT_SYNC);
|
||||||
unlock_mount_hash();
|
unlock_mount_hash();
|
||||||
}
|
}
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) || defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT)
|
||||||
|
// Check if bind mounted path should be hidden and umounted automatically.
|
||||||
|
// And we target only process with ksu domain.
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT)
|
||||||
|
if (susfs_auto_add_sus_bind_mount(old_name, &old_path)) {
|
||||||
|
goto orig_flow;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT)
|
||||||
|
susfs_auto_add_try_umount_for_bind_mount(path);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT)
|
||||||
|
orig_flow:
|
||||||
|
#endif
|
||||||
|
#endif // #if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT) || defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT)
|
||||||
|
|
||||||
out2:
|
out2:
|
||||||
unlock_mount(mp);
|
unlock_mount(mp);
|
||||||
out:
|
out:
|
||||||
|
@ -3433,6 +3528,13 @@ long do_mount(const char *dev_name, const char __user *dir_name,
|
||||||
#else
|
#else
|
||||||
retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,
|
retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,
|
||||||
dev_name, data_page);
|
dev_name, data_page);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||||
|
if (!retval && (!(flags & (MS_REMOUNT | MS_BIND | MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)))) {
|
||||||
|
if (susfs_is_current_ksu_domain()) {
|
||||||
|
susfs_auto_add_sus_ksu_default_mount(dir_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
dput_out:
|
dput_out:
|
||||||
path_put(&path);
|
path_put(&path);
|
||||||
|
@ -3511,6 +3613,10 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
|
||||||
struct mount *old;
|
struct mount *old;
|
||||||
struct mount *new;
|
struct mount *new;
|
||||||
int copy_flags;
|
int copy_flags;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
bool is_zygote_pid = susfs_is_current_zygote_domain();
|
||||||
|
int last_entry_mnt_id = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
BUG_ON(!ns);
|
BUG_ON(!ns);
|
||||||
|
|
||||||
|
@ -3530,6 +3636,12 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
|
||||||
copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
|
copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
|
||||||
if (user_ns != ns->user_ns)
|
if (user_ns != ns->user_ns)
|
||||||
copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
|
copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (is_zygote_pid) {
|
||||||
|
// Let clone_mnt() in copy_tree() know we only interested in function called by copy_mnt_ns()
|
||||||
|
copy_flags |= CL_SUSFS_COPY_MNT_NS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_RKP_NS_PROT
|
#ifdef CONFIG_RKP_NS_PROT
|
||||||
new = copy_tree(old, old->mnt->mnt_root, copy_flags);
|
new = copy_tree(old, old->mnt->mnt_root, copy_flags);
|
||||||
#else
|
#else
|
||||||
|
@ -3586,6 +3698,29 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
|
||||||
#endif
|
#endif
|
||||||
p = next_mnt(p, old);
|
p = next_mnt(p, old);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
// current->susfs_last_fake_mnt_id -> to record last valid fake mnt_id to zygote pid
|
||||||
|
// q->mnt.susfs_orig_mnt_id -> original mnt_id
|
||||||
|
// q->mnt_id -> will be modified to the fake mnt_id
|
||||||
|
|
||||||
|
// Here We are only interested in processes of which original mnt namespace belongs to zygote
|
||||||
|
// Also we just make use of existing 'q' mount pointer, no need to delcare extra mount pointer
|
||||||
|
if (is_zygote_pid) {
|
||||||
|
last_entry_mnt_id = list_first_entry(&new_ns->list, struct mount, mnt_list)->mnt_id;
|
||||||
|
list_for_each_entry(q, &new_ns->list, mnt_list) {
|
||||||
|
if (unlikely(q->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
q->mnt.susfs_orig_mnt_id = q->mnt_id;
|
||||||
|
q->mnt_id = last_entry_mnt_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Assign the 'last_entry_mnt_id' to 'current->susfs_last_fake_mnt_id' for later use.
|
||||||
|
// should be fine here assuming zygote is forking/unsharing app in one single thread.
|
||||||
|
// Or should we put a lock here?
|
||||||
|
current->susfs_last_fake_mnt_id = last_entry_mnt_id;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace_unlock();
|
namespace_unlock();
|
||||||
|
|
||||||
if (rootmnt)
|
if (rootmnt)
|
||||||
|
@ -4211,3 +4346,37 @@ const struct proc_ns_operations mntns_operations = {
|
||||||
.install = mntns_install,
|
.install = mntns_install,
|
||||||
.owner = mntns_owner,
|
.owner = mntns_owner,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||||
|
extern void susfs_try_umount_all(uid_t uid);
|
||||||
|
void susfs_run_try_umount_for_current_mnt_ns(void) {
|
||||||
|
struct mount *mnt;
|
||||||
|
struct mnt_namespace *mnt_ns;
|
||||||
|
|
||||||
|
mnt_ns = current->nsproxy->mnt_ns;
|
||||||
|
// Lock the namespace
|
||||||
|
namespace_lock();
|
||||||
|
list_for_each_entry(mnt, &mnt_ns->list, mnt_list) {
|
||||||
|
// Change the sus mount to be private
|
||||||
|
if (mnt->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) {
|
||||||
|
change_mnt_propagation(mnt, MS_PRIVATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unlock the namespace
|
||||||
|
namespace_unlock();
|
||||||
|
susfs_try_umount_all(current_uid().val);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
|
bool susfs_is_mnt_devname_ksu(struct path *path) {
|
||||||
|
struct mount *mnt;
|
||||||
|
|
||||||
|
if (path && path->mnt) {
|
||||||
|
mnt = real_mount(path->mnt);
|
||||||
|
if (mnt && mnt->mnt_devname && !strcmp(mnt->mnt_devname, "KSU")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -115,6 +115,16 @@ static int ovl_getattr(const struct path *path, struct kstat *stat,
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
ovl_path_lowerdata(dentry, &realpath);
|
||||||
|
if (likely(realpath.mnt && realpath.dentry)) {
|
||||||
|
old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
|
err = vfs_getattr(&realpath, stat);
|
||||||
|
ovl_revert_creds(old_cred);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ovl_path_real(dentry, &realpath);
|
ovl_path_real(dentry, &realpath);
|
||||||
old_cred = ovl_override_creds(dentry->d_sb);
|
old_cred = ovl_override_creds(dentry->d_sb);
|
||||||
err = vfs_getattr(&realpath, stat, request_mask, flags);
|
err = vfs_getattr(&realpath, stat, request_mask, flags);
|
||||||
|
|
|
@ -148,6 +148,9 @@ u64 ovl_dentry_version_get(struct dentry *dentry);
|
||||||
void ovl_dentry_version_inc(struct dentry *dentry);
|
void ovl_dentry_version_inc(struct dentry *dentry);
|
||||||
void ovl_path_upper(struct dentry *dentry, struct path *path);
|
void ovl_path_upper(struct dentry *dentry, struct path *path);
|
||||||
void ovl_path_lower(struct dentry *dentry, struct path *path);
|
void ovl_path_lower(struct dentry *dentry, struct path *path);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
void ovl_path_lowerdata(struct dentry *dentry, struct path *path);
|
||||||
|
#endif
|
||||||
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
|
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
|
||||||
int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
|
int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
|
||||||
struct dentry *ovl_dentry_upper(struct dentry *dentry);
|
struct dentry *ovl_dentry_upper(struct dentry *dentry);
|
||||||
|
|
|
@ -499,7 +499,19 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
|
||||||
if (!od)
|
if (!od)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
ovl_path_lowerdata(file->f_path.dentry, &realpath);
|
||||||
|
if (likely(realpath.mnt && realpath.dentry)) {
|
||||||
|
// We still use '__OVL_PATH_UPPER' here which should be fine.
|
||||||
|
type = __OVL_PATH_UPPER;
|
||||||
|
goto bypass_orig_flow;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
type = ovl_path_real(file->f_path.dentry, &realpath);
|
type = ovl_path_real(file->f_path.dentry, &realpath);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
bypass_orig_flow:
|
||||||
|
#endif
|
||||||
realfile = ovl_path_open(&realpath, file->f_flags);
|
realfile = ovl_path_open(&realpath, file->f_flags);
|
||||||
if (IS_ERR(realfile)) {
|
if (IS_ERR(realfile)) {
|
||||||
kfree(od);
|
kfree(od);
|
||||||
|
|
|
@ -186,6 +186,20 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)
|
||||||
*path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL };
|
*path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
void ovl_path_lowerdata(struct dentry *dentry, struct path *path)
|
||||||
|
{
|
||||||
|
struct ovl_entry *oe = dentry->d_fsdata;
|
||||||
|
|
||||||
|
if (oe->numlower) {
|
||||||
|
path->mnt = oe->lowerstack[oe->numlower - 1].mnt;
|
||||||
|
path->dentry = oe->lowerstack[oe->numlower - 1].dentry;
|
||||||
|
} else {
|
||||||
|
*path = (struct path) { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int ovl_want_write(struct dentry *dentry)
|
int ovl_want_write(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
|
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
|
||||||
|
@ -654,6 +668,18 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||||
struct path path;
|
struct path path;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
ovl_path_lowerdata(root_dentry, &path);
|
||||||
|
if (likely(path.mnt && path.dentry)) {
|
||||||
|
err = vfs_statfs(&path, buf);
|
||||||
|
if (!err) {
|
||||||
|
buf->f_namelen = 255; // 255 for erofs, ext2/4, f2fs
|
||||||
|
buf->f_type = path.dentry->d_sb->s_magic;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ovl_path_real(root_dentry, &path);
|
ovl_path_real(root_dentry, &path);
|
||||||
|
|
||||||
err = vfs_statfs(&path, buf);
|
err = vfs_statfs(&path, buf);
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
|
||||||
|
extern int susfs_spoof_cmdline_or_bootconfig(struct seq_file *m);
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FLAG_DELETE = 0,
|
FLAG_DELETE = 0,
|
||||||
|
@ -13,6 +16,12 @@ static char new_command_line[COMMAND_LINE_SIZE];
|
||||||
|
|
||||||
static int cmdline_proc_show(struct seq_file *m, void *v)
|
static int cmdline_proc_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
|
+#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
|
||||||
|
if (!susfs_spoof_cmdline_or_bootconfig(m)) {
|
||||||
|
seq_putc(m, '\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
seq_puts(m, new_command_line);
|
seq_puts(m, new_command_line);
|
||||||
seq_putc(m, '\n');
|
seq_putc(m, '\n');
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include <linux/page_idle.h>
|
#include <linux/page_idle.h>
|
||||||
#include <linux/shmem_fs.h>
|
#include <linux/shmem_fs.h>
|
||||||
#include <linux/mm_inline.h>
|
#include <linux/mm_inline.h>
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
|
||||||
|
@ -375,6 +378,10 @@ static void show_vma_header_prefix(struct seq_file *m,
|
||||||
MAJOR(dev), MINOR(dev), ino);
|
MAJOR(dev), MINOR(dev), ino);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
static void
|
||||||
show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
||||||
{
|
{
|
||||||
|
@ -390,8 +397,17 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
struct inode *inode = file_inode(vma->vm_file);
|
struct inode *inode = file_inode(vma->vm_file);
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
if (unlikely(inode->i_state & INODE_STATE_SUS_KSTAT)) {
|
||||||
|
susfs_sus_ino_for_show_map_vma(inode->i_ino, &dev, &ino);
|
||||||
|
goto bypass_orig_flow;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
dev = inode->i_sb->s_dev;
|
dev = inode->i_sb->s_dev;
|
||||||
ino = inode->i_ino;
|
ino = inode->i_ino;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
bypass_orig_flow:
|
||||||
|
#endif
|
||||||
pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
|
pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,17 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/fs_struct.h>
|
#include <linux/fs_struct.h>
|
||||||
#include "proc/internal.h" /* only for get_proc_task() in ->open() */
|
#include "proc/internal.h" /* only for get_proc_task() in ->open() */
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "pnode.h"
|
#include "pnode.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
extern bool susfs_is_current_ksu_domain(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct seq_file *m = file->private_data;
|
struct seq_file *m = file->private_data;
|
||||||
|
@ -99,6 +106,11 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
|
||||||
struct super_block *sb = mnt_path.dentry->d_sb;
|
struct super_block *sb = mnt_path.dentry->d_sb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain()))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sb->s_op->show_devname) {
|
if (sb->s_op->show_devname) {
|
||||||
err = sb->s_op->show_devname(m, mnt_path.dentry);
|
err = sb->s_op->show_devname(m, mnt_path.dentry);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -135,6 +147,11 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
|
||||||
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain()))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
|
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
|
||||||
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
||||||
if (sb->s_op->show_path) {
|
if (sb->s_op->show_path) {
|
||||||
|
@ -199,6 +216,11 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
|
||||||
struct super_block *sb = mnt_path.dentry->d_sb;
|
struct super_block *sb = mnt_path.dentry->d_sb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
if (unlikely((r->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT) && !susfs_is_current_ksu_domain()))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* device */
|
/* device */
|
||||||
if (sb->s_op->show_devname) {
|
if (sb->s_op->show_devname) {
|
||||||
seq_puts(m, "device ");
|
seq_puts(m, "device ");
|
||||||
|
|
17
fs/readdir.c
17
fs/readdir.c
|
@ -18,9 +18,16 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
extern int susfs_sus_ino_for_filldir64(unsigned long ino);
|
||||||
|
#endif
|
||||||
|
|
||||||
int iterate_dir(struct file *file, struct dir_context *ctx)
|
int iterate_dir(struct file *file, struct dir_context *ctx)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
|
@ -206,6 +213,11 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
|
||||||
int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
|
int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
|
||||||
sizeof(long));
|
sizeof(long));
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && susfs_sus_ino_for_filldir64(ino)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
buf->error = verify_dirent_name(name, namlen);
|
buf->error = verify_dirent_name(name, namlen);
|
||||||
if (unlikely(buf->error))
|
if (unlikely(buf->error))
|
||||||
return buf->error;
|
return buf->error;
|
||||||
|
@ -295,6 +307,11 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
|
||||||
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
|
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
|
||||||
sizeof(u64));
|
sizeof(u64));
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||||
|
if (likely(current->susfs_task_state & TASK_STRUCT_NON_ROOT_USER_APP_PROC) && susfs_sus_ino_for_filldir64(ino)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
buf->error = verify_dirent_name(name, namlen);
|
buf->error = verify_dirent_name(name, namlen);
|
||||||
if (unlikely(buf->error))
|
if (unlikely(buf->error))
|
||||||
return buf->error;
|
return buf->error;
|
||||||
|
|
18
fs/stat.c
18
fs/stat.c
|
@ -14,10 +14,16 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
#endif
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.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
|
* generic_fillattr - Fill in the basic attributes from the inode struct
|
||||||
* @inode: Inode to use as the source
|
* @inode: Inode to use as the source
|
||||||
|
@ -29,6 +35,16 @@
|
||||||
*/
|
*/
|
||||||
void generic_fillattr(struct inode *inode, struct kstat *stat)
|
void generic_fillattr(struct inode *inode, struct kstat *stat)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||||
|
if (unlikely(inode->i_state & INODE_STATE_SUS_KSTAT)) {
|
||||||
|
susfs_sus_ino_for_generic_fillattr(inode->i_ino, stat);
|
||||||
|
stat->mode = inode->i_mode;
|
||||||
|
stat->rdev = inode->i_rdev;
|
||||||
|
stat->uid = inode->i_uid;
|
||||||
|
stat->gid = inode->i_gid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
stat->dev = inode->i_sb->s_dev;
|
stat->dev = inode->i_sb->s_dev;
|
||||||
stat->ino = inode->i_ino;
|
stat->ino = inode->i_ino;
|
||||||
stat->mode = inode->i_mode;
|
stat->mode = inode->i_mode;
|
||||||
|
|
22
fs/statfs.c
22
fs/statfs.c
|
@ -89,6 +89,22 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
/* - When mounting overlay, the f_flags are set with 'ro' and 'relatime',
|
||||||
|
* but this is an abnormal status, as when we inspect the output from mountinfo,
|
||||||
|
* we will find that all partitions set with 'ro' will have 'noatime' set as well.
|
||||||
|
* - But what is strange here is that the vfsmnt f_flags of the lowest layer has corrent f_flags set,
|
||||||
|
* and still it is always changed to 'relatime' instead of 'noatime' for the final result,
|
||||||
|
* I can't think of any other reason to explain about this, maybe the f_flags is set by its own
|
||||||
|
* filesystem implementation but not the one from overlayfs.
|
||||||
|
* - Anyway we just cannot use the retrieved f_flags from ovl_getattr() of overlayfs,
|
||||||
|
* we need to run one more check for user_statfs() and fd_statfs() by ourselves.
|
||||||
|
*/
|
||||||
|
if (unlikely((st->f_flags & ST_RDONLY) && (st->f_flags & ST_RELATIME))) {
|
||||||
|
st->f_flags &= ~ST_RELATIME;
|
||||||
|
st->f_flags |= ST_NOATIME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +116,12 @@ int fd_statfs(int fd, struct kstatfs *st)
|
||||||
error = vfs_statfs(&f.file->f_path, st);
|
error = vfs_statfs(&f.file->f_path, st);
|
||||||
fdput(f);
|
fdput(f);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SUS_OVERLAYFS
|
||||||
|
if (unlikely((st->f_flags & ST_RDONLY) && (st->f_flags & ST_RELATIME))) {
|
||||||
|
st->f_flags &= ~ST_RELATIME;
|
||||||
|
st->f_flags |= ST_NOATIME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
140
fs/sus_su.c
Normal file
140
fs/sus_su.c
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include <linux/cred.h>
|
||||||
|
#include <linux/sus_su.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
|
||||||
|
extern bool susfs_is_log_enabled __read_mostly;
|
||||||
|
#define SUSFS_LOGI(fmt, ...) if (susfs_is_log_enabled) pr_info("susfs_sus_su:[%u][%u][%s] " fmt, current_uid().val, current->pid, __func__, ##__VA_ARGS__)
|
||||||
|
#define SUSFS_LOGE(fmt, ...) if (susfs_is_log_enabled) pr_err("susfs_sus_su:[%u][%u][%s]" fmt, current_uid().val, current->pid, __func__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define SUSFS_LOGI(fmt, ...)
|
||||||
|
#define SUSFS_LOGE(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FIFO_SIZE 1024
|
||||||
|
#define MAX_DRV_NAME 255
|
||||||
|
|
||||||
|
static int cur_maj_dev_num = -1;
|
||||||
|
static char fifo_buffer[FIFO_SIZE];
|
||||||
|
static struct cdev sus_su_cdev;
|
||||||
|
static const char *sus_su_token = "!@#$SU_IS_SUS$#@!-pRE6W9BKXrJr1hEKyvDq0CvWziVKbatT8yzq06fhtrEGky2tVS7Q2QTjhtMfVMGV";
|
||||||
|
static char rand_drv_path[MAX_DRV_NAME+1] = "/dev/";
|
||||||
|
static bool is_sus_su_enabled_before = false;
|
||||||
|
|
||||||
|
extern bool susfs_is_allow_su(void);
|
||||||
|
extern void ksu_escape_to_root(void);
|
||||||
|
|
||||||
|
static void gen_rand_drv_name(char *buffer, size_t min_length, size_t max_length) {
|
||||||
|
const char *symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-+@#:=";
|
||||||
|
size_t symbols_length = strlen(symbols);
|
||||||
|
size_t length, i;
|
||||||
|
unsigned int rand_value;
|
||||||
|
|
||||||
|
// Determine the random length of the string
|
||||||
|
get_random_bytes(&rand_value, sizeof(rand_value));
|
||||||
|
length = min_length + (rand_value % (max_length - min_length + 1));
|
||||||
|
|
||||||
|
for (i = 0; i < length; ++i) {
|
||||||
|
get_random_bytes(&rand_value, sizeof(rand_value));
|
||||||
|
buffer[i] = symbols[rand_value % symbols_length];
|
||||||
|
}
|
||||||
|
buffer[length] = '\0'; // Null-terminate the string
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fifo_open(struct inode *inode, struct file *file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fifo_release(struct inode *inode, struct file *file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fifo_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fifo_write(struct file *file, const char __user *buf, size_t len, loff_t *offset) {
|
||||||
|
int sus_su_token_len = strlen(sus_su_token);
|
||||||
|
|
||||||
|
if (!susfs_is_allow_su()) {
|
||||||
|
SUSFS_LOGE("root is not allowed for uid: '%d', pid: '%d'\n", current_uid().val, current->pid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_from_user(fifo_buffer, buf, sus_su_token_len+1)) {
|
||||||
|
SUSFS_LOGE("copy_from_user() failed, uid: '%d', pid: '%d'\n", current_uid().val, current->pid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(fifo_buffer, sus_su_token, sus_su_token_len+1)) {
|
||||||
|
SUSFS_LOGI("granting root access for uid: '%d', pid: '%d'\n", current_uid().val, current->pid);
|
||||||
|
ksu_escape_to_root();
|
||||||
|
} else {
|
||||||
|
SUSFS_LOGI("wrong token! deny root access for uid: '%d', pid: '%d'\n", current_uid().val, current->pid);
|
||||||
|
}
|
||||||
|
memset(fifo_buffer, 0, FIFO_SIZE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = fifo_open,
|
||||||
|
.release = fifo_release,
|
||||||
|
.read = fifo_read,
|
||||||
|
.write = fifo_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
int sus_su_fifo_init(int *maj_dev_num, char *drv_path) {
|
||||||
|
if (cur_maj_dev_num > 0) {
|
||||||
|
SUSFS_LOGE("'%s' is already registered\n", rand_drv_path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a random driver name if it is executed for the first time
|
||||||
|
if (!is_sus_su_enabled_before) {
|
||||||
|
// min length 192, max length 248, just make sure max length doesn't exceeds 255
|
||||||
|
gen_rand_drv_name(rand_drv_path+5, 192, 248);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_maj_dev_num = register_chrdev(0, rand_drv_path+5, &fops);
|
||||||
|
if (cur_maj_dev_num < 0) {
|
||||||
|
SUSFS_LOGE("Failed to register character device\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev_init(&sus_su_cdev, &fops);
|
||||||
|
if (cdev_add(&sus_su_cdev, MKDEV(cur_maj_dev_num, 0), 1) < 0) {
|
||||||
|
unregister_chrdev(cur_maj_dev_num, rand_drv_path+5);
|
||||||
|
SUSFS_LOGE("Failed to add cdev\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(drv_path, rand_drv_path, strlen(rand_drv_path));
|
||||||
|
*maj_dev_num = cur_maj_dev_num;
|
||||||
|
SUSFS_LOGI("'%s' registered with major device number %d\n", rand_drv_path, cur_maj_dev_num);
|
||||||
|
|
||||||
|
if (!is_sus_su_enabled_before)
|
||||||
|
is_sus_su_enabled_before = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sus_su_fifo_exit(int *maj_dev_num, char *drv_path) {
|
||||||
|
if (cur_maj_dev_num < 0) {
|
||||||
|
SUSFS_LOGE("'%s' was already unregistered before\n", rand_drv_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev_del(&sus_su_cdev);
|
||||||
|
unregister_chrdev(cur_maj_dev_num, rand_drv_path+5);
|
||||||
|
cur_maj_dev_num = -1;
|
||||||
|
*maj_dev_num = cur_maj_dev_num;
|
||||||
|
strncpy(drv_path, rand_drv_path, strlen(rand_drv_path));
|
||||||
|
SUSFS_LOGI("'%s' unregistered\n", rand_drv_path);
|
||||||
|
return 0;
|
||||||
|
}
|
25
fs/susfs.c
25
fs/susfs.c
|
@ -19,9 +19,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static spinlock_t susfs_spin_lock;
|
static spinlock_t susfs_spin_lock;
|
||||||
#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT
|
|
||||||
static const char *magic_mount_workdir = "/debug_ramdisk/workdir";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern bool susfs_is_current_ksu_domain(void);
|
extern bool susfs_is_current_ksu_domain(void);
|
||||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||||
|
@ -43,16 +40,26 @@ static DEFINE_HASHTABLE(SUS_PATH_HLIST, 10);
|
||||||
static int susfs_update_sus_path_inode(char *target_pathname) {
|
static int susfs_update_sus_path_inode(char *target_pathname) {
|
||||||
struct path p;
|
struct path p;
|
||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
|
const char *dev_type;
|
||||||
|
|
||||||
if (kern_path(target_pathname, LOOKUP_FOLLOW, &p)) {
|
if (kern_path(target_pathname, LOOKUP_FOLLOW, &p)) {
|
||||||
SUSFS_LOGE("Failed opening file '%s'\n", target_pathname);
|
SUSFS_LOGE("Failed opening file '%s'\n", target_pathname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't allow path of which filesystem type is "tmpfs", because its inode->i_ino is starting from 1 again,
|
// - We don't allow paths of which filesystem type is "tmpfs" or "fuse".
|
||||||
// which will cause wrong comparison in function susfs_sus_ino_for_filldir64()
|
// For tmpfs, because its starting inode->i_ino will begin with 1 again,
|
||||||
if (strcmp(p.mnt->mnt_sb->s_type->name, "tmpfs") == 0) {
|
// so it will cause wrong comparison in function susfs_sus_ino_for_filldir64()
|
||||||
SUSFS_LOGE("target_pathname: '%s' cannot be added since its filesystem is 'tmpfs'\n", target_pathname);
|
// For fuse, which is almost storage related, sus_path should not handle any paths of
|
||||||
|
// which filesystem is "fuse" as well, since app can write to "fuse" and lookup files via
|
||||||
|
// like binder / system API (you can see the uid is changed to 1000)/
|
||||||
|
// - so sus_path should be applied only on read-only filesystem like "erofs" or "f2fs", but not "tmpfs" or "fuse",
|
||||||
|
// people may rely on HMA for /data isolation instead.
|
||||||
|
dev_type = p.mnt->mnt_sb->s_type->name;
|
||||||
|
if (!strcmp(dev_type, "tmpfs") ||
|
||||||
|
!strcmp(dev_type, "fuse")) {
|
||||||
|
SUSFS_LOGE("target_pathname: '%s' cannot be added since its filesystem type is '%s'\n",
|
||||||
|
target_pathname, dev_type);
|
||||||
path_put(&p);
|
path_put(&p);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +583,7 @@ void susfs_auto_add_try_umount_for_bind_mount(struct path *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT
|
#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT
|
||||||
if (strstr(dpath, magic_mount_workdir)) {
|
if (strstr(dpath, MAGIC_MOUNT_WORKDIR)) {
|
||||||
is_magic_mount_path = true;
|
is_magic_mount_path = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -602,7 +609,7 @@ void susfs_auto_add_try_umount_for_bind_mount(struct path *path) {
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT
|
#ifdef CONFIG_KSU_SUSFS_HAS_MAGIC_MOUNT
|
||||||
if (is_magic_mount_path) {
|
if (is_magic_mount_path) {
|
||||||
strncpy(new_list->info.target_pathname, dpath + strlen(magic_mount_workdir), SUSFS_MAX_LEN_PATHNAME-1);
|
strncpy(new_list->info.target_pathname, dpath + strlen(MAGIC_MOUNT_WORKDIR), SUSFS_MAX_LEN_PATHNAME-1);
|
||||||
goto out_add_to_list;
|
goto out_add_to_list;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -71,6 +71,9 @@ struct vfsmount {
|
||||||
#endif
|
#endif
|
||||||
int mnt_flags;
|
int mnt_flags;
|
||||||
void *data;
|
void *data;
|
||||||
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
|
u64 susfs_orig_mnt_id;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file; /* forward dec */
|
struct file; /* forward dec */
|
||||||
|
|
|
@ -2185,6 +2185,10 @@ struct task_struct {
|
||||||
atomic_t stack_refcount;
|
atomic_t stack_refcount;
|
||||||
#endif
|
#endif
|
||||||
/* CPU-specific state of this task */
|
/* CPU-specific state of this task */
|
||||||
|
#ifdef CONFIG_KSU_SUSFS
|
||||||
|
u64 susfs_task_state;
|
||||||
|
u64 susfs_last_fake_mnt_id;
|
||||||
|
#endif
|
||||||
struct thread_struct thread;
|
struct thread_struct thread;
|
||||||
/*
|
/*
|
||||||
* WARNING: on x86, 'thread_struct' contains a variable-sized
|
* WARNING: on x86, 'thread_struct' contains a variable-sized
|
||||||
|
|
9
include/linux/sus_su.h
Normal file
9
include/linux/sus_su.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef __KSU_H_SUS_SU
|
||||||
|
#define __KSU_H_SUS_SU
|
||||||
|
|
||||||
|
#include "../../drivers/kernelsu/core_hook.h"
|
||||||
|
|
||||||
|
int sus_su_fifo_init(int *maj_dev_num, char *drv_path);
|
||||||
|
int sus_su_fifo_exit(int *maj_dev_num, char *drv_path);
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
#include <linux/path.h>
|
#include <linux/path.h>
|
||||||
|
#include <linux/susfs_def.h>
|
||||||
|
|
||||||
#define SUSFS_VERSION "v1.5.3"
|
#define SUSFS_VERSION "v1.5.3"
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
||||||
|
@ -14,52 +15,6 @@
|
||||||
#define SUSFS_VARIANT "GKI"
|
#define SUSFS_VARIANT "GKI"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/********/
|
|
||||||
/* ENUM */
|
|
||||||
/********/
|
|
||||||
/* shared with userspace ksu_susfs tool */
|
|
||||||
#define CMD_SUSFS_ADD_SUS_PATH 0x55550
|
|
||||||
#define CMD_SUSFS_ADD_SUS_MOUNT 0x55560
|
|
||||||
#define CMD_SUSFS_ADD_SUS_KSTAT 0x55570
|
|
||||||
#define CMD_SUSFS_UPDATE_SUS_KSTAT 0x55571
|
|
||||||
#define CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY 0x55572
|
|
||||||
#define CMD_SUSFS_ADD_TRY_UMOUNT 0x55580
|
|
||||||
#define CMD_SUSFS_SET_UNAME 0x55590
|
|
||||||
#define CMD_SUSFS_ENABLE_LOG 0x555a0
|
|
||||||
#define CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG 0x555b0
|
|
||||||
#define CMD_SUSFS_ADD_OPEN_REDIRECT 0x555c0
|
|
||||||
#define CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS 0x555d0
|
|
||||||
#define CMD_SUSFS_SHOW_VERSION 0x555e1
|
|
||||||
#define CMD_SUSFS_SHOW_ENABLED_FEATURES 0x555e2
|
|
||||||
#define CMD_SUSFS_SHOW_VARIANT 0x555e3
|
|
||||||
#define CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE 0x555e4
|
|
||||||
#define CMD_SUSFS_IS_SUS_SU_READY 0x555f0
|
|
||||||
#define CMD_SUSFS_SUS_SU 0x60000
|
|
||||||
|
|
||||||
#define SUSFS_MAX_LEN_PATHNAME 256 // 256 should address many paths already unless you are doing some strange experimental stuff, then set your own desired length
|
|
||||||
#define SUSFS_FAKE_CMDLINE_OR_BOOTCONFIG_SIZE 4096
|
|
||||||
|
|
||||||
#define TRY_UMOUNT_DEFAULT 0
|
|
||||||
#define TRY_UMOUNT_DETACH 1
|
|
||||||
|
|
||||||
#define SUS_SU_DISABLED 0
|
|
||||||
#define SUS_SU_WITH_OVERLAY 1 /* deprecated */
|
|
||||||
#define SUS_SU_WITH_HOOKS 2
|
|
||||||
|
|
||||||
/*
|
|
||||||
* inode->i_state => storing flag 'INODE_STATE_'
|
|
||||||
* mount->mnt.android_kabi_reserved4 => storing original mnt_id
|
|
||||||
* task_struct->android_kabi_reserved8 => storing last valid fake mnt_id
|
|
||||||
* user_struct->android_kabi_reserved2 => storing flag 'USER_STRUCT_KABI2_'
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INODE_STATE_SUS_PATH 16777216 // 1 << 24
|
|
||||||
#define INODE_STATE_SUS_MOUNT 33554432 // 1 << 25
|
|
||||||
#define INODE_STATE_SUS_KSTAT 67108864 // 1 << 26
|
|
||||||
#define INODE_STATE_OPEN_REDIRECT 134217728 // 1 << 27
|
|
||||||
|
|
||||||
#define USER_STRUCT_KABI2_NON_ROOT_USER_APP_PROFILE 16777216 // 1 << 24, for distinguishing root/no-root granted user app process
|
|
||||||
|
|
||||||
/*********/
|
/*********/
|
||||||
/* MACRO */
|
/* MACRO */
|
||||||
/*********/
|
/*********/
|
||||||
|
|
55
include/linux/susfs_def.h
Normal file
55
include/linux/susfs_def.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef KSU_SUSFS_DEF_H
|
||||||
|
#define KSU_SUSFS_DEF_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
|
|
||||||
|
/********/
|
||||||
|
/* ENUM */
|
||||||
|
/********/
|
||||||
|
/* shared with userspace ksu_susfs tool */
|
||||||
|
#define CMD_SUSFS_ADD_SUS_PATH 0x55550
|
||||||
|
#define CMD_SUSFS_ADD_SUS_MOUNT 0x55560
|
||||||
|
#define CMD_SUSFS_ADD_SUS_KSTAT 0x55570
|
||||||
|
#define CMD_SUSFS_UPDATE_SUS_KSTAT 0x55571
|
||||||
|
#define CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY 0x55572
|
||||||
|
#define CMD_SUSFS_ADD_TRY_UMOUNT 0x55580
|
||||||
|
#define CMD_SUSFS_SET_UNAME 0x55590
|
||||||
|
#define CMD_SUSFS_ENABLE_LOG 0x555a0
|
||||||
|
#define CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG 0x555b0
|
||||||
|
#define CMD_SUSFS_ADD_OPEN_REDIRECT 0x555c0
|
||||||
|
#define CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS 0x555d0
|
||||||
|
#define CMD_SUSFS_SHOW_VERSION 0x555e1
|
||||||
|
#define CMD_SUSFS_SHOW_ENABLED_FEATURES 0x555e2
|
||||||
|
#define CMD_SUSFS_SHOW_VARIANT 0x555e3
|
||||||
|
#define CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE 0x555e4
|
||||||
|
#define CMD_SUSFS_IS_SUS_SU_READY 0x555f0
|
||||||
|
#define CMD_SUSFS_SUS_SU 0x60000
|
||||||
|
|
||||||
|
#define SUSFS_MAX_LEN_PATHNAME 256 // 256 should address many paths already unless you are doing some strange experimental stuff, then set your own desired length
|
||||||
|
#define SUSFS_FAKE_CMDLINE_OR_BOOTCONFIG_SIZE 4096
|
||||||
|
|
||||||
|
#define TRY_UMOUNT_DEFAULT 0
|
||||||
|
#define TRY_UMOUNT_DETACH 1
|
||||||
|
|
||||||
|
#define SUS_SU_DISABLED 0
|
||||||
|
#define SUS_SU_WITH_OVERLAY 1 /* deprecated */
|
||||||
|
#define SUS_SU_WITH_HOOKS 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* inode->i_state => storing flag 'INODE_STATE_'
|
||||||
|
* mount->mnt.susfs_orig_mnt_id => storing original mnt_id
|
||||||
|
* task_struct->susfs_last_fake_mnt_id => storing last valid fake mnt_id
|
||||||
|
* task_struct->susfs_task_state => storing flag 'TASK_STRUCT_KABI'
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INODE_STATE_SUS_PATH BIT(24)
|
||||||
|
#define INODE_STATE_SUS_MOUNT BIT(25)
|
||||||
|
#define INODE_STATE_SUS_KSTAT BIT(26)
|
||||||
|
#define INODE_STATE_OPEN_REDIRECT BIT(27)
|
||||||
|
|
||||||
|
#define TASK_STRUCT_NON_ROOT_USER_APP_PROC BIT(24)
|
||||||
|
|
||||||
|
#define MAGIC_MOUNT_WORKDIR "/debug_ramdisk/workdir"
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -678,8 +678,19 @@ static int s_show(struct seq_file *m, void *p)
|
||||||
seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
|
seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
|
||||||
type, iter->name, iter->module_name);
|
type, iter->name, iter->module_name);
|
||||||
} else
|
} else
|
||||||
|
|
||||||
|
#ifndef CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS
|
||||||
seq_printf(m, "%pK %c %s\n", (void *)iter->value,
|
seq_printf(m, "%pK %c %s\n", (void *)iter->value,
|
||||||
iter->type, iter->name);
|
iter->type, iter->name);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
if (strstr(iter->name, "ksu_") || !strncmp(iter->name, "susfs_", 6) || !strncmp(iter->name, "ksud", 4)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
seq_printf(m, "%pK %c %s\n", (void *)iter->value,
|
||||||
|
iter->type, iter->name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1340,6 +1340,10 @@ static int override_release(char __user *release, size_t len)
|
||||||
return ret;
|
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)
|
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
|
||||||
{
|
{
|
||||||
struct new_utsname tmp;
|
struct new_utsname tmp;
|
||||||
|
@ -1353,6 +1357,9 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
|
||||||
pr_debug("fake uname: %s/%d release=%s\n",
|
pr_debug("fake uname: %s/%d release=%s\n",
|
||||||
current->comm, current->pid, tmp.release);
|
current->comm, current->pid, tmp.release);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
|
||||||
|
susfs_spoof_uname(&tmp);
|
||||||
|
#endif
|
||||||
up_read(&uts_sem);
|
up_read(&uts_sem);
|
||||||
if (copy_to_user(name, &tmp, sizeof(tmp)))
|
if (copy_to_user(name, &tmp, sizeof(tmp)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit df4332728f0c56842c8c0a1bc1d357f3f3c96a7c
|
|
Loading…
Add table
Add a link
Reference in a new issue