diff --git a/kernel/Kconfig b/kernel/Kconfig index bdc8c4b1..48bf19ae 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -68,19 +68,11 @@ config KPM choice prompt "KernelSU hook type" depends on KSU - default KSU_KPROBES_HOOK - help - Hook type for KernelSU - -config KSU_KPROBES_HOOK - bool "Hook KernelSU with Kprobes" - depends on KPROBES - help - If enabled, Hook required KernelSU syscalls with Kernel-probe. + default KSU_TRACEPOINT_HOOK config KSU_TRACEPOINT_HOOK bool "Hook KernelSU with Tracepoint" - depends on TRACEPOINTS + depends on HAVE_SYSCALL_TRACEPOINTS help If enabled, Hook required KernelSU syscalls with Tracepoint. diff --git a/kernel/Makefile b/kernel/Makefile index 2c917fb2..b47827b7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -18,10 +18,6 @@ ccflags-y += -DCONFIG_KSU_MANUAL_SU kernelsu-objs += manual_su.o endif -ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) -kernelsu-objs += ksu_trace.o -endif - ifeq ($(CONFIG_KSU_THRONE_TRACKER_LEGACY),y) $(info -- KernelSU/compat: using legacy throne tracker) kernelsu-objs += throne_tracker_legacy.o @@ -99,15 +95,12 @@ endif ccflags-y += -DKSU_VERSION=$(KSU_VERSION) ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\" -ifeq ($(CONFIG_KSU_KPROBES_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK) -ccflags-y += -DCONFIG_KSU_KPROBES_HOOK -else ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK) -ccflags-y += -DCONFIG_KSU_TRACEPOINT_HOOK +ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y) +$(info -- SukiSU: KSU_TRACEPOINT_HOOK) +ccflags-y += -DKSU_HAVE_SYSCALL_TRACEPOINTS_HOOK else ifeq ($(CONFIG_KSU_MANUAL_HOOK), y) -$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK) -ccflags-y += -DCONFIG_KSU_MANUAL_HOOK +$(info -- SukiSU: KSU_MANUAL_HOOK) +ccflags-y += -DKSU_MANUAL_HOOK endif KERNEL_VERSION := $(VERSION).$(PATCHLEVEL) diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 659f41a1..ab5d8aef 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -92,10 +92,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); #define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" -static struct work_struct ksu_save_work; -static struct work_struct ksu_load_work; - -static bool persistent_allow_list(void); +void save_allow_list(void); void ksu_show_allow_list(void) { @@ -255,7 +252,7 @@ out: } if (persist) - persistent_allow_list(); + save_allow_list(); return result; } @@ -351,7 +348,8 @@ bool ksu_get_allow_list(int *array, int *length, bool allow) return true; } -static void do_save_allow_list(struct work_struct *work) +// make sure allow list works cross boot +void save_allow_list(void) { u32 magic = FILE_MAGIC; u32 version = FILE_FORMAT_VERSION; @@ -393,7 +391,7 @@ exit: filp_close(fp, 0); } -static void do_load_allow_list(struct work_struct *work) +void ksu_load_allow_list() { loff_t off = 0; ssize_t ret = 0; @@ -478,21 +476,10 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data mutex_unlock(&allowlist_mutex); if (modified) { - persistent_allow_list(); + save_allow_list(); } } -// make sure allow list works cross boot -static bool persistent_allow_list(void) -{ - return ksu_queue_work(&ksu_save_work); -} - -bool ksu_load_allow_list(void) -{ - return ksu_queue_work(&ksu_load_work); -} - void ksu_allowlist_init(void) { int i; @@ -505,9 +492,6 @@ void ksu_allowlist_init(void) INIT_LIST_HEAD(&allow_list); - INIT_WORK(&ksu_save_work, do_save_allow_list); - INIT_WORK(&ksu_load_work, do_load_allow_list); - init_default_profiles(); } @@ -516,7 +500,7 @@ void ksu_allowlist_exit(void) struct perm_data *np = NULL; struct perm_data *n = NULL; - do_save_allow_list(NULL); + save_allow_list(); // free allowlist mutex_lock(&allowlist_mutex); diff --git a/kernel/allowlist.h b/kernel/allowlist.h index 69297f84..24ef1518 100644 --- a/kernel/allowlist.h +++ b/kernel/allowlist.h @@ -8,7 +8,7 @@ void ksu_allowlist_init(void); void ksu_allowlist_exit(void); -bool ksu_load_allow_list(void); +void ksu_load_allow_list(void); void ksu_show_allow_list(void); diff --git a/kernel/arch.h b/kernel/arch.h index 3f15cd07..66d8d59a 100644 --- a/kernel/arch.h +++ b/kernel/arch.h @@ -85,7 +85,7 @@ #define TASK_ALLOC_SYMBOL "security_task_alloc" #else -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK #error "Unsupported arch" #endif #endif diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 5321750b..d10c4edd 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -1,3 +1,5 @@ +#include "linux/compiler.h" +#include "linux/sched/signal.h" #include #include #include @@ -144,6 +146,7 @@ static inline bool is_zygote_normal_app_uid(uid_t uid) #endif // #ifdef CONFIG_KSU_SUSFS bool ksu_module_mounted = false; +extern bool ksu_su_compat_enabled; #ifdef CONFIG_COMPAT bool ksu_is_compat __read_mostly = false; @@ -255,10 +258,9 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) put_group_info(group_info); } -static void disable_seccomp(struct task_struct *tsk) +static void disable_seccomp() { - assert_spin_locked(&tsk->sighand->siglock); - + assert_spin_locked(¤t->sighand->siglock); // disable seccomp #if defined(CONFIG_GENERIC_ENTRY) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) @@ -268,54 +270,45 @@ static void disable_seccomp(struct task_struct *tsk) #endif #ifdef CONFIG_SECCOMP - tsk->seccomp.mode = 0; - if (tsk->seccomp.filter) { - // 5.9+ have filter_count and use seccomp_filter_release -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) - seccomp_filter_release(tsk); - atomic_set(&tsk->seccomp.filter_count, 0); + current->seccomp.mode = 0; + current->seccomp.filter = NULL; #else - // for 6.11+ kernel support? -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) - put_seccomp_filter(tsk); -#endif - tsk->seccomp.filter = NULL; -#endif - } #endif } void escape_to_root(void) { - struct cred *newcreds; + struct cred *cred; + struct task_struct *p = current; + struct task_struct *t; - if (current_euid().val == 0) { - pr_warn("Already root, don't escape!\n"); + cred = prepare_creds(); + if (!cred) { + pr_warn("prepare_creds failed!\n"); return; } - - newcreds = prepare_creds(); - if (newcreds == NULL) { - pr_err("%s: failed to allocate new cred.\n", __func__); + + if (cred->euid.val == 0) { + pr_warn("Already root, don't escape!\n"); #if __SULOG_GATE ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed"); #endif + abort_creds(cred); return; } - struct root_profile *profile = - ksu_get_root_profile(newcreds->uid.val); + struct root_profile *profile = ksu_get_root_profile(cred->uid.val); - newcreds->uid.val = profile->uid; - newcreds->suid.val = profile->uid; - newcreds->euid.val = profile->uid; - newcreds->fsuid.val = profile->uid; + cred->uid.val = profile->uid; + cred->suid.val = profile->uid; + cred->euid.val = profile->uid; + cred->fsuid.val = profile->uid; - newcreds->gid.val = profile->gid; - newcreds->fsgid.val = profile->gid; - newcreds->sgid.val = profile->gid; - newcreds->egid.val = profile->gid; - newcreds->securebits = 0; + cred->gid.val = profile->gid; + cred->fsgid.val = profile->gid; + cred->sgid.val = profile->gid; + cred->egid.val = profile->gid; + cred->securebits = 0; BUILD_BUG_ON(sizeof(profile->capabilities.effective) != sizeof(kernel_cap_t)); @@ -325,24 +318,31 @@ void escape_to_root(void) // we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec! u64 cap_for_ksud = profile->capabilities.effective | CAP_DAC_READ_SEARCH; - memcpy(&newcreds->cap_effective, &cap_for_ksud, - sizeof(newcreds->cap_effective)); - memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, - sizeof(newcreds->cap_permitted)); - memcpy(&newcreds->cap_bset, &profile->capabilities.effective, - sizeof(newcreds->cap_bset)); + memcpy(&cred->cap_effective, &cap_for_ksud, + sizeof(cred->cap_effective)); + memcpy(&cred->cap_permitted, &profile->capabilities.effective, + sizeof(cred->cap_permitted)); + memcpy(&cred->cap_bset, &profile->capabilities.effective, + sizeof(cred->cap_bset)); - setup_groups(profile, newcreds); - commit_creds(newcreds); + setup_groups(profile, cred); + commit_creds(cred); + + // Refer to kernel/seccomp.c: seccomp_set_mode_strict + // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. spin_lock_irq(¤t->sighand->siglock); - disable_seccomp(current); + disable_seccomp(); spin_unlock_irq(¤t->sighand->siglock); setup_selinux(profile->selinux_domain); #if __SULOG_GATE ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); #endif + + for_each_thread (p, t) { + ksu_set_task_tracepoint_flag(t); + } } #ifdef CONFIG_KSU_MANUAL_SU @@ -362,7 +362,10 @@ static void disable_seccomp_for_task(struct task_struct *tsk) seccomp_filter_release(tsk); atomic_set(&tsk->seccomp.filter_count, 0); #else + // for 6.11+ kernel support? +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) put_seccomp_filter(tsk); +#endif tsk->seccomp.filter = NULL; #endif } @@ -373,6 +376,8 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) { struct cred *newcreds; struct task_struct *target_task; + struct task_struct *p = current; + struct task_struct *t; pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid); @@ -454,6 +459,9 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid) #if __SULOG_GATE ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation"); #endif + for_each_thread (p, t) { + ksu_set_task_tracepoint_flag(t); + } pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); } #endif @@ -1031,6 +1039,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } + if (new_uid.val == 2000) { + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } + // if on private space, see if its possibly the manager if (new_uid.val > 100000 && new_uid.val % 100000 == ksu_get_manager_uid()) { ksu_set_manager_uid(new_uid.val); @@ -1042,17 +1056,28 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) ksu_install_fd(); spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } spin_unlock_irq(¤t->sighand->siglock); return 0; } - if (ksu_is_allow_uid(new_uid.val)) { + if (ksu_is_allow_uid(new_uid.val)) { if (current->seccomp.mode == SECCOMP_MODE_FILTER && current->seccomp.filter) { spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); spin_unlock_irq(¤t->sighand->siglock); } + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } else { + // Disable syscall tracepoint sucompat for non-allowed processes + if (ksu_su_compat_enabled) { + clear_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } } // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! @@ -1154,6 +1179,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } + if (new_uid.val == 2000) { + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } + if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) { // pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val); return 0; @@ -1170,6 +1201,9 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) ksu_install_fd(); spin_lock_irq(¤t->sighand->siglock); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } spin_unlock_irq(¤t->sighand->siglock); return 0; } @@ -1181,6 +1215,14 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); spin_unlock_irq(¤t->sighand->siglock); } + if (ksu_su_compat_enabled) { + set_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } + } else { + // Disable syscall tracepoint sucompat for non-allowed processes + if (ksu_su_compat_enabled) { + clear_tsk_thread_flag(current, TIF_SYSCALL_TRACEPOINT); + } } // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it! @@ -1203,7 +1245,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) // check old process's selinux context, if it is not zygote, ignore it! // because some su apps may setuid to untrusted_app but they are in global mount namespace // when we umount for such process, that is a disaster! - bool is_zygote_child = is_zygote(old->security); + bool is_zygote_child = is_zygote(old); if (!is_zygote_child) { pr_info("handle umount ignore non zygote child: %d\n", current->pid); @@ -1375,7 +1417,7 @@ static struct security_hook_list ksu_hooks[] = { #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU) LSM_HOOK_INIT(task_alloc, ksu_task_alloc), #endif -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_KPROBES_HOOK LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check), #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ @@ -1577,7 +1619,7 @@ __maybe_unused int ksu_kprobe_exit(void) void __init ksu_core_init(void) { ksu_lsm_hook_init(); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK int rc = ksu_kprobe_init(); if (rc) { pr_err("ksu_kprobe_init failed: %d\n", rc); @@ -1596,7 +1638,7 @@ void ksu_core_exit(void) ksu_sulog_exit(); #endif -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK pr_info("ksu_core_kprobe_exit\n"); ksu_kprobe_exit(); #endif diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h index 9740ee1b..39686416 100644 --- a/kernel/kernel_compat.h +++ b/kernel/kernel_compat.h @@ -7,12 +7,10 @@ #include "ss/policydb.h" #include "linux/key.h" -#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) -// arch/arm64/include/asm/barrier.h, adding dsb probably unneeded -#define DONT_GET_SMART() do { barrier(); isb(); } while (0) +#if defined(CONFIG_KPROBES) && !defined(KSU_MANUAL_HOOK) +#define KSU_KPROBES_HOOK 1 #else -// well, compiler atleast, and not our targets -#define DONT_GET_SMART() barrier() +#define KSU_KPROBES_HOOK 0 #endif /* diff --git a/kernel/ksu.c b/kernel/ksu.c index 51b8a364..7dbdf16e 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -61,10 +61,6 @@ extern void ksu_sucompat_exit(void); extern void ksu_ksud_init(void); extern void ksu_ksud_exit(void); extern void ksu_supercalls_init(); -#ifdef CONFIG_KSU_TRACEPOINT_HOOK -extern void ksu_trace_register(); -extern void ksu_trace_unregister(); -#endif int __init kernelsu_init(void) { @@ -106,16 +102,12 @@ int __init kernelsu_init(void) ksu_sucompat_init(); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK ksu_ksud_init(); #else pr_debug("init ksu driver\n"); #endif -#ifdef CONFIG_KSU_TRACEPOINT_HOOK - ksu_trace_register(); -#endif - #ifdef MODULE #ifndef CONFIG_KSU_DEBUG kobject_del(&THIS_MODULE->mkobj.kobj); @@ -139,13 +131,10 @@ void kernelsu_exit(void) destroy_workqueue(ksu_workqueue); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK ksu_ksud_exit(); #endif -#ifdef CONFIG_KSU_TRACEPOINT_HOOK - ksu_trace_unregister(); -#endif ksu_sucompat_exit(); diff --git a/kernel/ksu_trace.c b/kernel/ksu_trace.c deleted file mode 100644 index 4055877b..00000000 --- a/kernel/ksu_trace.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "ksu_trace.h" - - -// extern kernelsu functions -extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags); -extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, int *flags); -extern bool ksu_vfs_read_hook __read_mostly; -extern int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, size_t *count_ptr); -extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); -extern bool ksu_input_hook __read_mostly; -extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); -// end kernelsu functions - - -// tracepoint callback functions -void ksu_trace_execveat_hook_callback(void *data, int *fd, struct filename **filename_ptr, - void *argv, void *envp, int *flags) -{ - ksu_handle_execveat(fd, filename_ptr, argv, envp, flags); -} - -void ksu_trace_faccessat_hook_callback(void *data, int *dfd, const char __user **filename_user, - int *mode, int *flags) -{ - ksu_handle_faccessat(dfd, filename_user, mode, flags); -} - -void ksu_trace_sys_read_hook_callback(void *data, unsigned int fd, char __user **buf_ptr, - size_t *count_ptr) -{ - if (unlikely(ksu_vfs_read_hook)) - ksu_handle_sys_read(fd, buf_ptr, count_ptr); -} - -void ksu_trace_stat_hook_callback(void *data, int *dfd, const char __user **filename_user, - int *flags) -{ - ksu_handle_stat(dfd, filename_user, flags); -} - -void ksu_trace_input_hook_callback(void *data, unsigned int *type, unsigned int *code, - int *value) -{ - if (unlikely(ksu_input_hook)) - ksu_handle_input_handle_event(type, code, value); -} - -// end tracepoint callback functions - - -// register tracepoint callback functions -void ksu_trace_register(void) -{ - register_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL); - register_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL); - register_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL); - register_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL); - register_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL); -} - -// unregister tracepoint callback functions -void ksu_trace_unregister(void) -{ - unregister_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL); - unregister_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL); - unregister_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL); - unregister_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL); - unregister_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL); -} diff --git a/kernel/ksu_trace.h b/kernel/ksu_trace.h deleted file mode 100644 index 77425638..00000000 --- a/kernel/ksu_trace.h +++ /dev/null @@ -1,37 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM ksu_trace - -#if !defined(_KSU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _KSU_TRACE_H - -#include -#include - -DECLARE_TRACE(ksu_trace_execveat_hook, - TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags), - TP_ARGS(fd, filename_ptr, argv, envp, flags)); - -DECLARE_TRACE(ksu_trace_faccessat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *mode, int *flags), - TP_ARGS(dfd, filename_user, mode, flags)); - -DECLARE_TRACE(ksu_trace_sys_read_hook, - TP_PROTO(unsigned int fd, char __user **buf_ptr, size_t *count_ptr), - TP_ARGS(fd, buf_ptr, count_ptr)); - -DECLARE_TRACE(ksu_trace_stat_hook, - TP_PROTO(int *dfd, const char __user **filename_user, int *flags), - TP_ARGS(dfd, filename_user, flags)); - -DECLARE_TRACE(ksu_trace_input_hook, - TP_PROTO(unsigned int *type, unsigned int *code, int *value), - TP_ARGS(type, code, value)); - -#endif /* _KSU_TRACE_H */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE ksu_trace - -#include diff --git a/kernel/ksu_trace_export.c b/kernel/ksu_trace_export.c deleted file mode 100644 index b303cbbd..00000000 --- a/kernel/ksu_trace_export.c +++ /dev/null @@ -1,8 +0,0 @@ -#define CREATE_TRACE_POINTS -#include "ksu_trace.h" - -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_faccessat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_sys_read_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_stat_hook); -EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_input_hook); diff --git a/kernel/ksud.c b/kernel/ksud.c index a170ee52..f37878dc 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -54,7 +54,7 @@ static void stop_vfs_read_hook(void); static void stop_execve_hook(void); static void stop_input_hook(void); -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK static struct work_struct stop_vfs_read_work; static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; @@ -83,6 +83,9 @@ void on_post_fs_data(void) done = true; pr_info("%s!\n", __func__); ksu_load_allow_list(); + extern void ksu_mark_running_process(void); + pr_info("mark tif for running process\n"); + ksu_mark_running_process(); ksu_observer_init(); // sanity check, this may influence the performance stop_input_hook(); @@ -298,7 +301,7 @@ static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to) int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, size_t *count_ptr, loff_t **pos) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_KPROBES_HOOK if (!ksu_vfs_read_hook) { return 0; } @@ -411,7 +414,7 @@ static bool is_volumedown_enough(unsigned int count) int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_KPROBES_HOOK if (!ksu_input_hook) { return 0; } @@ -453,7 +456,7 @@ bool ksu_is_safe_mode() return false; } -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) { /* @@ -670,7 +673,7 @@ int __maybe_unused ksu_handle_compat_execve_ksud(const char __user *filename_use static void stop_vfs_read_hook(void) { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK bool ret = schedule_work(&stop_vfs_read_work); pr_info("unregister vfs_read kprobe: %d!\n", ret); #else @@ -681,7 +684,7 @@ static void stop_vfs_read_hook(void) static void stop_execve_hook(void) { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else @@ -696,7 +699,7 @@ static void stop_execve_hook(void) static void stop_input_hook(void) { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK static bool input_hook_stopped = false; if (input_hook_stopped) { return; @@ -714,7 +717,7 @@ static void stop_input_hook(void) // ksud: module support void ksu_ksud_init(void) { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK int ret; ret = register_kprobe(&execve_kp); @@ -734,7 +737,7 @@ void ksu_ksud_init(void) void ksu_ksud_exit(void) { -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_KPROBES_HOOK unregister_kprobe(&execve_kp); // this should be done before unregister vfs_read_kp // unregister_kprobe(&vfs_read_kp); diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 10cee518..062b6bcb 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -1,3 +1,5 @@ +#include "linux/cred.h" +#include "linux/sched.h" #include #include "selinux_defs.h" #include "../klog.h" // IWYU pragma: keep @@ -101,7 +103,7 @@ static inline u32 current_sid(void) } #endif -bool is_ksu_domain(void) +bool is_task_ksu_domain(const struct cred* cred) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) struct lsm_context ctx; @@ -110,10 +112,17 @@ bool is_ksu_domain(void) u32 seclen; #endif bool result; + if (!cred) { + return false; + } + const struct task_security_struct *tsec = selinux_cred(cred); + if (!tsec) { + return false; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) - int err = security_secid_to_secctx(current_sid(), &ctx); + int err = security_secid_to_secctx(tsec->sid, &ctx); #else - int err = security_secid_to_secctx(current_sid(), &domain, &seclen); + int err = security_secid_to_secctx(tsec->sid, &domain, &seclen); #endif if (err) { @@ -130,9 +139,18 @@ bool is_ksu_domain(void) return result; } -bool is_zygote(void *sec) +bool is_ksu_domain() { - struct task_security_struct *tsec = (struct task_security_struct *)sec; + current_sid(); + return is_task_ksu_domain(current_cred()); +} + +bool is_zygote(const struct cred* cred) +{ + if (!cred) { + return false; + } + const struct task_security_struct * tsec = selinux_cred(cred); if (!tsec) { return false; } diff --git a/kernel/selinux/selinux.h b/kernel/selinux/selinux.h index ce3a8bb7..dd7732b5 100644 --- a/kernel/selinux/selinux.h +++ b/kernel/selinux/selinux.h @@ -3,6 +3,7 @@ #include #include +#include "linux/sched.h" #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE) #define KSU_COMPAT_USE_SELINUX_STATE @@ -14,9 +15,11 @@ void setenforce(bool); bool getenforce(void); +bool is_task_ksu_domain(const struct cred* cred); + bool is_ksu_domain(void); -bool is_zygote(void *cred); +bool is_zygote(const struct cred* cred); void apply_kernelsu_rules(void); diff --git a/kernel/sucompat.c b/kernel/sucompat.c index d76ec089..d08dcc14 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -1,3 +1,5 @@ +#include "linux/compiler.h" +#include "selinux/selinux.h" #include #include #include @@ -5,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +17,8 @@ #else #include #endif +#include +#include #ifdef CONFIG_KSU_SUSFS_SUS_SU #include #endif @@ -100,7 +105,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, int *__unused_flags) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -156,7 +161,7 @@ struct filename* susfs_ksu_handle_stat(int *dfd, const char __user **filename_us int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -213,7 +218,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, { struct filename *filename; -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -270,7 +275,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user, char path[sizeof(su) + 1]; #endif -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) { return 0; } @@ -327,7 +332,7 @@ int ksu_handle_devpts(struct inode *inode) int __ksu_handle_devpts(struct inode *inode) { -#ifndef CONFIG_KSU_KPROBES_HOOK +#ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK if (!ksu_sucompat_hook_state) return 0; #endif @@ -357,41 +362,45 @@ int __ksu_handle_devpts(struct inode *inode) return 0; } -#ifdef CONFIG_KSU_KPROBES_HOOK +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK -static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) +// Tracepoint probe for sys_enter +static void sucompat_sys_enter_handler(void *data, struct pt_regs *regs, + long id) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *mode = (int *)&PT_REGS_PARM3(real_regs); + // Handle newfstatat + if (unlikely(id == __NR_newfstatat)) { + int *dfd = (int *)&PT_REGS_PARM1(regs); + const char __user **filename_user = + (const char __user **)&PT_REGS_PARM2(regs); + int *flags = (int *)&PT_REGS_SYSCALL_PARM4(regs); + ksu_handle_stat(dfd, filename_user, flags); + return; + } - return ksu_handle_faccessat(dfd, filename_user, mode, NULL); + // Handle faccessat + if (unlikely(id == __NR_faccessat)) { + int *dfd = (int *)&PT_REGS_PARM1(regs); + const char __user **filename_user = + (const char __user **)&PT_REGS_PARM2(regs); + int *mode = (int *)&PT_REGS_PARM3(regs); + ksu_handle_faccessat(dfd, filename_user, mode, NULL); + return; + } + + // Handle execve + if (unlikely(id == __NR_execve)) { + const char __user **filename_user = + (const char __user **)&PT_REGS_PARM1(regs); + ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, NULL); + return; + } } -static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int *dfd = (int *)&PT_REGS_PARM1(real_regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM2(real_regs); - int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs); +#endif // KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK - return ksu_handle_stat(dfd, filename_user, flags); -} +#ifdef KSU_KPROBES_HOOK -static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) -{ - struct pt_regs *real_regs = PT_REAL_REGS(regs); - const char __user **filename_user = - (const char **)&PT_REGS_PARM1(real_regs); - - return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL, - NULL); -} - -static struct kprobe *su_kps[6]; static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) { struct inode *inode; @@ -406,7 +415,7 @@ static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) } static struct kprobe *init_kprobe(const char *name, - kprobe_pre_handler_t handler) + kprobe_pre_handler_t handler) { struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); if (!kp) @@ -434,34 +443,82 @@ static void destroy_kprobe(struct kprobe **kp_ptr) kfree(kp); *kp_ptr = NULL; } + +static struct kprobe *pts_kp = NULL; #endif -// sucompat: permited process can execute 'su' to gain root access. -void ksu_sucompat_enable(void) +void ksu_mark_running_process() { -#ifdef CONFIG_KSU_KPROBES_HOOK - su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); - su_kps[1] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre); - su_kps[2] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); - su_kps[3] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); - su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre); - su_kps[5] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); + struct task_struct *p, *t; + read_lock(&tasklist_lock); + for_each_process_thread (p, t) { + if (!t->mm) { // only user processes + continue; + } + int uid = task_uid(t).val; + bool ksu_root_process = + uid == 0 && is_task_ksu_domain(get_task_cred(t)); + if (ksu_root_process || ksu_is_allow_uid(uid)) { + ksu_set_task_tracepoint_flag(t); + pr_info("sucompat: mark process: pid:%d, uid: %d, comm:%s\n", + t->pid, uid, t->comm); + } + } + read_unlock(&tasklist_lock); +} + +static void unmark_all_process() +{ + struct task_struct *p, *t; + read_lock(&tasklist_lock); + for_each_process_thread (p, t) { + ksu_clear_task_tracepoint_flag(t); + } + read_unlock(&tasklist_lock); + pr_info("sucompat: unmark all user process done!\n"); +} + +void ksu_sucompat_enable() +{ + int ret; + pr_info("sucompat: ksu_sucompat_enable called\n"); +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK + // Register sys_enter tracepoint for syscall interception + ret = register_trace_sys_enter(sucompat_sys_enter_handler, NULL); + unmark_all_process(); + ksu_mark_running_process(); + if (ret) { + pr_err("sucompat: failed to register sys_enter tracepoint: %d\n", ret); + } else { + pr_info("sucompat: sys_enter tracepoint registered\n"); + } #else ksu_sucompat_hook_state = true; - pr_info("ksu_sucompat init\n"); + pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat\n"); +#endif + +#ifdef KSU_KPROBES_HOOK + // Register kprobe for pts_unix98_lookup + pts_kp = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); #endif } -void ksu_sucompat_disable(void) +void ksu_sucompat_disable() { -#ifdef CONFIG_KSU_KPROBES_HOOK - int i; - for (i = 0; i < ARRAY_SIZE(su_kps); i++) { - destroy_kprobe(&su_kps[i]); - } + pr_info("sucompat: ksu_sucompat_disable called\n"); +#ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK + // Unregister sys_enter tracepoint + unregister_trace_sys_enter(sucompat_sys_enter_handler, NULL); + tracepoint_synchronize_unregister(); + pr_info("sucompat: sys_enter tracepoint unregistered\n"); #else ksu_sucompat_hook_state = false; - pr_info("ksu_sucompat exit\n"); + pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\n"); +#endif + +#ifdef KSU_KPROBES_HOOK + // Unregister pts_unix98_lookup kprobe + destroy_kprobe(&pts_kp); #endif } @@ -492,12 +549,7 @@ int susfs_sus_su_working_mode = 0; static bool ksu_is_su_kps_enabled(void) { #ifdef CONFIG_KSU_KPROBES_HOOK - int i; - for (i = 0; i < ARRAY_SIZE(su_kps); i++) { - if (su_kps[i]) { - return true; - } - } + destroy_kprobe(&pts_kp); #endif return false; } diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 9adab23e..61279dec 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -385,11 +385,11 @@ static int do_get_full_version(void __user *arg) static int do_get_hook_type(void __user *arg) { struct ksu_hook_type_cmd cmd = {0}; - const char *type = "Kprobes"; + const char *type = "Unknown"; -#if defined(CONFIG_KSU_TRACEPOINT_HOOK) +#if defined(KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK) type = "Tracepoint"; -#elif defined(CONFIG_KSU_MANUAL_HOOK) +#elif defined(KSU_MANUAL_HOOK) type = "Manual"; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)