kernel: rework umount with task_work

This commit is contained in:
weishu
2025-11-04 13:31:45 +00:00
committed by ShirkNeko
parent 801bcb0e1f
commit 1439e486a1

View File

@@ -1,4 +1,6 @@
#include "linux/slab.h" #include <linux/slab.h>
#include <linux/task_work.h>
#include <linux/thread_info.h>
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/capability.h> #include <linux/capability.h>
@@ -508,8 +510,44 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
ksu_umount_mnt(&path, flags); ksu_umount_mnt(&path, flags);
} }
struct umount_tw {
struct callback_head cb;
const struct cred *old_cred;
};
static void umount_tw_func(struct callback_head *cb)
{
struct umount_tw *tw = container_of(cb, struct umount_tw, cb);
const struct cred *saved = NULL;
if (tw->old_cred) {
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("/data/adb/kpm", false, MNT_DETACH);
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
if (saved)
revert_creds(saved);
if (tw->old_cred)
put_cred(tw->old_cred);
kfree(tw);
}
int ksu_handle_setuid(struct cred *new, const struct cred *old) int ksu_handle_setuid(struct cred *new, const struct cred *old)
{ {
struct umount_tw *tw;
if (!new || !old) { if (!new || !old) {
return 0; return 0;
} }
@@ -587,19 +625,21 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, current->pid); pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, current->pid);
#endif #endif
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and tw = kmalloc(sizeof(*tw), GFP_ATOMIC);
// filter the mountpoint whose target is `/data/adb` if (!tw)
try_umount("/odm", true, 0); return 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); tw->old_cred = get_current_cred();
try_umount("/data/adb/kpm", false, MNT_DETACH); tw->cb.func = umount_tw_func;
// try umount ksu temp path int err = task_work_add(current, &tw->cb, TWA_RESUME);
try_umount("/debug_ramdisk", false, MNT_DETACH); if (err) {
if (tw->old_cred) {
put_cred(tw->old_cred);
}
kfree(tw);
pr_warn("unmount add task_work failed\n");
}
return 0; return 0;
} }
@@ -653,7 +693,8 @@ static struct kprobe reboot_kp = {
}; };
// 2. cap_task_fix_setuid hook for handling setuid // 2. cap_task_fix_setuid hook for handling setuid
static int cap_task_fix_setuid_handler_pre(struct kprobe *p, struct pt_regs *regs) static int cap_task_fix_setuid_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{ {
struct cred *new = (struct cred *)PT_REGS_PARM1(regs); struct cred *new = (struct cred *)PT_REGS_PARM1(regs);
const struct cred *old = (const struct cred *)PT_REGS_PARM2(regs); const struct cred *old = (const struct cred *)PT_REGS_PARM2(regs);