diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index a97e21b3..d72d68fe 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -39,6 +39,10 @@ void apply_kernelsu_rules() // we may need to do mount on shell allow(db, "kernel", "shell_data_file", "file", ALL); + // our ksud triggered by init + allow(db, "init", "adb_data_file", "file", "execute"); + allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL); + // copied from Magisk rules // suRights allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search"); diff --git a/kernel/sucompat.c b/kernel/sucompat.c index f360c08c..6a53c4b6 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -1,4 +1,9 @@ +#include +#include +#include +#include +#include #include #include #include @@ -101,17 +106,28 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) static const char app_process[] = "/system/bin/app_process"; static bool first_app_process = true; + static const char system_bin_init[] = "/system/bin/init"; + static int init_count = 0; filename = PT_REGS_PARM2(regs); if (IS_ERR(filename)) { return 0; } + if (!memcmp(filename->name, system_bin_init, sizeof(system_bin_init) - 1)) { + // /system/bin/init executed + if (++init_count == 2) { + // 1: /system/bin/init selinux_setup + // 2: /system/bin/init second_stage + pr_info("/system/bin/init second_stage executed\n"); + apply_kernelsu_rules(); + } + } + if (first_app_process && !memcmp(filename->name, app_process, sizeof(app_process) - 1)) { first_app_process = false; pr_info("exec app_process, /data prepared!\n"); - apply_kernelsu_rules(); ksu_load_allow_list(); } @@ -129,6 +145,91 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) return 0; } +static const char KERNEL_SU_RC[] = +"\n" + +"service ksud /data/adb/ksud post-fs-data\n" +" user root\n" +" seclabel u:r:su:s0\n" +" oneshot\n" +"\n" + +"\n" +"on post-fs-data\n" +" start ksud\n" +"\n" +"\n" +; + +static void unregister_read_kp(); + +static int read_handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct file *file; + char __user *buf; + size_t count; + + if (strcmp(current->comm, "init")) { + // we are only interest in `init` process + return 0; + } + + file = PT_REGS_PARM1(regs); + if (IS_ERR(file)) { + return 0; + } + + if (!d_is_reg(file->f_path.dentry)) { + return 0; + } + + const char *short_name = file->f_path.dentry->d_name.name; + if (strcmp(short_name, "vold.rc")) { + // we are only interest `init.rc` file name file + return 0; + } + char path[PATH_MAX]; + char* dpath = d_path(&file->f_path, path, PATH_MAX); + if (IS_ERR(dpath)) { + return 0; + } + + if (strcmp(dpath, "/system/etc/init/vold.rc")) { + return 0; + } + + // we only process the first read + static bool rc_inserted = false; + if (rc_inserted) { + // we don't need this kprobe, unregister it! + unregister_read_kp(); + return 0; + } + rc_inserted = true; + + // now we can sure that the init process is reading `/system/etc/init/hw/init.rc` + buf = PT_REGS_PARM2(regs); + count = PT_REGS_PARM3(regs); + size_t rc_count = strlen(KERNEL_SU_RC); + + pr_info("vfs_read: %s, comm: %s, count: %d, rc_count: %d\n", dpath, current->comm, count, rc_count); + + if (count < rc_count) { + pr_err("count: %d < rc_count: %d", count, rc_count); + return 0; + } + size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count); + if (ret) { + pr_err("copy ksud.rc failed: %d\n", ret); + return 0; + } + + PT_REGS_PARM2(regs) = buf + rc_count; + PT_REGS_PARM3(regs) = count - rc_count; + + return 0; +} + static struct kprobe faccessat_kp = { .symbol_name = "do_faccessat", .pre_handler = faccessat_handler_pre, @@ -144,6 +245,17 @@ static struct kprobe execve_kp = { .pre_handler = execve_handler_pre, }; +static struct kprobe vfs_read_kp = { + .symbol_name = "vfs_read", + .pre_handler = read_handler_pre, +}; + +static void unregister_read_kp() { + // todo: add it to kernel worker + // unregister_kprobe(&vfs_read_kp); + pr_info("unregister vfs_read kprobe!\n"); +} + // sucompat: permited process can execute 'su' to gain root access. void enable_sucompat() { @@ -155,4 +267,7 @@ void enable_sucompat() pr_info("newfstatat_kp: %d\n", ret); ret = register_kprobe(&faccessat_kp); pr_info("faccessat_kp: %d\n", ret); + + ret = register_kprobe(&vfs_read_kp); + pr_info("vfs_read_kp: %d\n", ret); }