diff --git a/kernel/ksud.c b/kernel/ksud.c index 9abb1fdb..0e93604a 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -22,8 +22,6 @@ #include "arch.h" #include "klog.h" // IWYU pragma: keep #include "ksud.h" - -#include "kernel_compat.h" #include "selinux/selinux.h" #include "syscall_hook_manager.h" @@ -50,7 +48,7 @@ static const char KERNEL_SU_RC[] = "on property:sys.boot_completed=1\n" " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" "\n" - + "\n"; static void stop_vfs_read_hook(); @@ -63,9 +61,9 @@ static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; #else bool ksu_vfs_read_hook __read_mostly = true; +bool ksu_execveat_hook __read_mostly = true; bool ksu_input_hook __read_mostly = true; #endif -bool ksu_execveat_hook __read_mostly = true; u32 ksu_file_sid; @@ -134,18 +132,95 @@ void on_boot_completed(void){ ksu_mark_running_process(); } +#define MAX_ARG_STRINGS 0x7FFFFFFF +struct user_arg_ptr { +#ifdef CONFIG_COMPAT + bool is_compat; +#endif + union { + const char __user *const __user *native; +#ifdef CONFIG_COMPAT + const compat_uptr_t __user *compat; +#endif + } ptr; +}; + +static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) +{ + const char __user *native; + +#ifdef CONFIG_COMPAT + if (unlikely(argv.is_compat)) { + compat_uptr_t compat; + + if (get_user(compat, argv.ptr.compat + nr)) + return ERR_PTR(-EFAULT); + + return compat_ptr(compat); + } +#endif + + if (get_user(native, argv.ptr.native + nr)) + return ERR_PTR(-EFAULT); + + return native; +} + +/* + * count() counts the number of strings in array ARGV. + */ + +/* + * Make sure old GCC compiler can use __maybe_unused, + * Test passed in 4.4.x ~ 4.9.x when use GCC. + */ + +static int __maybe_unused count(struct user_arg_ptr argv, int max) +{ + int i = 0; + + if (argv.ptr.native != NULL) { + for (;;) { + const char __user *p = get_user_arg_ptr(argv, i); + + if (!p) + break; + + if (IS_ERR(p)) + return -EFAULT; + + if (i >= max) + return -E2BIG; + ++i; + + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; + cond_resched(); + } + } + return i; +} + static void on_post_fs_data_cbfun(struct callback_head *cb) { on_post_fs_data(); } -static struct callback_head on_post_fs_data_cb = { .func = on_post_fs_data_cbfun }; +static struct callback_head on_post_fs_data_cb = { .func = + on_post_fs_data_cbfun }; -// since _ksud handler only uses argv and envp for comparisons -// this can probably work -// adapted from ksu_handle_execveat_ksud -static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const char *envp, size_t envp_len) +// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version +int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, + struct user_arg_ptr *argv, + struct user_arg_ptr *envp, int *flags) { +#ifndef KSU_KPROBES_HOOK + if (!ksu_execveat_hook) { + return 0; + } +#endif + struct filename *filename; + static const char app_process[] = "/system/bin/app_process"; static bool first_app_process = true; @@ -155,80 +230,96 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c static const char old_system_init[] = "/init"; static bool init_second_stage_executed = false; - // return early when disabled - if (!ksu_execveat_hook) + if (!filename_ptr) return 0; - if (!filename) + filename = *filename_ptr; + if (IS_ERR(filename)) { return 0; + } - // debug! remove me! - pr_info("%s: filename: %s argv1: %s envp_len: %zu\n", __func__, filename, argv1, envp_len); - -#ifdef CONFIG_KSU_DEBUG - const char *envp_n = envp; - unsigned int envc = 1; - do { - pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); - envp_n += strlen(envp_n) + 1; - envc++; - } while (envp_n < envp + 256); -#endif - - if (init_second_stage_executed) - goto first_app_process; - - // /system/bin/init with argv1 - if (!init_second_stage_executed - && (!memcmp(filename, system_bin_init, sizeof(system_bin_init) - 1))) { - if (argv1 && !strcmp(argv1, "second_stage")) { - pr_info("%s: /system/bin/init second_stage executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; + if (unlikely(!memcmp(filename->name, system_bin_init, + sizeof(system_bin_init) - 1) && + argv)) { + // /system/bin/init executed + int argc = count(*argv, MAX_ARG_STRINGS); + pr_info("/system/bin/init argc: %d\n", argc); + if (argc > 1 && !init_second_stage_executed) { + const char __user *p = get_user_arg_ptr(*argv, 1); + if (p && !IS_ERR(p)) { + char first_arg[16]; + strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); + pr_info("/system/bin/init first arg: %s\n", first_arg); + if (!strcmp(first_arg, "second_stage")) { + pr_info("/system/bin/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } else { + pr_err("/system/bin/init parse args err!\n"); + } + } + } else if (unlikely(!memcmp(filename->name, old_system_init, + sizeof(old_system_init) - 1) && + argv)) { + // /init executed + int argc = count(*argv, MAX_ARG_STRINGS); + pr_info("/init argc: %d\n", argc); + if (argc > 1 && !init_second_stage_executed) { + /* This applies to versions between Android 6 ~ 7 */ + const char __user *p = get_user_arg_ptr(*argv, 1); + if (p && !IS_ERR(p)) { + char first_arg[16]; + strncpy_from_user_nofault(first_arg, p, sizeof(first_arg)); + pr_info("/init first arg: %s\n", first_arg); + if (!strcmp(first_arg, "--second-stage")) { + pr_info("/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } else { + pr_err("/init parse args err!\n"); + } + } else if (argc == 1 && !init_second_stage_executed && envp) { + /* This applies to versions between Android 8 ~ 9 */ + int envc = count(*envp, MAX_ARG_STRINGS); + if (envc > 0) { + int n; + for (n = 1; n <= envc; n++) { + const char __user *p = get_user_arg_ptr(*envp, n); + if (!p || IS_ERR(p)) { + continue; + } + char env[256]; + // Reading environment variable strings from user space + if (strncpy_from_user_nofault(env, p, sizeof(env)) < 0) + continue; + // Parsing environment variable names and values + char *env_name = env; + char *env_value = strchr(env, '='); + if (env_value == NULL) + continue; + // Replace equal sign with string terminator + *env_value = '\0'; + env_value++; + // Check if the environment variable name and value are matching + if (!strcmp(env_name, "INIT_SECOND_STAGE") && + (!strcmp(env_value, "1") || + !strcmp(env_value, "true"))) { + pr_info("/init second_stage executed\n"); + apply_kernelsu_rules(); + init_second_stage_executed = true; + } + } + } } } - // /init with argv1 - if (!init_second_stage_executed - && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { - if (argv1 && !strcmp(argv1, "--second-stage")) { - pr_info("%s: /init --second-stage executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; - } - } - - if (!envp || !envp_len) - goto first_app_process; - - // /init without argv1/useless-argv1 but usable envp - // untested! TODO: test and debug me! - if (!init_second_stage_executed && (!memcmp(filename, old_system_init, sizeof(old_system_init) - 1))) { - - // we hunt for "INIT_SECOND_STAGE" - const char *envp_n = envp; - unsigned int envc = 1; - do { - if (strstarts(envp_n, "INIT_SECOND_STAGE")) - break; - envp_n += strlen(envp_n) + 1; - envc++; - } while (envp_n < envp + envp_len); - pr_info("%s: envp[%d]: %s\n", __func__, envc, envp_n); - - if (!strcmp(envp_n, "INIT_SECOND_STAGE=1") - || !strcmp(envp_n, "INIT_SECOND_STAGE=true") ) { - pr_info("%s: /init +envp: INIT_SECOND_STAGE executed\n", __func__); - apply_kernelsu_rules(); - init_second_stage_executed = true; - } - } - -first_app_process: - if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) { + if (unlikely(first_app_process && !memcmp(filename->name, app_process, + sizeof(app_process) - 1))) { first_app_process = false; - pr_info("%s: exec app_process, /data prepared, second_stage: %d\n", __func__, init_second_stage_executed); - + pr_info("exec app_process, /data prepared, second_stage: %d\n", + init_second_stage_executed); struct task_struct *init_task; rcu_read_lock(); init_task = rcu_dereference(current->real_parent); @@ -243,72 +334,18 @@ first_app_process: return 0; } -int ksu_handle_pre_ksud(const char *filename) -{ - if (likely(!ksu_execveat_hook)) - return 0; - - // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) - // return 0; - if (likely(strcmp(filename, "/system/bin/init") && strcmp(filename, "/init") - && !strstarts(filename, "/system/bin/app_process") )) - return 0; - - if (!current || !current->mm) - return 0; - - // https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/mm_types.h#L429 - // unsigned long arg_start, arg_end, env_start, env_end; - unsigned long arg_start = current->mm->arg_start; - unsigned long arg_end = current->mm->arg_end; - unsigned long env_start = current->mm->env_start; - unsigned long env_end = current->mm->env_end; - - size_t arg_len = arg_end - arg_start; - size_t envp_len = env_end - env_start; - - if (arg_len <= 0 || envp_len <= 0) // this wont make sense, filter it - return 0; - - #define ARGV_MAX 32 // this is enough for argv1 - #define ENVP_MAX 256 // this is enough for INIT_SECOND_STAGE - char args[ARGV_MAX]; - size_t argv_copy_len = (arg_len > ARGV_MAX) ? ARGV_MAX : arg_len; - char envp[ENVP_MAX]; - size_t envp_copy_len = (envp_len > ENVP_MAX) ? ENVP_MAX : envp_len; - - // we cant use strncpy on here, else it will truncate once it sees \0 - if (ksu_copy_from_user_retry(args, (void __user *)arg_start, argv_copy_len)) - return 0; - - if (ksu_copy_from_user_retry(envp, (void __user *)env_start, envp_copy_len)) - return 0; - - args[ARGV_MAX - 1] = '\0'; - envp[ENVP_MAX - 1] = '\0'; - - // we only need argv1 ! - // abuse strlen here since it only gets length up to \0 - char *argv1 = args + strlen(args) + 1; - if (argv1 >= args + argv_copy_len) // out of bounds! - argv1 = ""; - - return ksu_handle_bprm_ksud(filename, argv1, envp, envp_copy_len); -} - static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *); static ssize_t (*orig_read_iter)(struct kiocb *, struct iov_iter *); static struct file_operations fops_proxy; static ssize_t read_count_append = 0; static ssize_t read_proxy(struct file *file, char __user *buf, size_t count, - loff_t *pos) + loff_t *pos) { bool first_read = file->f_pos == 0; ssize_t ret = orig_read(file, buf, count, pos); if (first_read) { - pr_info("read_proxy append %ld + %ld\n", ret, - read_count_append); + pr_info("read_proxy append %ld + %ld\n", ret, read_count_append); ret += read_count_append; } return ret; @@ -319,20 +356,19 @@ static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to) bool first_read = iocb->ki_pos == 0; ssize_t ret = orig_read_iter(iocb, to); if (first_read) { - pr_info("read_iter_proxy append %ld + %ld\n", ret, - read_count_append); + pr_info("read_iter_proxy append %ld + %ld\n", ret, read_count_append); ret += read_count_append; } return ret; } -int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, - size_t *count_ptr, loff_t **pos) +static int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos) { #ifndef KSU_KPROBES_HOOK - if (!ksu_vfs_read_hook) { - return 0; - } + if (!ksu_vfs_read_hook) { + return 0; + } #endif struct file *file; char __user *buf; @@ -385,7 +421,7 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, size_t rc_count = strlen(KERNEL_SU_RC); pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath, - current->comm, count, rc_count); + current->comm, count, rc_count); if (count < rc_count) { pr_err("count: %zu < rc_count: %zu\n", count, rc_count); @@ -420,8 +456,8 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, return 0; } -int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, - size_t *count_ptr) +static int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, + size_t *count_ptr) { struct file *file = fget(fd); if (!file) { @@ -440,12 +476,12 @@ static bool is_volumedown_enough(unsigned int count) } int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, - int *value) + int *value) { #ifndef KSU_KPROBES_HOOK - if (!ksu_input_hook) { - return 0; - } + if (!ksu_input_hook) { + return 0; + } #endif if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) { int val = *value; @@ -485,123 +521,27 @@ bool ksu_is_safe_mode() } #ifdef KSU_KPROBES_HOOK + static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { - /* - asmlinkage int sys_execve(const char __user *filenamei, - const char __user *const __user *argv, - const char __user *const __user *envp, struct pt_regs *regs) - */ struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user *filename_user = (const char __user *)PT_REGS_PARM1(real_regs); - const char __user *const __user *__argv = (const char __user *const __user *)PT_REGS_PARM2(real_regs); - const char __user *const __user *__envp = (const char __user *const __user *)PT_REGS_PARM3(real_regs); + const char __user **filename_user = + (const char **)&PT_REGS_PARM1(real_regs); + const char __user *const __user *__argv = + (const char __user *const __user *)PT_REGS_PARM2(real_regs); + struct user_arg_ptr argv = { .ptr.native = __argv }; + struct filename filename_in, *filename_p; char path[32]; if (!filename_user) return 0; -// filename stage - if (ksu_copy_from_user_retry(path, filename_user, sizeof(path))) - return 0; + memset(path, 0, sizeof(path)); + strncpy_from_user_nofault(path, *filename_user, 32); + filename_in.name = path; - path[sizeof(path) - 1] = '\0'; - - // not /system/bin/init, not /init, not /system/bin/app_process (64/32 thingy) - // we dont care !! - if (likely(strcmp(path, "/system/bin/init") && strcmp(path, "/init") - && !strstarts(path, "/system/bin/app_process") )) - return 0; - -// argv stage - char argv1[32] = {0}; - // memzero_explicit(argv1, 32); - if (__argv) { - const char __user *arg1_user = NULL; - // grab argv[1] pointer - // this looks like - /* - * 0x1000 ./program << this is __argv - * 0x1001 -o - * 0x1002 arg - */ - if (ksu_copy_from_user_retry(&arg1_user, __argv + 1, sizeof(arg1_user))) - goto no_argv1; // copy argv[1] pointer fail, probably no argv1 !! - - if (arg1_user) - ksu_copy_from_user_retry(argv1, arg1_user, sizeof(argv1)); - } - -no_argv1: - argv1[sizeof(argv1) - 1] = '\0'; - -// envp stage - #define ENVP_MAX 256 - char envp[ENVP_MAX] = {0}; - char *dst = envp; - size_t envp_len = 0; - int i = 0; // to track user pointer offset from __envp - - // memzero_explicit(envp, ENVP_MAX); - - if (__envp) { - do { - const char __user *env_entry_user = NULL; - // this is also like argv above - /* - * 0x1001 PATH=/bin - * 0x1002 VARIABLE=value - * 0x1002 some_more_env_var=1 - */ - - // check if pointer exists - if (ksu_copy_from_user_retry(&env_entry_user, __envp + i, sizeof(env_entry_user))) - break; - - // check if no more env entry - if (!env_entry_user) - break; - - // probably redundant to while condition but ok - if (envp_len >= ENVP_MAX - 1) - break; - - // copy strings from env_entry_user pointer that we collected - // also break if failed - if (ksu_copy_from_user_retry(dst, env_entry_user, ENVP_MAX - envp_len)) - break; - - // get the length of that new copy above - // get lngth of dst as far as ENVP_MAX - current collected envp_len - size_t len = strnlen(dst, ENVP_MAX - envp_len); - if (envp_len + len + 1 > ENVP_MAX) - break; // if more than 255 bytes, bail - - dst[len] = '\0'; - // collect total number of copied strings - envp_len = envp_len + len + 1; - // increment dst address since we need to put something on next iter - dst = dst + len + 1; - // pointer walk, __envp + i - i++; - } while (envp_len < ENVP_MAX); - } - - /* - at this point, we shoul've collected envp from - * 0x1001 PATH=/bin - * 0x1002 VARIABLE=value - * 0x1002 some_more_env_var=1 - to - * 0x1234 PATH=/bin\0VARIABLE=value\0some_more_env_var=1\0\0\0\0 - */ - - envp[ENVP_MAX - 1] = '\0'; - -#ifdef CONFIG_KSU_DEBUG - pr_info("%s: filename: %s argv[1]:%s envp_len: %zu\n", __func__, path, argv1, envp_len); -#endif - return ksu_handle_bprm_ksud(path, argv1, envp, envp_len); + filename_p = &filename_in; + return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL); } static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) @@ -615,7 +555,7 @@ static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) } static int input_handle_event_handler_pre(struct kprobe *p, - struct pt_regs *regs) + struct pt_regs *regs) { unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs); unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs); @@ -638,7 +578,6 @@ static struct kprobe input_event_kp = { .pre_handler = input_handle_event_handler_pre, }; - static void do_stop_vfs_read_hook(struct work_struct *work) { unregister_kprobe(&vfs_read_kp); @@ -661,8 +600,8 @@ static void stop_vfs_read_hook() bool ret = schedule_work(&stop_vfs_read_work); pr_info("unregister vfs_read kprobe: %d!\n", ret); #else - ksu_vfs_read_hook = false; - pr_info("stop vfs_read_hook\n"); + ksu_vfs_read_hook = false; + pr_info("stop vfs_read_hook\n"); #endif } @@ -672,9 +611,9 @@ static void stop_execve_hook() bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else - pr_info("stop execve_hook\n"); -#endif ksu_execveat_hook = false; + pr_info("stop execve_hook\n"); +#endif } static void stop_input_hook() @@ -688,8 +627,8 @@ static void stop_input_hook() bool ret = schedule_work(&stop_input_hook_work); pr_info("unregister input kprobe: %d!\n", ret); #else - ksu_input_hook = false; - pr_info("stop input_hook\n"); + ksu_input_hook = false; + pr_info("stop input_hook\n"); #endif } @@ -724,4 +663,4 @@ void ksu_ksud_exit() #endif is_boot_phase = false; -} +} \ No newline at end of file diff --git a/kernel/ksud.h b/kernel/ksud.h index 35ac67e8..271c354a 100644 --- a/kernel/ksud.h +++ b/kernel/ksud.h @@ -16,7 +16,4 @@ extern u32 ksu_file_sid; extern bool ksu_module_mounted; extern bool ksu_boot_completed; -extern bool ksu_execveat_hook __read_mostly; -extern int ksu_handle_pre_ksud(const char *filename); - #endif diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index dac853b0..98d74759 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -145,45 +145,17 @@ void apply_kernelsu_rules() #define CMD_TYPE_CHANGE 8 #define CMD_GENFSCON 9 -#ifdef CONFIG_64BIT struct sepol_data { u32 cmd; u32 subcmd; - u64 field_sepol1; - u64 field_sepol2; - u64 field_sepol3; - u64 field_sepol4; - u64 field_sepol5; - u64 field_sepol6; - u64 field_sepol7; + char __user *sepol1; + char __user *sepol2; + char __user *sepol3; + char __user *sepol4; + char __user *sepol5; + char __user *sepol6; + char __user *sepol7; }; -#ifdef CONFIG_COMPAT -extern bool ksu_is_compat __read_mostly; -struct sepol_compat_data { - u32 cmd; - u32 subcmd; - u32 field_sepol1; - u32 field_sepol2; - u32 field_sepol3; - u32 field_sepol4; - u32 field_sepol5; - u32 field_sepol6; - u32 field_sepol7; -}; -#endif // CONFIG_COMPAT -#else -struct sepol_data { - u32 cmd; - u32 subcmd; - u32 field_sepol1; - u32 field_sepol2; - u32 field_sepol3; - u32 field_sepol4; - u32 field_sepol5; - u32 field_sepol6; - u32 field_sepol7; -}; -#endif // CONFIG_64BIT static int get_object(char *buf, char __user *user_object, size_t buf_sz, char **object) @@ -233,59 +205,15 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) if (!getenforce()) { pr_info("SELinux permissive or disabled when handle policy!\n"); } - - u32 cmd, subcmd; - char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6, *sepol7; -#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT) - if (unlikely(ksu_is_compat)) { - struct sepol_compat_data compat_data; - if (copy_from_user(&compat_data, arg4, sizeof(struct sepol_compat_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = compat_ptr(compat_data.field_sepol1); - sepol2 = compat_ptr(compat_data.field_sepol2); - sepol3 = compat_ptr(compat_data.field_sepol3); - sepol4 = compat_ptr(compat_data.field_sepol4); - sepol5 = compat_ptr(compat_data.field_sepol5); - sepol6 = compat_ptr(compat_data.field_sepol6); - sepol7 = compat_ptr(compat_data.field_sepol7); - cmd = compat_data.cmd; - subcmd = compat_data.subcmd; - } else { - struct sepol_data data; - if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { - pr_err("sepol: copy sepol_data failed.\n"); - return -1; - } - sepol1 = data.field_sepol1; - sepol2 = data.field_sepol2; - sepol3 = data.field_sepol3; - sepol4 = data.field_sepol4; - sepol5 = data.field_sepol5; - sepol6 = data.field_sepol6; - sepol7 = data.field_sepol7; - cmd = data.cmd; - subcmd = data.subcmd; - } -#else - // basically for full native, say (64BIT=y COMPAT=n) || (64BIT=n) struct sepol_data data; if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) { pr_err("sepol: copy sepol_data failed.\n"); return -EINVAL; } - sepol1 = data.field_sepol1; - sepol2 = data.field_sepol2; - sepol3 = data.field_sepol3; - sepol4 = data.field_sepol4; - sepol5 = data.field_sepol5; - sepol6 = data.field_sepol6; - sepol7 = data.field_sepol7; - cmd = data.cmd; - subcmd = data.subcmd; -#endif + + u32 cmd = data.cmd; + u32 subcmd = data.subcmd; mutex_lock(&ksu_rules); @@ -299,22 +227,22 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char perm_buf[MAX_SEPOL_LEN]; char *s, *t, *c, *p; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { + if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { + if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { + if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } - if (get_object(perm_buf, sepol4, sizeof(perm_buf), &p) < + if (get_object(perm_buf, data.sepol4, sizeof(perm_buf), &p) < 0) { pr_err("sepol: copy perm failed.\n"); goto exit; @@ -344,24 +272,24 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char perm_set[MAX_SEPOL_LEN]; char *s, *t, *c; - if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) { + if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } - if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) { + if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } - if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) { + if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } - if (strncpy_from_user(operation, sepol4, + if (strncpy_from_user(operation, data.sepol4, sizeof(operation)) < 0) { pr_err("sepol: copy operation failed.\n"); goto exit; } - if (strncpy_from_user(perm_set, sepol5, sizeof(perm_set)) < + if (strncpy_from_user(perm_set, data.sepol5, sizeof(perm_set)) < 0) { pr_err("sepol: copy perm_set failed.\n"); goto exit; @@ -381,7 +309,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) } else if (cmd == CMD_TYPE_STATE) { char src[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } @@ -401,11 +329,11 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char type[MAX_SEPOL_LEN]; char attr[MAX_SEPOL_LEN]; - if (strncpy_from_user(type, sepol1, sizeof(type)) < 0) { + if (strncpy_from_user(type, data.sepol1, sizeof(type)) < 0) { pr_err("sepol: copy type failed.\n"); goto exit; } - if (strncpy_from_user(attr, sepol2, sizeof(attr)) < 0) { + if (strncpy_from_user(attr, data.sepol2, sizeof(attr)) < 0) { pr_err("sepol: copy attr failed.\n"); goto exit; } @@ -425,7 +353,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) } else if (cmd == CMD_ATTR) { char attr[MAX_SEPOL_LEN]; - if (strncpy_from_user(attr, sepol1, sizeof(attr)) < 0) { + if (strncpy_from_user(attr, data.sepol1, sizeof(attr)) < 0) { pr_err("sepol: copy attr failed.\n"); goto exit; } @@ -442,28 +370,28 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char default_type[MAX_SEPOL_LEN]; char object[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { + if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { + if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } - if (strncpy_from_user(default_type, sepol4, + if (strncpy_from_user(default_type, data.sepol4, sizeof(default_type)) < 0) { pr_err("sepol: copy default_type failed.\n"); goto exit; } char *real_object; - if (sepol5 == NULL) { + if (data.sepol5 == NULL) { real_object = NULL; } else { - if (strncpy_from_user(object, sepol5, + if (strncpy_from_user(object, data.sepol5, sizeof(object)) < 0) { pr_err("sepol: copy object failed.\n"); goto exit; @@ -482,19 +410,19 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char cls[MAX_SEPOL_LEN]; char default_type[MAX_SEPOL_LEN]; - if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) { + if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) { pr_err("sepol: copy src failed.\n"); goto exit; } - if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) { + if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) { pr_err("sepol: copy tgt failed.\n"); goto exit; } - if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) { + if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) { pr_err("sepol: copy cls failed.\n"); goto exit; } - if (strncpy_from_user(default_type, sepol4, + if (strncpy_from_user(default_type, data.sepol4, sizeof(default_type)) < 0) { pr_err("sepol: copy default_type failed.\n"); goto exit; @@ -515,15 +443,15 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4) char name[MAX_SEPOL_LEN]; char path[MAX_SEPOL_LEN]; char context[MAX_SEPOL_LEN]; - if (strncpy_from_user(name, sepol1, sizeof(name)) < 0) { + if (strncpy_from_user(name, data.sepol1, sizeof(name)) < 0) { pr_err("sepol: copy name failed.\n"); goto exit; } - if (strncpy_from_user(path, sepol2, sizeof(path)) < 0) { + if (strncpy_from_user(path, data.sepol2, sizeof(path)) < 0) { pr_err("sepol: copy path failed.\n"); goto exit; } - if (strncpy_from_user(context, sepol3, sizeof(context)) < + if (strncpy_from_user(context, data.sepol3, sizeof(context)) < 0) { pr_err("sepol: copy context failed.\n"); goto exit; @@ -546,4 +474,4 @@ exit: reset_avc_cache(); return ret; -} +} \ No newline at end of file diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 0aca8f76..713743bb 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -147,60 +147,6 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) return 0; } -// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code -int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, - void *__never_use_argv, void *__never_use_envp, - int *__never_use_flags) -{ - struct filename *filename; - const char sh[] = KSUD_PATH; - const char su[] = SU_PATH; - -#ifdef KSU_MANUAL_HOOK - if (!ksu_su_compat_enabled) { - return 0; - } -#endif - if (unlikely(!filename_ptr)) - return 0; - - filename = *filename_ptr; - if (IS_ERR(filename)) { - return 0; - } - - if (likely(memcmp(filename->name, su, sizeof(su)))) - return 0; - -#if __SULOG_GATE - bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val); - ksu_sulog_report_syscall(current_uid().val, NULL, "execve", filename->name); - - if (!is_allowed) { - return 0; - } - - ksu_sulog_report_su_attempt(current_uid().val, NULL, filename->name, is_allowed); -#else - if (!ksu_is_allow_uid_for_current(current_uid().val)) { - return 0; - } -#endif - - pr_info("do_execveat_common su found\n"); - memcpy((void *)filename->name, sh, sizeof(sh)); - - escape_with_root_profile(); - - return 0; -} - -int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, - void *envp, int *flags) -{ - return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, flags); -} - int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, void *__never_use_argv, void *__never_use_envp, int *__never_use_flags) diff --git a/kernel/syscall_hook_manager.c b/kernel/syscall_hook_manager.c index 79df3804..fa196126 100644 --- a/kernel/syscall_hook_manager.c +++ b/kernel/syscall_hook_manager.c @@ -209,7 +209,6 @@ static inline bool check_syscall_fastpath(int nr) case __NR_execve: case __NR_setresuid: case __NR_faccessat2: - case __NR_execveat: case __NR_clone: case __NR_clone3: return true; @@ -242,10 +241,6 @@ int ksu_handle_init_mark_tracker(int *fd, const char __user **filename_user, #include "manual_su.h" #endif -#ifdef CONFIG_COMPAT -bool ksu_is_compat __read_mostly = false; -#endif - #ifndef LOOKUP_FOLLOW #define LOOKUP_FOLLOW 0x0001 #endif @@ -266,48 +261,6 @@ static inline void ksu_handle_inode_permission(struct pt_regs *regs) } } -static inline void ksu_handle_bprm_check_security(struct pt_regs *regs, long id) -{ - const char __user *filename; - char path_buf[256]; - - if (id == __NR_execve) - filename = (const char __user *)PT_REGS_PARM1(regs); - else /* __NR_execveat */ - filename = (const char __user *)PT_REGS_PARM2(regs); - - if (!ksu_execveat_hook) - return; - - memset(path_buf, 0, sizeof(path_buf)); - strncpy_from_user_nofault(path_buf, filename, sizeof(path_buf)); - -#ifdef CONFIG_COMPAT - static bool compat_check_done __read_mostly = false; - if (unlikely(!compat_check_done) && - unlikely(!strcmp(path_buf, "/data/adb/ksud"))) { - char buf[4]; - struct file *file = filp_open(path_buf, O_RDONLY, 0); - if (!IS_ERR(file)) { - loff_t pos = 0; - kernel_read(file, buf, 4, &pos); - if (!memcmp(buf, "\x7f\x45\x4c\x46", 4)) { - char elf_class; - pos = 4; - kernel_read(file, &elf_class, 1, &pos); - if (elf_class == 0x01) - ksu_is_compat = true; - pr_info("%s: %s ELF magic found! ksu_is_compat: %d\n", - __func__, path_buf, ksu_is_compat); - compat_check_done = true; - } - filp_close(file, NULL); - } - } -#endif - ksu_handle_pre_ksud(path_buf); -} - static inline void ksu_handle_task_alloc(struct pt_regs *regs) { #ifdef CONFIG_KSU_MANUAL_SU @@ -371,10 +324,6 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id) if (id == __NR_faccessat || id == __NR_faccessat2) return ksu_handle_inode_permission(regs); - // Handle bprm_check_security via execve/execveat - if (id == __NR_execve || id == __NR_execveat) - return ksu_handle_bprm_check_security(regs, id); - #ifdef CONFIG_KSU_MANUAL_SU // Handle task_alloc via clone/fork if (id == __NR_clone || id == __NR_clone3) diff --git a/kernel/syscall_hook_manager.h b/kernel/syscall_hook_manager.h index 19b4e24f..b19d617b 100644 --- a/kernel/syscall_hook_manager.h +++ b/kernel/syscall_hook_manager.h @@ -15,8 +15,6 @@ #define DEVPTS_SUPER_MAGIC 0x1cd1 #endif -extern bool ksu_is_compat __read_mostly; - extern int __ksu_handle_devpts(struct inode *inode); // sucompat.c // Hook manager initialization and cleanup