From 5e64eee624086202c64f67764defd4a8911c6b4c Mon Sep 17 00:00:00 2001 From: weishu Date: Thu, 27 Nov 2025 03:17:59 +0000 Subject: [PATCH] kernel: Fix execve filename access on ARM64 --- kernel/Makefile | 1 + kernel/ksud.c | 26 +++++++++-- kernel/sucompat.c | 87 +---------------------------------- kernel/syscall_hook_manager.c | 13 +++++- kernel/util.c | 76 ++++++++++++++++++++++++++++++ kernel/util.h | 24 ++++++++++ 6 files changed, 135 insertions(+), 92 deletions(-) create mode 100644 kernel/util.c create mode 100644 kernel/util.h diff --git a/kernel/Makefile b/kernel/Makefile index bf4ffc2c..ee5a5845 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,6 +17,7 @@ kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += seccomp_cache.o kernelsu-objs += file_wrapper.o +kernelsu-objs += util.o kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o diff --git a/kernel/ksud.c b/kernel/ksud.c index 59f92798..72164c07 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -22,6 +22,7 @@ #include "arch.h" #include "klog.h" // IWYU pragma: keep #include "ksud.h" +#include "util.h" #include "selinux/selinux.h" #include "throne_tracker.h" @@ -88,11 +89,11 @@ void on_post_fs_data(void) is_boot_phase = false; ksu_file_sid = ksu_get_ksu_file_sid(); - pr_info("ksu_file sid: %d\n", ksu_file_sid); + pr_info("ksu_file sid: %d\n", ksu_file_sid); } extern void ext4_unregister_sysfs(struct super_block *sb); -int nuke_ext4_sysfs(const char* mnt) +int nuke_ext4_sysfs(const char *mnt) { #ifdef CONFIG_EXT4_FS struct path path; @@ -117,12 +118,14 @@ int nuke_ext4_sysfs(const char* mnt) #endif } -void on_module_mounted(void){ +void on_module_mounted(void) +{ pr_info("on_module_mounted!\n"); ksu_module_mounted = true; } -void on_boot_completed(void){ +void on_boot_completed(void) +{ ksu_boot_completed = true; pr_info("on_boot_completed!\n"); track_throne(true); @@ -527,12 +530,25 @@ static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) struct user_arg_ptr argv = { .ptr.native = __argv }; struct filename filename_in, *filename_p; char path[32]; + long ret; + unsigned long addr; + const char __user *fn; if (!filename_user) return 0; + addr = untagged_addr((unsigned long)*filename_user); + fn = (const char __user *)addr; + memset(path, 0, sizeof(path)); - strncpy_from_user_nofault(path, *filename_user, 32); + ret = strncpy_from_user_nofault(path, fn, 32); + if (ret < 0 && try_set_access_flag(addr)) { + ret = strncpy_from_user_nofault(path, fn, 32); + } + if (ret < 0) { + pr_err("Access filename failed for execve_handler_pre\n"); + return 0; + } filename_in.name = path; filename_p = &filename_in; diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 09c4a5f8..dcd97f19 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -18,28 +18,13 @@ #include "ksud.h" #include "sucompat.h" #include "app_profile.h" +#include "util.h" #include "sulog.h" #define SU_PATH "/system/bin/su" #define SH_PATH "/system/bin/sh" -#ifndef preempt_enable_no_resched_notrace -#define preempt_enable_no_resched_notrace() \ -do { \ - barrier(); \ - __preempt_count_dec(); \ -} while (0) -#endif - -#ifndef preempt_disable_notrace -#define preempt_disable_notrace() \ -do { \ - __preempt_count_inc(); \ - barrier(); \ -} while (0) -#endif - bool ksu_su_compat_enabled __read_mostly = true; static int su_compat_feature_get(u64 *value) @@ -86,76 +71,6 @@ static char __user *ksud_user_path(void) return userspace_stack_buffer(ksud_path, sizeof(ksud_path)); } -static bool try_set_access_flag(unsigned long addr) -{ -#ifdef CONFIG_ARM64 - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - pte_t *ptep, pte; - spinlock_t *ptl; - bool ret = false; - - if (!mm) - return false; - - if (!mmap_read_trylock(mm)) - return false; - - vma = find_vma(mm, addr); - if (!vma || addr < vma->vm_start) - goto out_unlock; - - pgd = pgd_offset(mm, addr); - if (!pgd_present(*pgd)) - goto out_unlock; - - p4d = p4d_offset(pgd, addr); - if (!p4d_present(*p4d)) - goto out_unlock; - - pud = pud_offset(p4d, addr); - if (!pud_present(*pud)) - goto out_unlock; - - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) - goto out_unlock; - - if (pmd_trans_huge(*pmd)) - goto out_unlock; - - ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); - if (!ptep) - goto out_unlock; - - pte = *ptep; - - if (!pte_present(pte)) - goto out_pte_unlock; - - if (pte_young(pte)) { - ret = true; - goto out_pte_unlock; - } - - ptep_set_access_flags(vma, addr, ptep, pte_mkyoung(pte), 0); - pr_info("set AF for addr %lx\n", addr); - ret = true; - -out_pte_unlock: - pte_unmap_unlock(ptep, ptl); -out_unlock: - mmap_read_unlock(mm); - return ret; -#else - return false; -#endif -} - int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, int *__unused_flags) { diff --git a/kernel/syscall_hook_manager.c b/kernel/syscall_hook_manager.c index 14d258aa..c003518c 100644 --- a/kernel/syscall_hook_manager.c +++ b/kernel/syscall_hook_manager.c @@ -18,6 +18,7 @@ #include "sucompat.h" #include "setuid_hook.h" #include "selinux/selinux.h" +#include "util.h" // Tracepoint registration count management // == 1: just us @@ -246,12 +247,22 @@ static inline bool check_syscall_fastpath(int nr) int ksu_handle_init_mark_tracker(const char __user **filename_user) { char path[64]; + unsigned long addr; + const char __user *fn; + long ret; if (unlikely(!filename_user)) return 0; + addr = untagged_addr((unsigned long)*filename_user); + fn = (const char __user *)addr; + memset(path, 0, sizeof(path)); - strncpy_from_user_nofault(path, *filename_user, sizeof(path)); + ret = strncpy_from_user_nofault(path, fn, sizeof(path)); + if (ret < 0 && try_set_access_flag(addr)) { + ret = strncpy_from_user_nofault(path, fn, sizeof(path)); + pr_info("ksu_handle_init_mark_tracker: %ld\n", ret); + } if (likely(strstr(path, "/app_process") == NULL && strstr(path, "/adbd") == NULL && strstr(path, "/ksud") == NULL)) { pr_info("hook_manager: unmark %d exec %s", current->pid, path); diff --git a/kernel/util.c b/kernel/util.c new file mode 100644 index 00000000..0e2d5e1d --- /dev/null +++ b/kernel/util.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#include "util.h" + +bool try_set_access_flag(unsigned long addr) +{ +#ifdef CONFIG_ARM64 + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep, pte; + spinlock_t *ptl; + bool ret = false; + + if (!mm) + return false; + + if (!mmap_read_trylock(mm)) + return false; + + vma = find_vma(mm, addr); + if (!vma || addr < vma->vm_start) + goto out_unlock; + + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) + goto out_unlock; + + p4d = p4d_offset(pgd, addr); + if (!p4d_present(*p4d)) + goto out_unlock; + + pud = pud_offset(p4d, addr); + if (!pud_present(*pud)) + goto out_unlock; + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + goto out_unlock; + + if (pmd_trans_huge(*pmd)) + goto out_unlock; + + ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); + if (!ptep) + goto out_unlock; + + pte = *ptep; + + if (!pte_present(pte)) + goto out_pte_unlock; + + if (pte_young(pte)) { + ret = true; + goto out_pte_unlock; + } + + ptep_set_access_flags(vma, addr, ptep, pte_mkyoung(pte), 0); + pr_info("set AF for addr %lx\n", addr); + ret = true; + +out_pte_unlock: + pte_unmap_unlock(ptep, ptl); +out_unlock: + mmap_read_unlock(mm); + return ret; +#else + return false; +#endif +} diff --git a/kernel/util.h b/kernel/util.h new file mode 100644 index 00000000..b7cccae9 --- /dev/null +++ b/kernel/util.h @@ -0,0 +1,24 @@ +#ifndef __KSU_UTIL_H +#define __KSU_UTIL_H + +#include + +#ifndef preempt_enable_no_resched_notrace +#define preempt_enable_no_resched_notrace() \ +do { \ + barrier(); \ + __preempt_count_dec(); \ +} while (0) +#endif + +#ifndef preempt_disable_notrace +#define preempt_disable_notrace() \ +do { \ + __preempt_count_inc(); \ + barrier(); \ +} while (0) +#endif + +bool try_set_access_flag(unsigned long addr); + +#endif