kernel: use sys_enter tracepoint for sucompat (#533)

* use sys_enter tracepoint for sucompat

* update sucompat rules

* clean tif mark

* mark tif after load allow list

* clear all tif first, then mark target

* Fix shell su

* allow when escape

* fix bugs

* kernel: Resolve logical inconsistencies

---------

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
ShirkNeko
2025-11-06 12:45:37 +08:00
committed by GitHub
parent 0ce7bc2627
commit 5323a500dd
17 changed files with 204 additions and 277 deletions

View File

@@ -31,7 +31,7 @@ jobs:
cd kernel cd kernel
echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ===" echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ==="
CONFIG_KSU=m CONFIG_KSU_KPROBES_HOOK=y CONFIG_KSU_MANUAL_SU=y make CONFIG_KSU=m CONFIG_KSU_TRACEPOINT_HOOK=y CONFIG_KSU_MANUAL_SU=y make
echo "=== Build completed ===" echo "=== Build completed ==="
# Create output directory in GitHub workspace # Create output directory in GitHub workspace

View File

@@ -36,17 +36,11 @@ config KPM
choice choice
prompt "KernelSU hook type" prompt "KernelSU hook type"
depends on KSU depends on KSU
default KSU_KPROBES_HOOK default KSU_TRACEPOINT_HOOK
config KSU_KPROBES_HOOK
bool "Hook KernelSU with Kprobes"
depends on KPROBES
help
If enabled, Hook required KernelSU syscalls with Kernel-probe.
config KSU_TRACEPOINT_HOOK config KSU_TRACEPOINT_HOOK
bool "Hook KernelSU with Tracepoint" bool "Hook KernelSU with Tracepoint"
depends on TRACEPOINTS depends on HAVE_SYSCALL_TRACEPOINTS
help help
If enabled, Hook required KernelSU syscalls with Tracepoint. If enabled, Hook required KernelSU syscalls with Tracepoint.

View File

@@ -19,10 +19,6 @@ ccflags-y += -DCONFIG_KSU_MANUAL_SU
kernelsu-objs += manual_su.o kernelsu-objs += manual_su.o
endif endif
ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
kernelsu-objs += ksu_trace.o
endif
kernelsu-objs += selinux/selinux.o kernelsu-objs += selinux/selinux.o
kernelsu-objs += selinux/sepolicy.o kernelsu-objs += selinux/sepolicy.o
kernelsu-objs += selinux/rules.o kernelsu-objs += selinux/rules.o
@@ -30,7 +26,6 @@ ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
obj-$(CONFIG_KSU) += kernelsu.o obj-$(CONFIG_KSU) += kernelsu.o
obj-$(CONFIG_KSU_TRACEPOINT_HOOK) += ksu_trace_export.o
obj-$(CONFIG_KPM) += kpm/ obj-$(CONFIG_KPM) += kpm/
@@ -124,15 +119,12 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE)) $(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE))
endif endif
ifeq ($(CONFIG_KSU_KPROBES_HOOK), y) ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK) $(info -- SukiSU: KSU_TRACEPOINT_HOOK)
ccflags-y += -DCONFIG_KSU_KPROBES_HOOK ccflags-y += -DKSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
else ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK)
ccflags-y += -DCONFIG_KSU_TRACEPOINT_HOOK
else ifeq ($(CONFIG_KSU_MANUAL_HOOK), y) else ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK) $(info -- SukiSU: KSU_MANUAL_HOOK)
ccflags-y += -DCONFIG_KSU_MANUAL_HOOK ccflags-y += -DKSU_MANUAL_HOOK
endif endif
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL) KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)

View File

