Skip to content
This repository was archived by the owner on Oct 30, 2025. It is now read-only.

Commit 1c2a3dc

Browse files
committed
kernel: core_hook: automate and refactor umount (tiann#2531)
monitors and lists all incoming mounts by hooking security_sb_mount this requires ksud to go back and use sys_mount instead of fsopen + move_mount this also fixes that MNT_DETACH issue. tiann#2386 (comment) Modules also can create an overlay with KSU devname and it will be added to the list. Context: aviraxp@c7facef#commitcomment-153941502 Stale: tiann#2531 Signed-off-by: backslashxx <[email protected]>
1 parent 8e6c99a commit 1c2a3dc

File tree

1 file changed

+77
-38
lines changed

1 file changed

+77
-38
lines changed

kernel/core_hook.c

Lines changed: 77 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -504,25 +504,6 @@ static bool is_appuid(kuid_t uid)
504504
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
505505
}
506506

507-
static bool should_umount(struct path *path)
508-
{
509-
if (!path) {
510-
return false;
511-
}
512-
513-
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
514-
pr_info("ignore global mnt namespace process: %d\n",
515-
current_uid().val);
516-
return false;
517-
}
518-
519-
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
520-
const char *fstype = path->mnt->mnt_sb->s_type->name;
521-
return strcmp(fstype, "overlay") == 0;
522-
}
523-
return false;
524-
}
525-
526507
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT)
527508
static void ksu_path_umount(const char *mnt, struct path *path, int flags)
528509
{
@@ -546,7 +527,7 @@ static void ksu_sys_umount(const char *mnt, int flags)
546527
}
547528
#endif // KSU_HAS_PATH_UMOUNT
548529

549-
static void try_umount(const char *mnt, bool check_mnt, int flags)
530+
static void try_umount(const char *mnt, int flags)
550531
{
551532
struct path path;
552533
int err = kern_path(mnt, 0, &path);
@@ -560,12 +541,6 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
560541
return;
561542
}
562543

563-
// we are only interest in some specific mounts
564-
if (check_mnt && !should_umount(&path)) {
565-
path_put(&path);
566-
return;
567-
}
568-
569544
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT)
570545
ksu_path_umount(mnt, &path, flags);
571546
// dont call path_put here!!
@@ -578,8 +553,16 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
578553
#endif
579554
}
580555

556+
struct mount_entry {
557+
char *umountable;
558+
struct list_head list;
559+
};
560+
LIST_HEAD(mount_list);
561+
581562
int ksu_handle_setuid(struct cred *new, const struct cred *old)
582563
{
564+
struct mount_entry *entry, *tmp;
565+
583566
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
584567
if (!ksu_module_mounted) {
585568
return 0;
@@ -624,33 +607,88 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
624607
current->pid);
625608
return 0;
626609
}
627-
#ifdef CONFIG_KSU_DEBUG
610+
628611
// umount the target mnt
629612
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
630613
current->pid);
631-
#endif
632614

633-
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
634-
// filter the mountpoint whose target is `/data/adb`
635-
try_umount("/odm", true, 0);
636-
try_umount("/system", true, 0);
637-
try_umount("/vendor", true, 0);
638-
try_umount("/product", true, 0);
639-
try_umount("/system_ext", true, 0);
640-
try_umount("/data/adb/modules", false, MNT_DETACH);
615+
list_for_each_entry_safe(entry, tmp, &mount_list, list) {
616+
try_umount(entry->umountable, MNT_DETACH);
617+
// don't free! keep on heap! this is used on subsequent setuid calls
618+
// if this is freed, we dont have anything to umount next
619+
// FIXME: might leak, refresh the list?
620+
}
641621

642-
// try umount ksu temp path
643-
try_umount("/debug_ramdisk", false, MNT_DETACH);
622+
return 0;
623+
}
644624

625+
static int ksu_mount_monitor(const char *dev_name, const char *dirname, const char *type)
626+
{
627+
628+
char *device_name_copy = kstrdup(dev_name, GFP_KERNEL);
629+
char *fstype_copy = kstrdup(type, GFP_KERNEL);
630+
char *dirname_copy = kstrdup(dirname, GFP_KERNEL);
631+
const char *string_fstype = fstype_copy ? fstype_copy : "(null)";
632+
const char *string_devname = device_name_copy ? device_name_copy : "(null)";
633+
struct mount_entry *new_entry;
634+
635+
if (unlikely(!dirname_copy)) // if dirname is null thats just questionable
636+
goto out;
637+
638+
/*
639+
* feel free to add your own patterns
640+
* default one is just KSU devname or it starts with /data/adb/modules
641+
*
642+
* for devicenamme and fstype string comparisons, make sure to use string_fstype/string_devname as NULL is being allowed.
643+
* using device_name_copy, fstype_copy can lead to null pointer dereference.
644+
*/
645+
if ((!strcmp(string_devname, "KSU"))
646+
// || !strcmp(dirname_copy, "/system/etc/hosts") // this is an example
647+
|| strstarts(dirname_copy, "/data/adb/modules") ) {
648+
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
649+
if (new_entry) {
650+
new_entry->umountable = kstrdup(dirname, GFP_KERNEL);
651+
list_add(&new_entry->list, &mount_list);
652+
pr_info("%s: devicename %s fstype: %s path: %s\n", __func__, string_devname, string_fstype, new_entry->umountable);
653+
}
654+
}
655+
out:
656+
kfree(device_name_copy);
657+
kfree(fstype_copy);
658+
kfree(dirname_copy);
645659
return 0;
646660
}
647661

662+
// for UL, hook on security.c ksu_sb_mount(dev_name, path, type, flags, data);
663+
int ksu_sb_mount(const char *dev_name, const struct path *path,
664+
const char *type, unsigned long flags, void *data)
665+
{
666+
/*
667+
* 384 is what throne_tracker uses, something sensible even for /data/app
668+
* we can pattern match revanced mounts even.
669+
* we are not really interested on mountpoints that are longer than that
670+
* this is now up to the modder for tweaking
671+
*/
672+
char buf[384];
673+
char *dir_name = d_path(path, buf, sizeof(buf));
674+
675+
if (dir_name && dir_name != buf) {
676+
#ifdef CONFIG_KSU_DEBUG
677+
pr_info("security_sb_mount: devname: %s path: %s type: %s \n", dev_name, dir_name, type);
678+
#endif
679+
return ksu_mount_monitor(dev_name, dir_name, type);
680+
} else {
681+
return 0;
682+
}
683+
}
684+
648685
static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
649686
unsigned long arg4, unsigned long arg5)
650687
{
651688
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
652689
return -ENOSYS;
653690
}
691+
654692
// kernel 4.4 and 4.9
655693
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
656694
static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
@@ -684,6 +722,7 @@ static struct security_hook_list ksu_hooks[] = {
684722
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
685723
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
686724
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
725+
LSM_HOOK_INIT(sb_mount, ksu_sb_mount),
687726
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
688727
LSM_HOOK_INIT(key_permission, ksu_key_permission)
689728
#endif

0 commit comments

Comments
 (0)