diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c index 841a0e52..db47f8eb 100644 --- a/kernel/kernel_compat.c +++ b/kernel/kernel_compat.c @@ -173,3 +173,26 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, return ret; } #endif + +static inline int ksu_access_ok(const void *addr, unsigned long size) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + return access_ok(addr, size); +#else + return access_ok(VERIFY_READ, addr, size); +#endif +} + +long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr, + long count) +{ + long ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count); + if (likely(ret >= 0)) + return ret; + + // we faulted! fallback to slow path + if (unlikely(!ksu_access_ok(unsafe_addr, count))) + return -EFAULT; + + return strncpy_from_user(dst, unsafe_addr, count); +} diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index 6d79f7ed..c85e9e2c 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -23,6 +23,9 @@ extern long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, long count); +extern long ksu_strncpy_from_user_retry(char *dst, + const void __user *unsafe_addr, + long count); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) extern struct key *init_session_keyring; diff --git a/kernel/ksud.c b/kernel/ksud.c index b30c69d0..2543239d 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -197,12 +197,11 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, const char __user *p = get_user_arg_ptr(*argv, 1); if (p && !IS_ERR(p)) { char first_arg[16]; - ksu_strncpy_from_user_nofault( + ksu_strncpy_from_user_retry( first_arg, p, sizeof(first_arg)); pr_info("/system/bin/init first arg: %s\n", first_arg); - if (!strcmp(first_arg, "second_stage") || - (argc == 2 && !strcmp(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; @@ -223,7 +222,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, const char __user *p = get_user_arg_ptr(*argv, 1); if (p && !IS_ERR(p)) { char first_arg[16]; - ksu_strncpy_from_user_nofault( + ksu_strncpy_from_user_retry( first_arg, p, sizeof(first_arg)); pr_info("/init first arg: %s\n", first_arg); if (!strcmp(first_arg, "--second-stage")) { @@ -248,7 +247,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, } char env[256]; // Reading environment variable strings from user space - if (ksu_strncpy_from_user_nofault( + if (ksu_strncpy_from_user_retry( env, p, sizeof(env)) < 0) continue; // Parsing environment variable names and values