@@ -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" #define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
static struct work_struct ksu_save_work; void save_allow_list(void);
static struct work_struct ksu_load_work;
static bool persistent_allow_list(void);
void ksu_show_allow_list(void) void ksu_show_allow_list(void)
{ {
@@ -255,7 +252,7 @@ out:
} }
if (persist) if (persist)
persistent_allow_list(); save_allow_list();
return result; return result;
} }
@@ -351,7 +348,8 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true; 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 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION; u32 version = FILE_FORMAT_VERSION;
@@ -393,7 +391,7 @@ exit:
filp_close(fp, 0); filp_close(fp, 0);
} }
static void do_load_allow_list(struct work_struct *work) void ksu_load_allow_list()
{ {
loff_t off = 0; loff_t off = 0;
ssize_t ret = 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); mutex_unlock(&allowlist_mutex);
if (modified) { 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) void ksu_allowlist_init(void)
{ {
int i; int i;
@@ -505,9 +492,6 @@ void ksu_allowlist_init(void)
INIT_LIST_HEAD(&allow_list); 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(); init_default_profiles();
} }
@@ -516,7 +500,7 @@ void ksu_allowlist_exit(void)
struct perm_data *np = NULL; struct perm_data *np = NULL;
struct perm_data *n = NULL; struct perm_data *n = NULL;
do_save_allow_list(NULL); save_allow_list();
// free allowlist // free allowlist
mutex_lock(&allowlist_mutex); mutex_lock(&allowlist_mutex);

View File

@@ -8,7 +8,7 @@ void ksu_allowlist_init(void);
void ksu_allowlist_exit(void); void ksu_allowlist_exit(void);
bool ksu_load_allow_list(void); void ksu_load_allow_list(void);
void ksu_show_allow_list(void); void ksu_show_allow_list(void);

View File

@@ -1,3 +1,5 @@
#include "linux/compiler.h"
#include "linux/sched/signal.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/task_work.h> #include <linux/task_work.h>
#include <linux/thread_info.h> #include <linux/thread_info.h>
@@ -47,6 +49,7 @@
#endif #endif
bool ksu_module_mounted = false; bool ksu_module_mounted = false;
extern bool ksu_su_compat_enabled;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
bool ksu_is_compat __read_mostly = false; bool ksu_is_compat __read_mostly = false;
@@ -175,6 +178,8 @@ static void disable_seccomp()
void escape_to_root(void) void escape_to_root(void)
{ {
struct cred *cred; struct cred *cred;
struct task_struct *p = current;
struct task_struct *t;
cred = prepare_creds(); cred = prepare_creds();
if (!cred) { if (!cred) {
@@ -233,6 +238,10 @@ void escape_to_root(void)
#if __SULOG_GATE #if __SULOG_GATE
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root"); ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
#endif #endif
for_each_thread(p, t){
set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
}
} }
#ifdef CONFIG_KSU_MANUAL_SU #ifdef CONFIG_KSU_MANUAL_SU
@@ -266,6 +275,8 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
{ {
struct cred *newcreds; struct cred *newcreds;
struct task_struct *target_task; 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); pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid);
@@ -347,6 +358,9 @@ void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
#if __SULOG_GATE #if __SULOG_GATE
ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation"); ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation");
#endif #endif
for_each_thread(p, t){
set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
}
pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid); pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid);
} }
#endif #endif
@@ -500,6 +514,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0; 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)) { 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); // pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val);
return 0; return 0;
@@ -516,6 +536,9 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
ksu_install_fd(); ksu_install_fd();
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); 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(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
return 0; return 0;
} }
@@ -527,6 +550,14 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot); ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->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! // this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
@@ -549,7 +580,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! // 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 // 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! // 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) { if (!is_zygote_child) {
pr_info("handle umount ignore non zygote child: %d\n", current->pid); pr_info("handle umount ignore non zygote child: %d\n", current->pid);
return 0; return 0;

View File

@@ -1,28 +0,0 @@
#ifndef __KSU_H_KSHOOK
#define __KSU_H_KSHOOK
#include <linux/fs.h>
#include <linux/types.h>
// For sucompat
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *flags);
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
// For ksud
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
size_t *count_ptr, loff_t **pos);
// For ksud and sucompat
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
void *envp, int *flags);
// For volume button
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value);
#endif

View File

