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:
@@ -68,19 +68,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
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,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
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_KSU_THRONE_TRACKER_LEGACY),y)
|
ifeq ($(CONFIG_KSU_THRONE_TRACKER_LEGACY),y)
|
||||||
$(info -- KernelSU/compat: using legacy throne tracker)
|
$(info -- KernelSU/compat: using legacy throne tracker)
|
||||||
kernelsu-objs += throne_tracker_legacy.o
|
kernelsu-objs += throne_tracker_legacy.o
|
||||||
@@ -99,15 +95,12 @@ endif
|
|||||||
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
||||||
ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\"
|
ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\"
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
#define TASK_ALLOC_SYMBOL "security_task_alloc"
|
#define TASK_ALLOC_SYMBOL "security_task_alloc"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
#error "Unsupported arch"
|
#error "Unsupported arch"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -144,6 +146,7 @@ static inline bool is_zygote_normal_app_uid(uid_t uid)
|
|||||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||||
|
|
||||||
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;
|
||||||
@@ -255,10 +258,9 @@ static void setup_groups(struct root_profile *profile, struct cred *cred)
|
|||||||
put_group_info(group_info);
|
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
|
// disable seccomp
|
||||||
#if defined(CONFIG_GENERIC_ENTRY) && \
|
#if defined(CONFIG_GENERIC_ENTRY) && \
|
||||||
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||||
@@ -268,54 +270,45 @@ static void disable_seccomp(struct task_struct *tsk)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP
|
#ifdef CONFIG_SECCOMP
|
||||||
tsk->seccomp.mode = 0;
|
current->seccomp.mode = 0;
|
||||||
if (tsk->seccomp.filter) {
|
current->seccomp.filter = NULL;
|
||||||
// 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);
|
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void escape_to_root(void)
|
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) {
|
cred = prepare_creds();
|
||||||
pr_warn("Already root, don't escape!\n");
|
if (!cred) {
|
||||||
|
pr_warn("prepare_creds failed!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
newcreds = prepare_creds();
|
if (cred->euid.val == 0) {
|
||||||
if (newcreds == NULL) {
|
pr_warn("Already root, don't escape!\n");
|
||||||
pr_err("%s: failed to allocate new cred.\n", __func__);
|
|
||||||
#if __SULOG_GATE
|
#if __SULOG_GATE
|
||||||
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed");
|
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed");
|
||||||
#endif
|
#endif
|
||||||
|
abort_creds(cred);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct root_profile *profile =
|
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
|
||||||
ksu_get_root_profile(newcreds->uid.val);
|
|
||||||
|
|
||||||
newcreds->uid.val = profile->uid;
|
cred->uid.val = profile->uid;
|
||||||
newcreds->suid.val = profile->uid;
|
cred->suid.val = profile->uid;
|
||||||
newcreds->euid.val = profile->uid;
|
cred->euid.val = profile->uid;
|
||||||
newcreds->fsuid.val = profile->uid;
|
cred->fsuid.val = profile->uid;
|
||||||
|
|
||||||
newcreds->gid.val = profile->gid;
|
cred->gid.val = profile->gid;
|
||||||
newcreds->fsgid.val = profile->gid;
|
cred->fsgid.val = profile->gid;
|
||||||
newcreds->sgid.val = profile->gid;
|
cred->sgid.val = profile->gid;
|
||||||
newcreds->egid.val = profile->gid;
|
cred->egid.val = profile->gid;
|
||||||
newcreds->securebits = 0;
|
cred->securebits = 0;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
||||||
sizeof(kernel_cap_t));
|
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!
|
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
|
||||||
u64 cap_for_ksud =
|
u64 cap_for_ksud =
|
||||||
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
||||||
memcpy(&newcreds->cap_effective, &cap_for_ksud,
|
memcpy(&cred->cap_effective, &cap_for_ksud,
|
||||||
sizeof(newcreds->cap_effective));
|
sizeof(cred->cap_effective));
|
||||||
memcpy(&newcreds->cap_permitted, &profile->capabilities.effective,
|
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
|
||||||
sizeof(newcreds->cap_permitted));
|
sizeof(cred->cap_permitted));
|
||||||
memcpy(&newcreds->cap_bset, &profile->capabilities.effective,
|
memcpy(&cred->cap_bset, &profile->capabilities.effective,
|
||||||
sizeof(newcreds->cap_bset));
|
sizeof(cred->cap_bset));
|
||||||
|
|
||||||
setup_groups(profile, newcreds);
|
setup_groups(profile, cred);
|
||||||
commit_creds(newcreds);
|
|
||||||
|
|
||||||
|
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);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
disable_seccomp(current);
|
disable_seccomp();
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
|
||||||
setup_selinux(profile->selinux_domain);
|
setup_selinux(profile->selinux_domain);
|
||||||
#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) {
|
||||||
|
ksu_set_task_tracepoint_flag(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
#ifdef CONFIG_KSU_MANUAL_SU
|
||||||
@@ -362,7 +362,10 @@ static void disable_seccomp_for_task(struct task_struct *tsk)
|
|||||||
seccomp_filter_release(tsk);
|
seccomp_filter_release(tsk);
|
||||||
atomic_set(&tsk->seccomp.filter_count, 0);
|
atomic_set(&tsk->seccomp.filter_count, 0);
|
||||||
#else
|
#else
|
||||||
|
// for 6.11+ kernel support?
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
|
||||||
put_seccomp_filter(tsk);
|
put_seccomp_filter(tsk);
|
||||||
|
#endif
|
||||||
tsk->seccomp.filter = NULL;
|
tsk->seccomp.filter = NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -373,6 +376,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);
|
||||||
|
|
||||||
@@ -454,6 +459,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) {
|
||||||
|
ksu_set_task_tracepoint_flag(t);
|
||||||
|
}
|
||||||
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
|
||||||
@@ -1031,6 +1039,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 on private space, see if its possibly the manager
|
// if on private space, see if its possibly the manager
|
||||||
if (new_uid.val > 100000 && new_uid.val % 100000 == ksu_get_manager_uid()) {
|
if (new_uid.val > 100000 && new_uid.val % 100000 == ksu_get_manager_uid()) {
|
||||||
ksu_set_manager_uid(new_uid.val);
|
ksu_set_manager_uid(new_uid.val);
|
||||||
@@ -1042,6 +1056,9 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
|||||||
ksu_install_fd();
|
ksu_install_fd();
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->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(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1053,6 +1070,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(¤t->sighand->siglock);
|
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!
|
// 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;
|
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;
|
||||||
@@ -1170,6 +1201,9 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
|||||||
ksu_install_fd();
|
ksu_install_fd();
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->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(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
return 0;
|
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);
|
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
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!
|
// 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!
|
// 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",
|
pr_info("handle umount ignore non zygote child: %d\n",
|
||||||
current->pid);
|
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)
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0) && defined(CONFIG_KSU_MANUAL_SU)
|
||||||
LSM_HOOK_INIT(task_alloc, ksu_task_alloc),
|
LSM_HOOK_INIT(task_alloc, ksu_task_alloc),
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
#ifndef KSU_KPROBES_HOOK
|
||||||
LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check),
|
LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check),
|
||||||
#endif
|
#endif
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
#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)
|
void __init ksu_core_init(void)
|
||||||
{
|
{
|
||||||
ksu_lsm_hook_init();
|
ksu_lsm_hook_init();
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
int rc = ksu_kprobe_init();
|
int rc = ksu_kprobe_init();
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("ksu_kprobe_init failed: %d\n", rc);
|
pr_err("ksu_kprobe_init failed: %d\n", rc);
|
||||||
@@ -1596,7 +1638,7 @@ void ksu_core_exit(void)
|
|||||||
ksu_sulog_exit();
|
ksu_sulog_exit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
pr_info("ksu_core_kprobe_exit\n");
|
pr_info("ksu_core_kprobe_exit\n");
|
||||||
ksu_kprobe_exit();
|
ksu_kprobe_exit();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,12 +7,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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
15
kernel/ksu.c
15
kernel/ksu.c
@@ -61,10 +61,6 @@ extern void ksu_sucompat_exit(void);
|
|||||||
extern void ksu_ksud_init(void);
|
extern void ksu_ksud_init(void);
|
||||||
extern void ksu_ksud_exit(void);
|
extern void ksu_ksud_exit(void);
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -106,16 +102,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_debug("init ksu driver\n");
|
pr_debug("init ksu driver\n");
|
||||||
#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);
|
||||||
@@ -139,13 +131,10 @@ void kernelsu_exit(void)
|
|||||||
|
|
||||||
destroy_workqueue(ksu_workqueue);
|
destroy_workqueue(ksu_workqueue);
|
||||||
|
|
||||||
#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_sucompat_exit();
|
ksu_sucompat_exit();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
@@ -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);
|
|
||||||
@@ -54,7 +54,7 @@ static void stop_vfs_read_hook(void);
|
|||||||
static void stop_execve_hook(void);
|
static void stop_execve_hook(void);
|
||||||
static void stop_input_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_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;
|
||||||
@@ -83,6 +83,9 @@ void on_post_fs_data(void)
|
|||||||
done = true;
|
done = true;
|
||||||
pr_info("%s!\n", __func__);
|
pr_info("%s!\n", __func__);
|
||||||
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();
|
||||||
@@ -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,
|
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;
|
||||||
}
|
}
|
||||||
@@ -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 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;
|
||||||
}
|
}
|
||||||
@@ -453,7 +456,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)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -670,7 +673,7 @@ int __maybe_unused ksu_handle_compat_execve_ksud(const char __user *filename_use
|
|||||||
|
|
||||||
static void stop_vfs_read_hook(void)
|
static void stop_vfs_read_hook(void)
|
||||||
{
|
{
|
||||||
#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
|
||||||
@@ -681,7 +684,7 @@ static void stop_vfs_read_hook(void)
|
|||||||
|
|
||||||
static void stop_execve_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);
|
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
|
||||||
@@ -696,7 +699,7 @@ static void stop_execve_hook(void)
|
|||||||
|
|
||||||
static void stop_input_hook(void)
|
static void stop_input_hook(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
static bool input_hook_stopped = false;
|
static bool input_hook_stopped = false;
|
||||||
if (input_hook_stopped) {
|
if (input_hook_stopped) {
|
||||||
return;
|
return;
|
||||||
@@ -714,7 +717,7 @@ static void stop_input_hook(void)
|
|||||||
// ksud: module support
|
// ksud: module support
|
||||||
void ksu_ksud_init(void)
|
void ksu_ksud_init(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef KSU_KPROBES_HOOK
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = register_kprobe(&execve_kp);
|
ret = register_kprobe(&execve_kp);
|
||||||
@@ -734,7 +737,7 @@ void ksu_ksud_init(void)
|
|||||||
|
|
||||||
void ksu_ksud_exit(void)
|
void ksu_ksud_exit(void)
|
||||||
{
|
{
|
||||||
#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);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include "linux/cred.h"
|
||||||
|
#include "linux/sched.h"
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include "selinux_defs.h"
|
#include "selinux_defs.h"
|
||||||
#include "../klog.h" // IWYU pragma: keep
|
#include "../klog.h" // IWYU pragma: keep
|
||||||
@@ -101,7 +103,7 @@ static inline u32 current_sid(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_ksu_domain(void)
|
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;
|
||||||
@@ -110,10 +112,17 @@ bool is_ksu_domain(void)
|
|||||||
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) {
|
||||||
@@ -130,9 +139,18 @@ bool is_ksu_domain(void)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
#include "linux/sched.h"
|
||||||
|
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE)
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE)
|
||||||
#define KSU_COMPAT_USE_SELINUX_STATE
|
#define KSU_COMPAT_USE_SELINUX_STATE
|
||||||
@@ -14,9 +15,11 @@ void setenforce(bool);
|
|||||||
|
|
||||||
bool getenforce(void);
|
bool getenforce(void);
|
||||||
|
|
||||||
|
bool is_task_ksu_domain(const struct cred* cred);
|
||||||
|
|
||||||
bool is_ksu_domain(void);
|
bool is_ksu_domain(void);
|
||||||
|
|
||||||
bool is_zygote(void *cred);
|
bool is_zygote(const struct cred* cred);
|
||||||
|
|
||||||
void apply_kernelsu_rules(void);
|
void apply_kernelsu_rules(void);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include "linux/compiler.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,6 +7,7 @@
|
|||||||
#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>
|
||||||
@@ -14,6 +17,8 @@
|
|||||||
#else
|
#else
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <asm/syscall.h>
|
||||||
|
#include <trace/events/syscalls.h>
|
||||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||||
#include <linux/susfs_def.h>
|
#include <linux/susfs_def.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -100,7 +105,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
|||||||
int *__unused_flags)
|
int *__unused_flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
@@ -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)
|
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) {
|
if (!ksu_sucompat_hook_state) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -213,7 +218,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
|||||||
{
|
{
|
||||||
struct filename *filename;
|
struct filename *filename;
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
@@ -270,7 +275,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
|||||||
char path[sizeof(su) + 1];
|
char path[sizeof(su) + 1];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
@@ -327,7 +332,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
|
||||||
@@ -357,41 +362,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)
|
// 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);
|
// Handle newfstatat
|
||||||
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
|
if (unlikely(id == __NR_newfstatat)) {
|
||||||
|
int *dfd = (int *)&PT_REGS_PARM1(regs);
|
||||||
const char __user **filename_user =
|
const char __user **filename_user =
|
||||||
(const char **)&PT_REGS_PARM2(real_regs);
|
(const char __user **)&PT_REGS_PARM2(regs);
|
||||||
int *mode = (int *)&PT_REGS_PARM3(real_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)
|
#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[6];
|
|
||||||
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;
|
||||||
@@ -434,34 +443,82 @@ static void destroy_kprobe(struct kprobe **kp_ptr)
|
|||||||
kfree(kp);
|
kfree(kp);
|
||||||
*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()
|
||||||
void ksu_sucompat_enable(void)
|
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
struct task_struct *p, *t;
|
||||||
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
|
read_lock(&tasklist_lock);
|
||||||
su_kps[1] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre);
|
for_each_process_thread (p, t) {
|
||||||
su_kps[2] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
|
if (!t->mm) { // only user processes
|
||||||
su_kps[3] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
|
continue;
|
||||||
su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre);
|
}
|
||||||
su_kps[5] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
|
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
|
#else
|
||||||
ksu_sucompat_hook_state = true;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_sucompat_disable(void)
|
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\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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,12 +549,7 @@ int susfs_sus_su_working_mode = 0;
|
|||||||
|
|
||||||
static bool ksu_is_su_kps_enabled(void) {
|
static bool ksu_is_su_kps_enabled(void) {
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
int i;
|
destroy_kprobe(&pts_kp);
|
||||||
for (i = 0; i < ARRAY_SIZE(su_kps); i++) {
|
|
||||||
if (su_kps[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user