Skip to content

Commit

Permalink
import susfs 1.5.5 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
macka69 authored and raystef66 committed Feb 8, 2025
1 parent 1c92a27 commit 811a7f7
Show file tree
Hide file tree
Showing 18 changed files with 454 additions and 57 deletions.
2 changes: 1 addition & 1 deletion KernelSU-Next
Submodule KernelSU-Next updated from e4549b to 95c7da
3 changes: 1 addition & 2 deletions arch/arm64/configs/lmi_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -751,5 +751,4 @@ CONFIG_FRAME_WARN=4096
CONFIG_MAGIC_SYSRQ=y
CONFIG_PANIC_TIMEOUT=-1
CONFIG_FTRACE=y
CONFIG_DEBUG_ALIGN_RODATA=y

CONFIG_DEBUG_ALIGN_RODATA=y
177 changes: 152 additions & 25 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,25 @@
#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

static DEFINE_IDA(susfs_mnt_id_ida);
static DEFINE_IDA(susfs_mnt_group_ida);

#define CL_ZYGOTE_COPY_MNT_NS BIT(24) /* used by copy_mnt_ns() */
#define CL_COPY_MNT_NS BIT(25) /* used by copy_mnt_ns() */
#endif

#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
extern void susfs_auto_add_sus_ksu_default_mount(const char __user *to_pathname);
bool susfs_is_auto_add_sus_ksu_default_mount_enabled = true;
#endif
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
extern int susfs_auto_add_sus_bind_mount(const char *pathname, struct path *path_target);
bool susfs_is_auto_add_sus_bind_mount_enabled = true;
#endif
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
extern void susfs_auto_add_try_umount_for_bind_mount(struct path *path);
#endif
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
extern void susfs_auto_add_sus_ksu_default_mount(const char __user *to_pathname);
bool susfs_is_auto_add_try_umount_for_bind_mount_enabled = true;
#endif

/* Maximum number of mounts in a mount namespace */
Expand Down Expand Up @@ -116,6 +123,18 @@ static inline struct hlist_head *mp_hash(struct dentry *dentry)
return &mountpoint_hashtable[tmp & mp_hash_mask];
}

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// Our own mnt_alloc_id() that assigns mnt_id starting from DEFAULT_SUS_MNT_ID
static int susfs_mnt_alloc_id(struct mount *mnt)
{
int res = ida_alloc_min(&susfs_mnt_id_ida, DEFAULT_SUS_MNT_ID, GFP_KERNEL);

if (res < 0)
return res;
mnt->mnt_id = res;
return 0;
}
#endif
static int mnt_alloc_id(struct mount *mnt)
{
int res = ida_alloc(&mnt_id_ida, GFP_KERNEL);
Expand All @@ -129,10 +148,22 @@ static int mnt_alloc_id(struct mount *mnt)
static void mnt_free_id(struct mount *mnt)
{
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// 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)) {
ida_free(&mnt_id_ida, mnt->mnt.susfs_orig_mnt_id);
// We should first check the 'mnt->mnt.susfs_mnt_id_backup', see if it is DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE
// if so, these mnt_id were not assigned by mnt_alloc_id() so we don't need to free it.
if (unlikely(mnt->mnt.susfs_mnt_id_backup == DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE)) {
return;
}
// Now we can check if its mnt_id is sus
if (unlikely(mnt->mnt_id >= DEFAULT_SUS_MNT_ID)) {
ida_free(&susfs_mnt_id_ida, mnt->mnt_id);
return;
}
// Lastly if 'mnt->mnt.susfs_mnt_id_backup' is not 0, then it contains a backup origin mnt_id
// so we free it in the original way
if (likely(mnt->mnt.susfs_mnt_id_backup)) {
// If mnt->mnt.susfs_mnt_id_backup is not zero, it means mnt->mnt_id is spoofed,
// so here we return the original mnt_id for being freed.
ida_free(&mnt_id_ida, mnt->mnt.susfs_mnt_id_backup);
return;
}
#endif
Expand All @@ -152,7 +183,20 @@ static void susfs_mnt_alloc_group_id(struct mount *mnt)
*/
static int mnt_alloc_group_id(struct mount *mnt)
{
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
int res;

// Check if mnt has sus mnt_id
if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) {
// If so, assign a sus mnt_group id DEFAULT_SUS_MNT_GROUP_ID from susfs_mnt_group_ida
res = ida_alloc_min(&susfs_mnt_group_ida, DEFAULT_SUS_MNT_GROUP_ID, GFP_KERNEL);
goto bypass_orig_flow;
}
res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL);
bypass_orig_flow:
#else
int res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL);
#endif

