diff --git a/kernel/kernel_umount.c b/kernel/kernel_umount.c index be58b5f4..694f9921 100644 --- a/kernel/kernel_umount.c +++ b/kernel/kernel_umount.c @@ -52,7 +52,6 @@ static const struct ksu_feature_handler kernel_umount_handler = { #ifdef CONFIG_KSU_SUSFS extern bool susfs_is_mnt_devname_ksu(struct path *path); - #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) extern bool susfs_is_log_enabled; #endif // #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) @@ -61,27 +60,6 @@ extern void susfs_try_umount(void); #endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT #endif // #ifdef CONFIG_KSU_SUSFS -static bool should_umount(struct path *path) -{ - if (!path) { - return false; - } -#ifdef CONFIG_KSU_SUSFS - return susfs_is_mnt_devname_ksu(path); -#else - - if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) { - pr_info("ignore global mnt namespace process: %d\n", current_uid().val); - return false; - } - - if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) { - const char *fstype = path->mnt->mnt_sb->s_type->name; - return strcmp(fstype, "overlay") == 0; - } - return false; -#endif // #ifdef CONFIG_KSU_SUSFS -} #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT) static int ksu_path_umount(struct path *path, int flags) @@ -119,9 +97,9 @@ static int ksu_sys_umount(const char *mnt, int flags) #endif #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT -void try_umount(const char *mnt, bool check_mnt, int flags) +void try_umount(const char *mnt, int flags) #else -static void try_umount(const char *mnt, bool check_mnt, int flags) +static void try_umount(const char *mnt, int flags) #endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT { struct path path; @@ -137,12 +115,6 @@ static void try_umount(const char *mnt, bool check_mnt, int flags) return; } - // we are only interest in some specific mounts - if (check_mnt && !should_umount(&path)) { - path_put(&path); - return; - } - #if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG) if (susfs_is_log_enabled) { pr_info("susfs: umounting '%s'\n", mnt); @@ -184,16 +156,13 @@ static void umount_tw_func(struct callback_head *cb) saved = override_creds(tw->old_cred); } - // fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and - // filter the mountpoint whose target is `/data/adb` - try_umount("/odm", true, 0); - try_umount("/system", true, 0); - try_umount("/vendor", true, 0); - try_umount("/product", true, 0); - try_umount("/system_ext", true, 0); - try_umount("/data/adb/modules", false, MNT_DETACH); - // try umount ksu temp path - try_umount("/debug_ramdisk", false, MNT_DETACH); + struct mount_entry *entry; + down_read(&mount_list_lock); + list_for_each_entry(entry, &mount_list, list) { + pr_info("%s: unmounting: %s flags 0x%x\n", __func__, entry->umountable, entry->flags); + try_umount(entry->umountable, entry->flags); + } + up_read(&mount_list_lock); if (saved) revert_creds(saved); diff --git a/kernel/kernel_umount.h b/kernel/kernel_umount.h index 9ca23c5b..96cf56ce 100644 --- a/kernel/kernel_umount.h +++ b/kernel/kernel_umount.h @@ -2,6 +2,8 @@ #define __KSU_H_KERNEL_UMOUNT #include +#include +#include void ksu_kernel_umount_init(void); void ksu_kernel_umount_exit(void); @@ -11,4 +13,13 @@ void ksu_kernel_umount_exit(void); int ksu_handle_umount(uid_t old_uid, uid_t new_uid); #endif // #ifndef CONFIG_KSU_SUSFS -#endif \ No newline at end of file +// for the umount list +struct mount_entry { + char *umountable; + unsigned int flags; + struct list_head list; +}; +extern struct list_head mount_list; +extern struct rw_semaphore mount_list_lock; + +#endif diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 542b7cd9..3b96e5f5 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -593,6 +593,111 @@ static int do_nuke_ext4_sysfs(void __user *arg) return nuke_ext4_sysfs(mnt); } +struct list_head mount_list = LIST_HEAD_INIT(mount_list); +DECLARE_RWSEM(mount_list_lock); + +static int add_try_umount(void __user *arg) +{ + struct mount_entry *new_entry, *entry, *tmp; + struct ksu_add_try_umount_cmd cmd; + char buf[256] = {0}; + + if (copy_from_user(&cmd, arg, sizeof cmd)) + return -EFAULT; + + switch (cmd.mode) { + case KSU_UMOUNT_WIPE: { + struct mount_entry *entry, *tmp; + down_write(&mount_list_lock); + list_for_each_entry_safe(entry, tmp, &mount_list, list) { + pr_info("wipe_umount_list: removing entry: %s\n", entry->umountable); + list_del(&entry->list); + kfree(entry->umountable); + kfree(entry); + } + up_write(&mount_list_lock); + + return 0; + } + + case KSU_UMOUNT_ADD: { + long len = strncpy_from_user(buf, (const char __user *)cmd.arg, 256); + if (len <= 0) + return -EFAULT; + + buf[sizeof(buf) - 1] = '\0'; + + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + + new_entry->umountable = kstrdup(buf, GFP_KERNEL); + if (!new_entry->umountable) { + kfree(new_entry); + return -1; + } + + down_write(&mount_list_lock); + + // disallow dupes + // if this gets too many, we can consider moving this whole task to a kthread + list_for_each_entry(entry, &mount_list, list) { + if (!strcmp(entry->umountable, buf)) { + pr_info("cmd_add_try_umount: %s is already here!\n", buf); + up_write(&mount_list_lock); + kfree(new_entry->umountable); + kfree(new_entry); + return -1; + } + } + + // now check flags and add + // this also serves as a null check + if (cmd.flags) + new_entry->flags = cmd.flags; + else + new_entry->flags = 0; + + // debug + list_add(&new_entry->list, &mount_list); + up_write(&mount_list_lock); + pr_info("cmd_add_try_umount: %s added!\n", buf); + + return 0; + } + + // this is just strcmp'd wipe anyway + case KSU_UMOUNT_DEL: { + long len = strncpy_from_user(buf, (const char __user *)cmd.arg, sizeof(buf) - 1); + if (len <= 0) + return -EFAULT; + + buf[sizeof(buf) - 1] = '\0'; + + down_write(&mount_list_lock); + list_for_each_entry_safe(entry, tmp, &mount_list, list) { + if (!strcmp(entry->umountable, buf)) { + pr_info("cmd_add_try_umount: entry removed: %s\n", entry->umountable); + list_del(&entry->list); + kfree(entry->umountable); + kfree(entry); + } + } + up_write(&mount_list_lock); + + return 0; + } + + default: { + pr_err("cmd_add_try_umount: invalid operation %u\n", cmd.mode); + return -EINVAL; + } + + } // switch(cmd.mode) + + return 0; +} + // 100. GET_FULL_VERSION - Get full version string static int do_get_full_version(void __user *arg) { @@ -814,6 +919,7 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = { { .cmd = KSU_IOCTL_GET_WRAPPER_FD, .name = "GET_WRAPPER_FD", .handler = do_get_wrapper_fd, .perm_check = manager_or_root }, { .cmd = KSU_IOCTL_MANAGE_MARK, .name = "MANAGE_MARK", .handler = do_manage_mark, .perm_check = manager_or_root }, { .cmd = KSU_IOCTL_NUKE_EXT4_SYSFS, .name = "NUKE_EXT4_SYSFS", .handler = do_nuke_ext4_sysfs, .perm_check = manager_or_root }, + { .cmd = KSU_IOCTL_ADD_TRY_UMOUNT, .name = "ADD_TRY_UMOUNT", .handler = add_try_umount, .perm_check = manager_or_root }, { .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow}, { .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root}, { .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root}, diff --git a/kernel/supercalls.h b/kernel/supercalls.h index 53e8bfab..a66e4854 100644 --- a/kernel/supercalls.h +++ b/kernel/supercalls.h @@ -89,15 +89,26 @@ struct ksu_manage_mark_cmd { __u32 result; // Output: for get operation - mark status or reg_count }; -struct ksu_nuke_ext4_sysfs_cmd { - __aligned_u64 arg; // Input: mnt pointer -}; - #define KSU_MARK_GET 1 #define KSU_MARK_MARK 2 #define KSU_MARK_UNMARK 3 #define KSU_MARK_REFRESH 4 +struct ksu_nuke_ext4_sysfs_cmd { + __aligned_u64 arg; // Input: mnt pointer +}; + +struct ksu_add_try_umount_cmd { + __aligned_u64 arg; // char ptr, this is the mountpoint + __u32 flags; // this is the flag we use for it + __u8 mode; // denotes what to do with it 0:wipe_list 1:add_to_list 2:delete_entry +}; + +#define KSU_UMOUNT_WIPE 0 // ignore everything and wipe list +#define KSU_UMOUNT_ADD 1 // add entry (path + flags) +#define KSU_UMOUNT_DEL 2 // delete entry, strcmp + + // Other command structures struct ksu_get_full_version_cmd { char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string @@ -152,6 +163,7 @@ struct ksu_manual_su_cmd { #define KSU_IOCTL_GET_WRAPPER_FD _IOC(_IOC_WRITE, 'K', 15, 0) #define KSU_IOCTL_MANAGE_MARK _IOC(_IOC_READ|_IOC_WRITE, 'K', 16, 0) #define KSU_IOCTL_NUKE_EXT4_SYSFS _IOC(_IOC_WRITE, 'K', 17, 0) +#define KSU_IOCTL_ADD_TRY_UMOUNT _IOC(_IOC_WRITE, 'K', 18, 0) // Other IOCTL command definitions #define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0) #define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)