@@ -6,12 +6,10 @@
#include "ss/policydb.h" #include "ss/policydb.h"
#include "linux/key.h" #include "linux/key.h"
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) #if defined(CONFIG_KPROBES) && !defined(KSU_MANUAL_HOOK)
// arch/arm64/include/asm/barrier.h, adding dsb probably unneeded #define KSU_KPROBES_HOOK 1
#define DONT_GET_SMART() do { barrier(); isb(); } while (0)
#else #else
// well, compiler atleast, and not our targets #define KSU_KPROBES_HOOK 0
#define DONT_GET_SMART() barrier()
#endif #endif
/* /*

View File

@@ -29,11 +29,6 @@ extern void ksu_sucompat_exit();
extern void ksu_ksud_init(); extern void ksu_ksud_init();
extern void ksu_ksud_exit(); extern void ksu_ksud_exit();
extern void ksu_supercalls_init(); 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) int __init kernelsu_init(void)
{ {
#ifdef CONFIG_KSU_DEBUG #ifdef CONFIG_KSU_DEBUG
@@ -60,16 +55,12 @@ int __init kernelsu_init(void)
ksu_sucompat_init(); ksu_sucompat_init();
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
ksu_ksud_init(); ksu_ksud_init();
#else #else
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html"); pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
#endif #endif
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
ksu_trace_register();
#endif
#ifdef MODULE #ifdef MODULE
#ifndef CONFIG_KSU_DEBUG #ifndef CONFIG_KSU_DEBUG
kobject_del(&THIS_MODULE->mkobj.kobj); kobject_del(&THIS_MODULE->mkobj.kobj);
@@ -90,14 +81,10 @@ void kernelsu_exit(void)
ksu_sucompat_exit(); ksu_sucompat_exit();
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
ksu_ksud_exit(); ksu_ksud_exit();
#endif #endif
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
ksu_trace_unregister();
#endif
ksu_core_exit(); ksu_core_exit();
ksu_feature_exit(); ksu_feature_exit();
} }

View File

@@ -1,69 +0,0 @@
#include "ksu_trace.h"
// extern kernelsu functions
extern bool ksu_vfs_read_hook __read_mostly;
extern bool ksu_input_hook __read_mostly;
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 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 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);
}

View File

@@ -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 <linux/fs.h>
#include <linux/tracepoint.h>
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 <trace/define_trace.h>

View File

@@ -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);

View File

@@ -49,7 +49,7 @@ static void stop_vfs_read_hook();
static void stop_execve_hook(); static void stop_execve_hook();
static void stop_input_hook(); static void stop_input_hook();
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
static struct work_struct stop_vfs_read_work; static struct work_struct stop_vfs_read_work;
static struct work_struct stop_execve_hook_work; static struct work_struct stop_execve_hook_work;
static struct work_struct stop_input_hook_work; static struct work_struct stop_input_hook_work;
@@ -74,6 +74,9 @@ void on_post_fs_data(void)
done = true; done = true;
pr_info("on_post_fs_data!\n"); pr_info("on_post_fs_data!\n");
ksu_load_allow_list(); 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(); ksu_observer_init();
// sanity check, this may influence the performance // sanity check, this may influence the performance
stop_input_hook(); stop_input_hook();
@@ -268,7 +271,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, int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
size_t *count_ptr, loff_t **pos) size_t *count_ptr, loff_t **pos)
{ {
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_KPROBES_HOOK
if (!ksu_vfs_read_hook) { if (!ksu_vfs_read_hook) {
return 0; return 0;
} }
@@ -381,7 +384,7 @@ static bool is_volumedown_enough(unsigned int count)
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value) int *value)
{ {
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_KPROBES_HOOK
if (!ksu_input_hook) { if (!ksu_input_hook) {
return 0; return 0;
} }
@@ -423,7 +426,7 @@ bool ksu_is_safe_mode()
return false; return false;
} }
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs) static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{ {
/* /*
@@ -596,7 +599,7 @@ static void do_stop_input_hook(struct work_struct *work)
static void stop_vfs_read_hook() static void stop_vfs_read_hook()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
bool ret = schedule_work(&stop_vfs_read_work); bool ret = schedule_work(&stop_vfs_read_work);
pr_info("unregister vfs_read kprobe: %d!\n", ret); pr_info("unregister vfs_read kprobe: %d!\n", ret);
#else #else
@@ -607,7 +610,7 @@ static void stop_vfs_read_hook()
static void stop_execve_hook() static void stop_execve_hook()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
bool ret = schedule_work(&stop_execve_hook_work); bool ret = schedule_work(&stop_execve_hook_work);
pr_info("unregister execve kprobe: %d!\n", ret); pr_info("unregister execve kprobe: %d!\n", ret);
#else #else
@@ -623,7 +626,7 @@ static void stop_input_hook()
return; return;
} }
input_hook_stopped = true; input_hook_stopped = true;
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
bool ret = schedule_work(&stop_input_hook_work); bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret); pr_info("unregister input kprobe: %d!\n", ret);
#else #else
@@ -635,7 +638,7 @@ static void stop_input_hook()
// ksud: module support // ksud: module support
void ksu_ksud_init() void ksu_ksud_init()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
int ret; int ret;
ret = register_kprobe(&execve_kp); ret = register_kprobe(&execve_kp);
@@ -655,7 +658,7 @@ void ksu_ksud_init()
void ksu_ksud_exit() void ksu_ksud_exit()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef KSU_KPROBES_HOOK
unregister_kprobe(&execve_kp); unregister_kprobe(&execve_kp);
// this should be done before unregister vfs_read_kp // this should be done before unregister vfs_read_kp
// unregister_kprobe(&vfs_read_kp); // unregister_kprobe(&vfs_read_kp);

View File

@@ -1,4 +1,6 @@
#include "selinux.h" #include "selinux.h"
#include "linux/cred.h"
#include "linux/sched.h"
#include "objsec.h" #include "objsec.h"
#include "linux/version.h" #include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep #include "../klog.h" // IWYU pragma: keep
@@ -84,7 +86,7 @@ static inline u32 current_sid(void)
} }
#endif #endif
bool is_ksu_domain() bool is_task_ksu_domain(const struct cred* cred)
{ {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
struct lsm_context ctx; struct lsm_context ctx;
@@ -93,10 +95,17 @@ bool is_ksu_domain()
u32 seclen; u32 seclen;
#endif #endif
bool result; 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) #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 #else
int err = security_secid_to_secctx(current_sid(), &domain, &seclen); int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
#endif #endif
if (err) { if (err) {
@@ -113,9 +122,18 @@ bool is_ksu_domain()
return result; 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) { if (!tsec) {
return false; return false;
} }

View File

@@ -3,6 +3,7 @@
#include "linux/types.h" #include "linux/types.h"
#include "linux/version.h" #include "linux/version.h"
#include "linux/sched.h"
void setup_selinux(const char *); void setup_selinux(const char *);
@@ -10,9 +11,11 @@ void setenforce(bool);
bool getenforce(); bool getenforce();
bool is_task_ksu_domain(const struct cred* cred);
bool is_ksu_domain(); bool is_ksu_domain();
bool is_zygote(void *cred); bool is_zygote(const struct cred* cred);
void apply_kernelsu_rules(); void apply_kernelsu_rules();

View File

@@ -1,3 +1,6 @@
#include "linux/compiler.h"
#include "linux/sched.h"
#include "selinux/selinux.h"
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/security.h> #include <linux/security.h>
#include <asm/current.h> #include <asm/current.h>
@@ -5,10 +8,13 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/tracepoint.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <asm/syscall.h>
#include <trace/events/syscalls.h>
#include "objsec.h" #include "objsec.h"
#include "allowlist.h" #include "allowlist.h"
@@ -62,7 +68,7 @@ static const struct ksu_feature_handler su_compat_handler = {
.set_handler = su_compat_feature_set, .set_handler = su_compat_feature_set,
}; };
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
static bool ksu_sucompat_hook_state __read_mostly = true; static bool ksu_sucompat_hook_state __read_mostly = true;
#endif #endif
@@ -94,7 +100,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
{ {
const char su[] = SU_PATH; const char su[] = SU_PATH;
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
if (!ksu_sucompat_hook_state) { if (!ksu_sucompat_hook_state) {
return 0; return 0;
} }
@@ -124,7 +130,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
// const char sh[] = SH_PATH; // const char sh[] = SH_PATH;
const char su[] = SU_PATH; const char su[] = SU_PATH;
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
if (!ksu_sucompat_hook_state) { if (!ksu_sucompat_hook_state) {
return 0; return 0;
} }
@@ -182,7 +188,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
const char sh[] = KSUD_PATH; const char sh[] = KSUD_PATH;
const char su[] = SU_PATH; const char su[] = SU_PATH;
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
if (!ksu_sucompat_hook_state) { if (!ksu_sucompat_hook_state) {
return 0; return 0;
} }
@@ -228,7 +234,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
const char su[] = SU_PATH; const char su[] = SU_PATH;
char path[sizeof(su) + 1]; char path[sizeof(su) + 1];
#ifndef CONFIG_KSU_KPROBES_HOOK #ifndef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
if (!ksu_sucompat_hook_state){ if (!ksu_sucompat_hook_state){
return 0; return 0;
} }
@@ -273,7 +279,7 @@ int ksu_handle_devpts(struct inode *inode)
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) if (!ksu_sucompat_hook_state)
return 0; return 0;
#endif #endif
@@ -299,40 +305,45 @@ int __ksu_handle_devpts(struct inode *inode)
return 0; 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)
{
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);
return ksu_handle_faccessat(dfd, filename_user, mode, NULL); // Tracepoint probe for sys_enter
static void sucompat_sys_enter_handler(void *data, struct pt_regs *regs,
long id)
{
// 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;
}
// 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) #endif // KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
{
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);
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[4];
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs) static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
{ {
struct inode *inode; struct inode *inode;
@@ -347,7 +358,7 @@ static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
} }
static struct kprobe *init_kprobe(const char *name, 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); struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
if (!kp) if (!kp)
@@ -376,32 +387,81 @@ static void destroy_kprobe(struct kprobe **kp_ptr)
*kp_ptr = NULL; *kp_ptr = NULL;
} }
static struct kprobe *pts_kp = NULL;
#endif #endif
// sucompat: permited process can execute 'su' to gain root access. void ksu_mark_running_process()
{
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)) {
set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
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) {
clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
}
read_unlock(&tasklist_lock);
pr_info("sucompat: unmark all user process done!\n");
}
void ksu_sucompat_enable() void ksu_sucompat_enable()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK int ret;
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); pr_info("sucompat: ksu_sucompat_enable called\n");
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); #ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre); // Register sys_enter tracepoint for syscall interception
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre); 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 #else
ksu_sucompat_hook_state = true; ksu_sucompat_hook_state = true;
pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat\n"); pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat\n");
#endif #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 ksu_sucompat_disable()
{ {
#ifdef CONFIG_KSU_KPROBES_HOOK pr_info("sucompat: ksu_sucompat_disable called\n");
int i; #ifdef KSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
for (i = 0; i < ARRAY_SIZE(su_kps); i++) { // Unregister sys_enter tracepoint
destroy_kprobe(&su_kps[i]); unregister_trace_sys_enter(sucompat_sys_enter_handler, NULL);
} tracepoint_synchronize_unregister();
pr_info("sucompat: sys_enter tracepoint unregistered\n");
#else #else
ksu_sucompat_hook_state = false; ksu_sucompat_hook_state = false;
pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\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 #endif
} }
@@ -423,4 +483,3 @@ void ksu_sucompat_exit()
} }
ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT); ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT);
} }

View File

@@ -385,11 +385,11 @@ static int do_get_full_version(void __user *arg)
static int do_get_hook_type(void __user *arg) static int do_get_hook_type(void __user *arg)
{ {
struct ksu_hook_type_cmd cmd = {0}; 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"; type = "Tracepoint";
#elif defined(CONFIG_KSU_MANUAL_HOOK) #elif defined(KSU_MANUAL_HOOK)
type = "Manual"; type = "Manual";
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)