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

Commit cf968fd

Browse files
committed
kernel: core_hook: expose prctl interface for umount list (5ec1cff#16)
basically add try umount from susfs, but native to ksu TODO: add proper comments and shit
1 parent 2063484 commit cf968fd

File tree

2 files changed

+56
-37
lines changed

2 files changed

+56
-37
lines changed

kernel/core_hook.c

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ static void nuke_ext4_sysfs() {
237237
path_put(&path);
238238
}
239239

240+
struct mount_entry {
241+
char *umountable;
242+
struct list_head list;
243+
};
244+
LIST_HEAD(mount_list);
245+
240246
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
241247
unsigned long arg4, unsigned long arg5)
242248
{
@@ -268,6 +274,46 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
268274
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
269275
#endif
270276

277+
if (arg2 == CMD_ADD_TRY_UMOUNT) {
278+
struct mount_entry *new_entry, *entry;
279+
char buf[384];
280+
memzero_explicit(buf, 384); // overkill, init as empty is ok
281+
282+
if (copy_from_user(buf, (const char __user *)arg3, sizeof(buf) - 1)) {
283+
pr_err("cmd_add_try_umount: failed to copy user string\n");
284+
return 0;
285+
}
286+
buf[384 - 1] = '\0';
287+
288+
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
289+
if (!new_entry)
290+
return 0;
291+
292+
new_entry->umountable = kstrdup(buf, GFP_KERNEL);
293+
if (!new_entry->umountable) {
294+
kfree(new_entry);
295+
return 0;
296+
}
297+
298+
// disallow dupes
299+
// if this gets too many, we can consider moving this whole task to a kthread
300+
list_for_each_entry(entry, &mount_list, list) {
301+
if (!strcmp(entry->umountable, buf)) {
302+
pr_info("cmd_add_try_umount: %s is already here!\n", buf);
303+
return 0;
304+
}
305+
}
306+
307+
// debug
308+
// pr_info("cmd_add_try_umount: %s added!\n", buf);
309+
list_add(&new_entry->list, &mount_list);
310+
311+
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
312+
pr_err("prctl reply error, cmd: %lu\n", arg2);
313+
}
314+
return 0;
315+
}
316+
271317
if (arg2 == CMD_BECOME_MANAGER) {
272318
if (from_manager) {
273319
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
@@ -503,25 +549,6 @@ static bool is_non_appuid(kuid_t uid)
503549
return appid < FIRST_APPLICATION_UID;
504550
}
505551

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

548-
static void try_umount(const char *mnt, bool check_mnt, int flags)
575+
static void try_umount(const char *mnt, int flags)
549576
{
550577
struct path path;
551578
int err = kern_path(mnt, 0, &path);
@@ -559,12 +586,6 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
559586
return;
560587
}
561588

562-
// we are only interest in some specific mounts
563-
if (check_mnt && !should_umount(&path)) {
564-
path_put(&path);
565-
return;
566-
}
567-
568589
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT)
569590
ksu_path_umount(mnt, &path, flags);
570591
// dont call path_put here!!
@@ -579,6 +600,8 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
579600

580601
int ksu_handle_setuid(struct cred *new, const struct cred *old)
581602
{
603+
struct mount_entry *entry, *tmp;
604+
582605
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
583606
if (!ksu_module_mounted) {
584607
return 0;
@@ -641,17 +664,10 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
641664
current->pid);
642665
#endif
643666

644-
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
645-
// filter the mountpoint whose target is `/data/adb`
646-
try_umount("/odm", true, 0);
647-
try_umount("/system", true, 0);
648-
try_umount("/vendor", true, 0);
649-
try_umount("/product", true, 0);
650-
try_umount("/system_ext", true, 0);
651-
try_umount("/data/adb/modules", false, MNT_DETACH);
652-
653-
// try umount ksu temp path
654-
try_umount("/debug_ramdisk", false, MNT_DETACH);
667+
// don't free! keep on heap! this is used on subsequent setuid calls
668+
// if this is freed, we dont have anything to umount next
669+
list_for_each_entry_safe(entry, tmp, &mount_list, list)
670+
try_umount(entry->umountable, MNT_DETACH);
655671

656672
return 0;
657673
}
@@ -662,6 +678,7 @@ static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
662678
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
663679
return -ENOSYS;
664680
}
681+
665682
// kernel 4.4 and 4.9
666683
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
667684
static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,

kernel/ksu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#define CMD_ENABLE_SU 15
2626
#define CMD_GET_MANAGER_UID 16
2727

28+
#define CMD_ADD_TRY_UMOUNT 10001
29+
2830
#define EVENT_POST_FS_DATA 1
2931
#define EVENT_BOOT_COMPLETED 2
3032
#define EVENT_MODULE_MOUNTED 3

0 commit comments

Comments
 (0)