if (res < 0)
return res;
Expand All @@ -166,9 +210,10 @@ static int mnt_alloc_group_id(struct mount *mnt)
void mnt_release_group_id(struct mount *mnt)
{
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// If mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID, it means 'mnt' is 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)) {
// If mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID, it means 'mnt' is also sus mount,
// then we free the mnt->mnt_group_id from susfs_mnt_group_ida
if (mnt->mnt_group_id >= DEFAULT_SUS_MNT_GROUP_ID) {
ida_free(&susfs_mnt_group_ida, mnt->mnt_group_id);
mnt->mnt_group_id = 0;
return;
}
Expand Down Expand Up @@ -218,13 +263,31 @@ static void drop_mountpoint(struct fs_pin *p)
mntput(&m->mnt);
}

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
static struct mount *alloc_vfsmnt(const char *name, bool should_spoof, int custom_mnt_id)
#else
static struct mount *alloc_vfsmnt(const char *name)
#endif
{
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
if (mnt) {
int err;

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
if (should_spoof) {
if (!custom_mnt_id) {
err = susfs_mnt_alloc_id(mnt);
} else {
mnt->mnt_id = custom_mnt_id;
err = 0;
}
goto bypass_orig_flow;
}
#endif
err = mnt_alloc_id(mnt);
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
bypass_orig_flow:
#endif
if (err)
goto out_free_cache;

Expand Down Expand Up @@ -997,7 +1060,17 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
if (!type)
return ERR_PTR(-ENODEV);

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// For newly created mounts, the only caller process we care is KSU
if (unlikely(susfs_is_current_ksu_domain())) {
mnt = alloc_vfsmnt(name, true, 0);
goto bypass_orig_flow;
}
mnt = alloc_vfsmnt(name, false, 0);
bypass_orig_flow:
#else
mnt = alloc_vfsmnt(name);
#endif
if (!mnt)
return ERR_PTR(-ENOMEM);

Expand Down Expand Up @@ -1025,8 +1098,9 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
mnt->mnt_parent = mnt;

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// If caller process is zygote, then it is a normal mount, so we just reorder the mnt_id
if (susfs_is_current_zygote_domain()) {
mnt->mnt.susfs_orig_mnt_id = mnt->mnt_id;
mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id;
mnt->mnt_id = current->susfs_last_fake_mnt_id++;
}
#endif
Expand Down Expand Up @@ -1060,7 +1134,52 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
struct mount *mnt;
int err;

#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
bool is_current_ksu_domain = susfs_is_current_ksu_domain();
bool is_current_zygote_domain = susfs_is_current_zygote_domain();

/* - It is very important that we need to use CL_COPY_MNT_NS to identify whether
* the clone is a copy_tree() or single mount like called by __do_loopback()
* - if caller process is KSU, consider the following situation:
* 1. it is NOT doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id
* 2. it is doing unshare => spoof the new mnt_id with the old mnt_id
* - If caller process is zygote and old mnt_id is sus => call alloc_vfsmnt() to assign a new sus mnt_id
* - For the rest of caller process that doing unshare => call alloc_vfsmnt() to assign a new sus mnt_id only for old sus mount
*/
// Firstly, check if it is KSU process
if (unlikely(is_current_ksu_domain)) {
// if it is doing single clone
if (!(flag & CL_COPY_MNT_NS)) {
mnt = alloc_vfsmnt(old->mnt_devname, true, 0);
goto bypass_orig_flow;
}
// if it is doing unshare
mnt = alloc_vfsmnt(old->mnt_devname, true, old->mnt_id);
if (mnt) {
mnt->mnt.susfs_mnt_id_backup = DEFAULT_SUS_MNT_ID_FOR_KSU_PROC_UNSHARE;
}
goto bypass_orig_flow;
}
// Secondly, check if it is zygote process and no matter it is doing unshare or not
if (likely(is_current_zygote_domain) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) {
/* Important Note:
* - Here we can't determine whether the unshare is called zygisk or not,
* so we can only patch out the unshare code in zygisk source code for now
* - But at least we can deal with old sus mounts using alloc_vfsmnt()
*/
mnt = alloc_vfsmnt(old->mnt_devname, true, 0);
goto bypass_orig_flow;
}
// Lastly, for other process that is doing unshare operation, but only deal with old sus mount
if ((flag & CL_COPY_MNT_NS) && (old->mnt_id >= DEFAULT_SUS_MNT_ID)) {
mnt = alloc_vfsmnt(old->mnt_devname, true, 0);
goto bypass_orig_flow;
}
mnt = alloc_vfsmnt(old->mnt_devname, false, 0);
bypass_orig_flow:
#else
mnt = alloc_vfsmnt(old->mnt_devname);
#endif
if (!mnt)
return ERR_PTR(-ENOMEM);

Expand Down Expand Up @@ -1114,8 +1233,9 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
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;
// If caller process is zygote and not doing unshare, so we just reorder the mnt_id
if (likely(is_current_zygote_domain) && !(flag & CL_ZYGOTE_COPY_MNT_NS)) {
mnt->mnt.susfs_mnt_id_backup = mnt->mnt_id;
mnt->mnt_id = current->susfs_last_fake_mnt_id++;
}
#endif
Expand Down Expand Up @@ -2356,12 +2476,15 @@ static int do_loopback(struct path *path, const char *old_name,
// 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)) {
if (susfs_is_auto_add_sus_bind_mount_enabled &&
susfs_auto_add_sus_bind_mount(old_name, &old_path)) {
goto orig_flow;
}
#endif
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT)
susfs_auto_add_try_umount_for_bind_mount(path);
if (susfs_is_auto_add_try_umount_for_bind_mount_enabled) {
susfs_auto_add_try_umount_for_bind_mount(path);
}
#endif
}
#if defined(CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT)
Expand Down Expand Up @@ -2969,7 +3092,9 @@ long do_mount(const char *dev_name, const char __user *dir_name,
retval = do_new_mount(&path, type_page, sb_flags, mnt_flags,
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)))) {
// For both Legacy and Magic Mount KernelSU
if (!retval && susfs_is_auto_add_sus_ksu_default_mount_enabled &&
(!(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);
}
Expand Down Expand Up @@ -3076,9 +3201,11 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
if (user_ns != ns->user_ns)
copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
// Always let clone_mnt() in copy_tree() know it is from copy_mnt_ns()
copy_flags |= CL_COPY_MNT_NS;
if (is_zygote_pid) {
// Let clone_mnt() in copy_tree() know we only interested in function called by copy_mnt_ns()
copy_flags |= CL_SUSFS_COPY_MNT_NS;
// Let clone_mnt() in copy_tree() know copy_mnt_ns() is run by zygote process
copy_flags |= CL_ZYGOTE_COPY_MNT_NS;
}
#endif

Expand Down Expand Up @@ -3120,18 +3247,18 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
}
#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.susfs_mnt_id_backup -> original mnt_id
// q->mnt_id -> will be modified to the fake mnt_id

// Here We are only interested in processes of which original mnt namespace belongs to zygote
// Also we just make use of existing 'q' mount pointer, no need to delcare extra mount pointer
if (is_zygote_pid) {
last_entry_mnt_id = list_first_entry(&new_ns->list, struct mount, mnt_list)->mnt_id;
list_for_each_entry(q, &new_ns->list, mnt_list) {
if (unlikely(q->mnt.mnt_root->d_inode->i_state & INODE_STATE_SUS_MOUNT)) {
if (unlikely(q->mnt_id >= DEFAULT_SUS_MNT_ID)) {
continue;
}
q->mnt.susfs_orig_mnt_id = q->mnt_id;
q->mnt.susfs_mnt_id_backup = q->mnt_id;
q->mnt_id = last_entry_mnt_id++;
}
}
Expand Down Expand Up @@ -3699,7 +3826,7 @@ void susfs_run_try_umount_for_current_mnt_ns(void) {
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) {
if (mnt->mnt_id >= DEFAULT_SUS_MNT_ID) {
change_mnt_propagation(mnt, MS_PRIVATE);
}
}
Expand All @@ -3720,4 +3847,4 @@ bool susfs_is_mnt_devname_ksu(struct path *path) {
}
return false;
}
#endif
#endif
Loading

0 comments on commit 811a7f7

Please sign in to comment.