kernel, manager: Track upstream changes (#195)

* These commits are carefully picked from upstream (tiann/KernelSU)

- Picked range:
8c5f485f27..e5f43a3427

Signed-off-by: Faris <rissu.ntk@gmail.com>
Co-authored-by: Wang Han <416810799@qq.com>
Co-authored-by: TwinbornPlate75 <3342733415@qq.com>
Co-authored-by: KOWX712 <leecc0503@gmail.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
Faris
2025-11-09 07:35:42 +07:00
committed by ShirkNeko
parent 00ea078da7
commit a2211e2909
20 changed files with 565 additions and 257 deletions

22
kernel/.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
.cache/
.thinlto-cache/
compile_commands.json
*.ko
*.o
*.mod
*.lds
*.mod.o
.*.o*
.*.mod*
*.ko*
*.mod.c
*.symvers*
*.order
.*.ko.cmd
.tmp_versions/
libs/
obj/
CLAUDE.md
.ddk-version
.vscode/settings.json

View File

@@ -118,10 +118,15 @@ endif
ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
endif endif
ifeq ($(shell grep -q "task_security_struct\s\+\*selinux_cred" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
ccflags-y += -DKSU_OPTIONAL_SELINUX_CRED
endif
# Check if __poll_t is available # Check if __poll_t exists in linux or uapi types headers (handles backports)
ifeq ($(shell grep -q "__poll_t" $(srctree)/include/linux/poll.h; echo $$?),1) ifneq ($(shell grep -q "__poll_t" \
ccflags-y += -DKSU_NEED_POLL_T_DEF $(srctree)/include/linux/types.h \
$(srctree)/include/uapi/linux/types.h; echo $$?),0)
ccflags-y += -DKSU_NO___POLL_T
endif endif
ifeq ($(shell grep -q "anon_inode_getfd_secure" $(srctree)/fs/anon_inodes.c; echo $$?),0) ifeq ($(shell grep -q "anon_inode_getfd_secure" $(srctree)/fs/anon_inodes.c; echo $$?),0)
@@ -178,7 +183,7 @@ else
$(info -- KPM is disabled) $(info -- KPM is disabled)
endif endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-missing-prototypes ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-missing-prototypes
# Keep a new line here!! Because someone may append config # Keep a new line here!! Because someone may append config

View File

@@ -1,3 +1,5 @@
#include <linux/mutex.h>
#include <linux/task_work.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/fs.h> #include <linux/fs.h>
@@ -8,6 +10,11 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include <linux/sched/task.h>
#else
#include <linux/sched.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include <linux/compiler_types.h> #include <linux/compiler_types.h>
#endif #endif
@@ -93,10 +100,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 persistent_allow_list(void);
static struct work_struct ksu_load_work;
bool persistent_allow_list(void);
void ksu_show_allow_list(void) void ksu_show_allow_list(void)
{ {
@@ -231,9 +235,9 @@ out:
} else { } else {
if (profile->allow_su) { if (profile->allow_su) {
/* /*
* 1024 apps with uid higher than BITMAP_UID_MAX * 1024 apps with uid higher than BITMAP_UID_MAX
* registered to request superuser? * registered to request superuser?
*/ */
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
pr_err("too many apps registered\n"); pr_err("too many apps registered\n");
WARN_ON(1); WARN_ON(1);
@@ -270,11 +274,6 @@ bool __ksu_is_allow_uid(uid_t uid)
{ {
int i; int i;
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
}
if (forbid_system_uid(uid)) { if (forbid_system_uid(uid)) {
// do not bother going through the list if it's system // do not bother going through the list if it's system
return false; return false;
@@ -299,6 +298,15 @@ bool __ksu_is_allow_uid(uid_t uid)
return false; return false;
} }
bool __ksu_is_allow_uid_for_current(uid_t uid)
{
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
}
return __ksu_is_allow_uid(uid);
}
bool ksu_uid_should_umount(uid_t uid) bool ksu_uid_should_umount(uid_t uid)
{ {
struct app_profile profile = { .current_uid = uid }; struct app_profile profile = { .current_uid = uid };
@@ -360,7 +368,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true; return true;
} }
void do_save_allow_list(struct work_struct *work) static void do_persistent_allow_list(struct callback_head *_cb)
{ {
u32 magic = FILE_MAGIC; u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION; u32 version = FILE_FORMAT_VERSION;
@@ -368,11 +376,13 @@ void do_save_allow_list(struct work_struct *work)
struct list_head *pos = NULL; struct list_head *pos = NULL;
loff_t off = 0; loff_t off = 0;
mutex_lock(&allowlist_mutex);
struct file *fp = ksu_filp_open_compat( struct file *fp = ksu_filp_open_compat(
KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644); KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (IS_ERR(fp)) { if (IS_ERR(fp)) {
pr_err("save_allow_list create file failed: %ld\n", pr_err("save_allow_list create file failed: %ld\n",
PTR_ERR(fp)); PTR_ERR(fp));
mutex_unlock(&allowlist_mutex);
return; return;
} }
@@ -391,7 +401,7 @@ void do_save_allow_list(struct work_struct *work)
list_for_each (pos, &allow_list) { list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list); p = list_entry(pos, struct perm_data, list);
pr_info("save allow list, name: %s uid: %d, allow: %d\n", pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid, p->profile.key, p->profile.current_uid,
p->profile.allow_su); p->profile.allow_su);
@@ -401,9 +411,38 @@ void do_save_allow_list(struct work_struct *work)
exit: exit:
filp_close(fp, 0); filp_close(fp, 0);
mutex_unlock(&allowlist_mutex);
} }
void do_load_allow_list(struct work_struct *work) void persistent_allow_list(void)
{
struct task_struct *tsk;
tsk = get_pid_task(find_vpid(1), PIDTYPE_PID);
if (!tsk) {
pr_err("save_allow_list find init task err\n");
return;
}
struct callback_head *cb =
kzalloc(sizeof(struct callback_head), GFP_KERNEL);
if (!cb) {
pr_err("save_allow_list alloc cb err\b");
goto put_task;
}
cb->func = do_persistent_allow_list;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 8)
task_work_add(tsk, cb, TWA_RESUME);
#else
task_work_add(tsk, cb, true);
#endif
put_task:
put_task_struct(tsk);
}
void ksu_load_allow_list(void)
{ {
loff_t off = 0; loff_t off = 0;
ssize_t ret = 0; ssize_t ret = 0;
@@ -494,17 +533,6 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
} }
} }
// make sure allow list works cross boot
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;
@@ -517,9 +545,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();
} }
@@ -528,7 +553,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); persistent_allow_list();
// free allowlist // free allowlist
mutex_lock(&allowlist_mutex); mutex_lock(&allowlist_mutex);

View File

@@ -8,13 +8,19 @@ 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);
// Check if the uid is in allow list
bool __ksu_is_allow_uid(uid_t uid); bool __ksu_is_allow_uid(uid_t uid);
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid)) #define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
// Check if the uid is in allow list, or current is ksu domain root
bool __ksu_is_allow_uid_for_current(uid_t uid);
#define ksu_is_allow_uid_for_current(uid) \
unlikely(__ksu_is_allow_uid_for_current(uid))
bool ksu_get_allow_list(int *array, int *length, bool allow); bool ksu_get_allow_list(int *array, int *length, bool allow);
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *),

View File

@@ -1,3 +1,10 @@
#include <linux/compiler.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include <linux/sched/task_stack.h>
#else
#include <linux/sched.h>
#endif
#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>
@@ -22,7 +29,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/uidgid.h> #include <linux/uidgid.h>
#include <linux/version.h>
#ifndef KSU_HAS_PATH_UMOUNT #ifndef KSU_HAS_PATH_UMOUNT
#include <linux/syscalls.h> // sys_umount (<4.17) & ksys_umount (4.17+) #include <linux/syscalls.h> // sys_umount (<4.17) & ksys_umount (4.17+)
#endif #endif
@@ -42,6 +48,7 @@
#include "throne_comm.h" #include "throne_comm.h"
#include "kernel_compat.h" #include "kernel_compat.h"
#include "supercalls.h" #include "supercalls.h"
#include "sucompat.h"
bool ksu_module_mounted __read_mostly = false; bool ksu_module_mounted __read_mostly = false;
@@ -56,6 +63,7 @@ bool ksu_is_compat __read_mostly = false;
#endif #endif
static bool ksu_kernel_umount_enabled = true; static bool ksu_kernel_umount_enabled = true;
static bool ksu_enhanced_security_enabled = false;
static int kernel_umount_feature_get(u64 *value) static int kernel_umount_feature_get(u64 *value)
{ {
@@ -78,13 +86,34 @@ static const struct ksu_feature_handler kernel_umount_handler = {
.set_handler = kernel_umount_feature_set, .set_handler = kernel_umount_feature_set,
}; };
static int enhanced_security_feature_get(u64 *value)
{
*value = ksu_enhanced_security_enabled ? 1 : 0;
return 0;
}
static int enhanced_security_feature_set(u64 value)
{
bool enable = value != 0;
ksu_enhanced_security_enabled = enable;
pr_info("enhanced_security: set to %d\n", enable);
return 0;
}
static const struct ksu_feature_handler enhanced_security_handler = {
.feature_id = KSU_FEATURE_ENHANCED_SECURITY,
.name = "enhanced_security",
.get_handler = enhanced_security_feature_get,
.set_handler = enhanced_security_feature_set,
};
static inline bool is_allow_su(void) static inline bool is_allow_su(void)
{ {
if (is_manager()) { if (is_manager()) {
// we are manager, allow! // we are manager, allow!
return true; return true;
} }
return ksu_is_allow_uid(current_uid().val); return ksu_is_allow_uid_for_current(current_uid().val);
} }
static inline bool is_unsupported_uid(uid_t uid) static inline bool is_unsupported_uid(uid_t uid)
@@ -179,6 +208,10 @@ static void disable_seccomp(struct task_struct *tsk)
void escape_to_root(void) void escape_to_root(void)
{ {
struct cred *cred; struct cred *cred;
#ifdef KSU_SHOULD_USE_NEW_TP
struct task_struct *p = current;
struct task_struct *t;
#endif
cred = prepare_creds(); cred = prepare_creds();
if (!cred) { if (!cred) {
@@ -229,8 +262,15 @@ void escape_to_root(void)
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain); setup_selinux(profile->selinux_domain);
#ifdef KSU_SHOULD_USE_NEW_TP
for_each_thread (p, t) {
ksu_set_task_tracepoint_flag(t);
}
#endif
} }
extern void ext4_unregister_sysfs(struct super_block *sb);
void nuke_ext4_sysfs(void) void nuke_ext4_sysfs(void)
{ {
#ifdef CONFIG_EXT4_FS #ifdef CONFIG_EXT4_FS
@@ -244,12 +284,13 @@ void nuke_ext4_sysfs(void)
struct super_block *sb = path.dentry->d_inode->i_sb; struct super_block *sb = path.dentry->d_inode->i_sb;
const char *name = sb->s_type->name; const char *name = sb->s_type->name;
if (strcmp(name, "ext4") != 0) { if (strcmp(name, "ext4") != 0) {
pr_info("skipping s_type: %s\n", name); pr_info("nuke_module: skipping s_type: %s\n", name);
path_put(&path); path_put(&path);
return; return;
} }
ext4_unregister_sysfs(sb); ext4_unregister_sysfs(sb);
pr_info("nuke_module: ext4 sysfs unregistered.n\n");
path_put(&path); path_put(&path);
#endif #endif
} }
@@ -285,6 +326,7 @@ static bool should_umount(struct path *path)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || \ #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || \
defined(KSU_HAS_PATH_UMOUNT) defined(KSU_HAS_PATH_UMOUNT)
extern int path_umount(struct path *path, int flags);
#define ksu_umount_mnt(__unused, path, flags) (path_umount(path, flags)) #define ksu_umount_mnt(__unused, path, flags) (path_umount(path, flags))
#else #else
static int ksu_sys_umount(const char *mnt, int flags) static int ksu_sys_umount(const char *mnt, int flags)
@@ -384,6 +426,14 @@ static void umount_tw_func(struct callback_head *cb)
} }
#endif #endif
// force_sig kcompat, TODO: move it out of core_hook.c
// https://elixir.bootlin.com/linux/v5.3-rc1/source/kernel/signal.c#L1613
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
#define __force_sig(sig) force_sig(sig)
#else
#define __force_sig(sig) force_sig(sig, current)
#endif
int ksu_handle_setuid(struct cred *new, const struct cred *old) int ksu_handle_setuid(struct cred *new, const struct cred *old)
{ {
if (!new || !old) { if (!new || !old) {
@@ -396,9 +446,39 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
if (0 != old_uid.val) { if (0 != old_uid.val) {
// old process is not root, ignore it. // old process is not root, ignore it.
if (ksu_enhanced_security_enabled) {
// disallow any non-ksu domain escalation from non-root to root!
if (unlikely(new_uid.val) == 0) {
if (!is_ksu_domain()) {
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
current->pid, current->comm,
old_uid.val, new_uid.val);
__force_sig(SIGKILL);
return 0;
}
}
// disallow appuid decrease to any other uid if it is allowed to su
if (is_appuid(old_uid)) {
if (new_uid.val < old_uid.val &&
!ksu_is_allow_uid_for_current(
old_uid.val)) {
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
current->pid, current->comm,
old_uid.val, new_uid.val);
__force_sig(SIGKILL);
return 0;
}
}
}
return 0; return 0;
} }
#ifdef KSU_SHOULD_USE_NEW_TP
if (new_uid.val == 2000 && ksu_su_compat_enabled) {
ksu_set_task_tracepoint_flag(current);
}
#endif
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;
@@ -417,10 +497,11 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
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);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
ksu_set_task_tracepoint_flag(current);
return 0; return 0;
} }
if (ksu_is_allow_uid(new_uid.val)) { if (ksu_is_allow_uid_for_current(new_uid.val)) {
if (current->seccomp.mode == SECCOMP_MODE_FILTER && if (current->seccomp.mode == SECCOMP_MODE_FILTER &&
current->seccomp.filter) { current->seccomp.filter) {
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
@@ -428,9 +509,17 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
__NR_reboot); __NR_reboot);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
} }
if (ksu_su_compat_enabled) {
ksu_set_task_tracepoint_flag(current);
}
} else {
if (ksu_su_compat_enabled) {
// Disable syscall tracepoint sucompat for non-allowed processes
ksu_clear_task_tracepoint_flag(current);
}
} }
#else #else
if (ksu_is_allow_uid(new_uid.val)) { if (ksu_is_allow_uid_for_current(new_uid.val)) {
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
disable_seccomp(current); disable_seccomp(current);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
@@ -465,7 +554,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!
if (!is_zygote(old->security)) { if (!is_zygote(old)) {
pr_info("handle umount ignore non zygote child: %d\n", pr_info("handle umount ignore non zygote child: %d\n",
current->pid); current->pid);
return 0; return 0;
@@ -706,6 +795,10 @@ void __init ksu_core_init(void)
if (ksu_register_feature_handler(&kernel_umount_handler)) { if (ksu_register_feature_handler(&kernel_umount_handler)) {
pr_err("Failed to register umount feature handler\n"); pr_err("Failed to register umount feature handler\n");
} }
if (ksu_register_feature_handler(&enhanced_security_handler)) {
pr_err("Failed to register enhanced security feature handler\n");
}
} }
void ksu_core_exit(void) void ksu_core_exit(void)
@@ -723,13 +816,20 @@ void __init ksu_core_init(void)
if (ksu_register_feature_handler(&kernel_umount_handler)) { if (ksu_register_feature_handler(&kernel_umount_handler)) {
pr_err("Failed to register umount feature handler\n"); pr_err("Failed to register umount feature handler\n");
} }
if (ksu_register_feature_handler(&enhanced_security_handler)) {
pr_err("Failed to register enhanced security feature handler\n");
}
} }
void ksu_core_exit(void) void ksu_core_exit(void)
{ {
ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT); ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT);
ksu_uid_exit(); ksu_uid_exit();
ksu_throne_comm_exit(); ksu_throne_comm_exit();
ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY);
} }
#endif #endif

View File

@@ -6,6 +6,7 @@
enum ksu_feature_id { enum ksu_feature_id {
KSU_FEATURE_SU_COMPAT = 0, KSU_FEATURE_SU_COMPAT = 0,
KSU_FEATURE_KERNEL_UMOUNT = 1, KSU_FEATURE_KERNEL_UMOUNT = 1,
KSU_FEATURE_ENHANCED_SECURITY = 2,
KSU_FEATURE_MAX KSU_FEATURE_MAX
}; };

View File

@@ -18,6 +18,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/cred.h> #include <linux/cred.h>
extern int install_session_keyring_to_cred(struct cred *, struct key *);
struct key *init_session_keyring = NULL; struct key *init_session_keyring = NULL;
static inline int install_session_keyring(struct key *keyring) static inline int install_session_keyring(struct key *keyring)
{ {
@@ -38,50 +39,6 @@ static inline int install_session_keyring(struct key *keyring)
} }
#endif #endif
extern struct task_struct init_task;
// mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA
struct ksu_ns_fs_saved {
struct nsproxy *ns;
struct fs_struct *fs;
};
static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
{
ns_fs_saved->ns = current->nsproxy;
ns_fs_saved->fs = current->fs;
}
static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
{
current->nsproxy = ns_fs_saved->ns;
current->fs = ns_fs_saved->fs;
}
static bool android_context_saved_checked = false;
static bool android_context_saved_enabled = false;
static struct ksu_ns_fs_saved android_context_saved;
void ksu_android_ns_fs_check(void)
{
if (android_context_saved_checked)
return;
android_context_saved_checked = true;
task_lock(current);
if (current->nsproxy && current->fs &&
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
android_context_saved_enabled = true;
#ifdef CONFIG_KSU_DEBUG
pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n",
current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
#endif
ksu_save_ns_fs(&android_context_saved);
} else {
pr_info("android context saved disabled\n");
}
task_unlock(current);
}
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
@@ -92,27 +49,7 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
install_session_keyring(init_session_keyring); install_session_keyring(init_session_keyring);
} }
#endif #endif
// switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns return filp_open(filename, flags, mode);
struct ksu_ns_fs_saved saved;
if (android_context_saved_enabled) {
#ifdef CONFIG_KSU_DEBUG
pr_info("start switch current nsproxy and fs to android context\n");
#endif
task_lock(current);
ksu_save_ns_fs(&saved);
ksu_load_ns_fs(&android_context_saved);
task_unlock(current);
}
struct file *fp = filp_open(filename, flags, mode);
if (android_context_saved_enabled) {
task_lock(current);
ksu_load_ns_fs(&saved);
task_unlock(current);
#ifdef CONFIG_KSU_DEBUG
pr_info("switch current nsproxy and fs back to saved successfully\n");
#endif
}
return fp;
} }
ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,

View File

@@ -27,6 +27,10 @@
#endif #endif
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && defined(KSU_KPROBE_HOOK)
#define KSU_SHOULD_USE_NEW_TP
#endif
extern long ksu_strncpy_from_user_nofault(char *dst, extern long ksu_strncpy_from_user_nofault(char *dst,
const void __user *unsafe_addr, const void __user *unsafe_addr,
long count); long count);
@@ -38,7 +42,7 @@ extern long ksu_strncpy_from_user_retry(char *dst,
defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
extern struct key *init_session_keyring; extern struct key *init_session_keyring;
#endif #endif
extern void ksu_android_ns_fs_check(void);
extern struct file *ksu_filp_open_compat(const char *filename, int flags, extern struct file *ksu_filp_open_compat(const char *filename, int flags,
umode_t mode); umode_t mode);
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,

View File

@@ -5,7 +5,6 @@
#include <generated/utsrelease.h> #include <generated/utsrelease.h>
#include <generated/compile.h> #include <generated/compile.h>
#include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION macros */ #include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION macros */
#include <linux/workqueue.h>
#include "allowlist.h" #include "allowlist.h"
#include "arch.h" #include "arch.h"
@@ -18,14 +17,10 @@
#include "ksud.h" #include "ksud.h"
#include "supercalls.h" #include "supercalls.h"
static struct workqueue_struct *ksu_workqueue; extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags);
bool ksu_queue_work(struct work_struct *work) extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
{ void *argv, void *envp, int *flags);
return queue_work(ksu_workqueue, work);
}
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
void *envp, int *flags) void *envp, int *flags)
{ {
@@ -55,17 +50,13 @@ int __init kernelsu_init(void)
ksu_core_init(); ksu_core_init();
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
ksu_allowlist_init(); ksu_allowlist_init();
ksu_throne_tracker_init(); ksu_throne_tracker_init();
ksu_sucompat_init(); ksu_sucompat_init();
#ifdef KSU_KPROBES_HOOK
ksu_ksud_init(); ksu_ksud_init();
#endif
#ifdef MODULE #ifdef MODULE
#ifndef CONFIG_KSU_DEBUG #ifndef CONFIG_KSU_DEBUG
@@ -75,6 +66,7 @@ int __init kernelsu_init(void)
return 0; return 0;
} }
extern void ksu_observer_exit(void);
void kernelsu_exit(void) void kernelsu_exit(void)
{ {
ksu_allowlist_exit(); ksu_allowlist_exit();
@@ -85,13 +77,12 @@ void kernelsu_exit(void)
destroy_workqueue(ksu_workqueue); destroy_workqueue(ksu_workqueue);
#ifdef KSU_KPROBES_HOOK
ksu_ksud_exit(); ksu_ksud_exit();
#endif
ksu_sucompat_exit(); ksu_sucompat_exit();
ksu_core_exit(); ksu_core_exit();
ksu_feature_exit(); ksu_feature_exit();
} }

View File

@@ -95,8 +95,7 @@ struct app_profile {
}; };
}; };
bool ksu_queue_work(struct work_struct *work); #if 0
static inline int startswith(char *s, char *prefix) static inline int startswith(char *s, char *prefix)
{ {
return strncmp(s, prefix, strlen(prefix)); return strncmp(s, prefix, strlen(prefix));
@@ -110,5 +109,6 @@ static inline int endswith(const char *s, const char *t)
return 1; return 1;
return strcmp(s + slen - tlen, t); return strcmp(s + slen - tlen, t);
} }
#endif
#endif #endif

View File

@@ -1,3 +1,6 @@
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <linux/task_work.h>
#include <asm/current.h> #include <asm/current.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/cred.h> #include <linux/cred.h>
@@ -26,6 +29,8 @@
#include "ksud.h" #include "ksud.h"
#include "kernel_compat.h" #include "kernel_compat.h"
#include "selinux/selinux.h" #include "selinux/selinux.h"
#include "manager.h"
#include "sucompat.h"
static const char KERNEL_SU_RC[] = static const char KERNEL_SU_RC[] =
"\n" "\n"
@@ -79,6 +84,7 @@ 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();
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();
@@ -102,6 +108,13 @@ struct user_arg_ptr {
} ptr; } ptr;
}; };
static void on_post_fs_data_cbfun(struct callback_head *cb)
{
on_post_fs_data();
}
static struct callback_head on_post_fs_data_cb = { .func = on_post_fs_data_cbfun };
// since _ksud handler only uses argv and envp for comparisons // since _ksud handler only uses argv and envp for comparisons
// this can probably work // this can probably work
// adapted from ksu_handle_execveat_ksud // adapted from ksu_handle_execveat_ksud
@@ -146,7 +159,6 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c
pr_info("%s: /system/bin/init second_stage executed\n", __func__); pr_info("%s: /system/bin/init second_stage executed\n", __func__);
apply_kernelsu_rules(); apply_kernelsu_rules();
init_second_stage_executed = true; init_second_stage_executed = true;
ksu_android_ns_fs_check();
} }
} }
@@ -157,7 +169,6 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c
pr_info("%s: /init --second-stage executed\n", __func__); pr_info("%s: /init --second-stage executed\n", __func__);
apply_kernelsu_rules(); apply_kernelsu_rules();
init_second_stage_executed = true; init_second_stage_executed = true;
ksu_android_ns_fs_check();
} }
} }
@@ -184,15 +195,25 @@ static int ksu_handle_bprm_ksud(const char *filename, const char *argv1, const c
pr_info("%s: /init +envp: INIT_SECOND_STAGE executed\n", __func__); pr_info("%s: /init +envp: INIT_SECOND_STAGE executed\n", __func__);
apply_kernelsu_rules(); apply_kernelsu_rules();
init_second_stage_executed = true; init_second_stage_executed = true;
ksu_android_ns_fs_check();
} }
} }
first_app_process: first_app_process:
if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) { if (first_app_process && !memcmp(filename, app_process, sizeof(app_process) - 1)) {
first_app_process = false; first_app_process = false;
pr_info("%s: exec app_process, /data prepared, second_stage: %d\n", __func__, init_second_stage_executed); pr_info("exec app_process, /data prepared, second_stage: %d\n",
on_post_fs_data(); init_second_stage_executed);
struct task_struct *init_task;
rcu_read_lock();
init_task = rcu_dereference(current->real_parent);
if (init_task) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 8)
task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME);
#else
task_work_add(init_task, &on_post_fs_data_cb, true);
#endif
}
rcu_read_unlock();
stop_execve_hook(); stop_execve_hook();
} }

View File

@@ -40,6 +40,4 @@ static inline void ksu_invalidate_manager_uid(void)
} }
int ksu_observer_init(void); int ksu_observer_init(void);
void ksu_observer_exit(void);
#endif #endif

View File

@@ -186,6 +186,13 @@ static int get_object(char *buf, char __user *user_object, size_t buf_sz,
return 0; return 0;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) || \
!defined(KSU_COMPAT_USE_SELINUX_STATE)
extern int avc_ss_reset(u32 seqno);
#else
extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
#endif
// reset avc cache table, otherwise the new rules will not take effect if already denied // reset avc cache table, otherwise the new rules will not take effect if already denied
static void reset_avc_cache(void) static void reset_avc_cache(void)
{ {

View File

@@ -1,4 +1,7 @@
#include <linux/version.h> #include "linux/cred.h"
#include "linux/sched.h"
#include "linux/security.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
@@ -24,14 +27,12 @@ static int transive_to_domain(const char *domain)
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
domain, sid, error); domain, sid, error);
} }
if (!error) { if (!error) {
tsec->sid = sid; tsec->sid = sid;
tsec->create_sid = 0; tsec->create_sid = 0;
tsec->keycreate_sid = 0; tsec->keycreate_sid = 0;
tsec->sockcreate_sid = 0; tsec->sockcreate_sid = 0;
} }
return error; return error;
} }
@@ -93,65 +94,68 @@ static inline u32 current_sid(void)
} }
#endif #endif
bool is_ksu_domain(void) #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 14, 0)
struct lsm_context {
char *context;
u32 len;
};
static int __security_secid_to_secctx(u32 secid, struct lsm_context *cp)
{ {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) return security_secid_to_secctx(secid, &cp->context, &cp->len);
struct lsm_context ctx; }
static void __security_release_secctx(struct lsm_context *cp)
{
return security_release_secctx(cp->context, cp->len);
}
#else #else
char *domain; #define __security_secid_to_secctx security_secid_to_secctx
u32 seclen; #define __security_release_secctx security_release_secctx
#endif
bool result;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
int err = security_secid_to_secctx(current_sid(), &ctx);
#else
int err = security_secid_to_secctx(current_sid(), &domain, &seclen);
#endif #endif
if (err) { bool is_task_ksu_domain(const struct cred *cred)
{
struct lsm_context ctx;
bool result;
if (!cred) {
return false; return false;
} }
const struct task_security_struct *tsec = __selinux_cred(cred);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0;
security_release_secctx(&ctx);
#else
result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
security_release_secctx(domain, seclen);
#endif
return result;
}
bool is_zygote(void *sec)
{
struct task_security_struct *tsec = (struct task_security_struct *)sec;
if (!tsec) { if (!tsec) {
return false; return false;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) int err = __security_secid_to_secctx(tsec->sid, &ctx);
struct lsm_context ctx;
#else
char *domain;
u32 seclen;
#endif
bool result;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
int err = security_secid_to_secctx(tsec->sid, &ctx);
#else
int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
#endif
if (err) { if (err) {
return false; return false;
} }
result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0;
__security_release_secctx(&ctx);
return result;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) bool is_ksu_domain(void)
{
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;
}
struct lsm_context ctx;
bool result;
int err = __security_secid_to_secctx(tsec->sid, &ctx);
if (err) {
return false;
}
result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0; result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0;
security_release_secctx(&ctx); __security_release_secctx(&ctx);
#else
result = strncmp("u:r:zygote:s0", domain, seclen) == 0;
security_release_secctx(domain, seclen);
#endif
return result; return result;
} }

View File

@@ -1,8 +1,9 @@
#ifndef __KSU_H_SELINUX #ifndef __KSU_H_SELINUX
#define __KSU_H_SELINUX #define __KSU_H_SELINUX
#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)) || \ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || \
defined(KSU_COMPAT_HAS_SELINUX_STATE) defined(KSU_COMPAT_HAS_SELINUX_STATE)
@@ -13,11 +14,13 @@ void setup_selinux(const char *);
void setenforce(bool); void setenforce(bool);
bool is_task_ksu_domain(const struct cred *cred);
bool getenforce(void); bool getenforce(void);
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);

View File

@@ -33,4 +33,10 @@
#define __setenforce(val) #define __setenforce(val)
#endif #endif
#ifdef KSU_OPTIONAL_SELINUX_CRED
#define __selinux_cred(cred) (selinux_cred(cred))
#else
#define __selinux_cred(cred) (cred->security)
#endif
#endif #endif

View File

@@ -30,8 +30,80 @@
static const char su[] = SU_PATH; static const char su[] = SU_PATH;
static const char ksud_path[] = KSUD_PATH; static const char ksud_path[] = KSUD_PATH;
bool ksu_su_compat_enabled __read_mostly = true;
static bool ksu_su_compat_enabled __read_mostly = true; #ifdef KSU_SHOULD_USE_NEW_TP
#include "linux/compiler.h"
#include "linux/printk.h"
#include "selinux/selinux.h"
#include <linux/tracepoint.h>
#include <linux/spinlock.h>
#include <asm/syscall.h>
#include <trace/events/syscalls.h>
void ksu_mark_running_process(void)
{
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 handle_process_mark(bool mark)
{
struct task_struct *p, *t;
read_lock(&tasklist_lock);
for_each_process_thread (p, t) {
if (mark)
ksu_set_task_tracepoint_flag(t);
else
ksu_clear_task_tracepoint_flag(t);
}
read_unlock(&tasklist_lock);
}
static void mark_all_process(void)
{
handle_process_mark(true);
pr_info("sucompat: mark all user process done!\n");
}
static void unmark_all_process(void)
{
handle_process_mark(false);
pr_info("sucompat: unmark all user process done!\n");
}
#else
void ksu_mark_running_process(void)
{
}
static void handle_process_mark(bool mark)
{
}
static void mark_all_process(void)
{
}
static void unmark_all_process(void)
{
}
#endif
static int su_compat_feature_get(u64 *value) static int su_compat_feature_get(u64 *value)
{ {
@@ -93,7 +165,7 @@ static inline bool __is_su_allowed(const void *ptr_to_check)
if (!ksu_su_compat_enabled) if (!ksu_su_compat_enabled)
return false; return false;
#endif #endif
if (likely(!ksu_is_allow_uid(current_uid().val))) if (!ksu_is_allow_uid_for_current(current_uid().val))
return false; return false;
if (unlikely(!ptr_to_check)) if (unlikely(!ptr_to_check))
@@ -209,86 +281,150 @@ int __ksu_handle_devpts(struct inode *inode)
return 0; return 0;
} }
#ifdef KSU_KPROBES_HOOK #ifdef KSU_SHOULD_USE_NEW_TP
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
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)) {
const char __user **filename_user = int *dfd = (int *)&PT_REGS_PARM1(regs);
(const char **)&PT_REGS_PARM2(real_regs); const char __user **filename_user =
int *mode = (int *)&PT_REGS_PARM3(real_regs); (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) #endif // CONFIG_HAVE_SYSCALL_TRACEPOINTS
#ifdef CONFIG_KRETPROBES
static struct kretprobe *init_kretprobe(const char *name,
kretprobe_handler_t handler)
{ {
struct pt_regs *real_regs = PT_REAL_REGS(regs); struct kretprobe *rp = kzalloc(sizeof(struct kretprobe), GFP_KERNEL);
int *dfd = (int *)&PT_REGS_PARM1(real_regs); if (!rp)
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);
}
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);
}
#ifdef CONFIG_COMPAT
static struct kprobe *su_kps[5];
#else
static struct kprobe *su_kps[3];
#endif
static struct kprobe *init_kprobe(const char *name,
kprobe_pre_handler_t handler)
{
struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
if (!kp)
return NULL; return NULL;
kp->symbol_name = name; rp->kp.symbol_name = name;
kp->pre_handler = handler; rp->handler = handler;
rp->data_size = 0;
rp->maxactive = 0;
int ret = register_kprobe(kp); int ret = register_kretprobe(rp);
pr_info("sucompat: register_%s kprobe: %d\n", name, ret); pr_info("sucompat: register_%s kretprobe: %d\n", name, ret);
if (ret) { if (ret) {
kfree(kp); kfree(rp);
return NULL; return NULL;
} }
return kp; return rp;
} }
static void destroy_kprobe(struct kprobe **kp_ptr) static void destroy_kretprobe(struct kretprobe **rp_ptr)
{ {
struct kprobe *kp = *kp_ptr; struct kretprobe *rp = *rp_ptr;
if (!kp) if (!rp)
return; return;
unregister_kprobe(kp); unregister_kretprobe(rp);
synchronize_rcu(); synchronize_rcu();
kfree(kp); kfree(rp);
*kp_ptr = NULL; *rp_ptr = NULL;
} }
static int tracepoint_reg_count = 0;
static DEFINE_SPINLOCK(tracepoint_reg_lock);
static int syscall_regfunc_handler(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
unsigned long flags;
spin_lock_irqsave(&tracepoint_reg_lock, flags);
if (tracepoint_reg_count < 1) {
// while install our tracepoint, mark our processes
unmark_all_process();
ksu_mark_running_process();
} else {
// while installing other tracepoint, mark all processes
mark_all_process();
}
tracepoint_reg_count++;
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
return 0;
}
static int syscall_unregfunc_handler(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
unsigned long flags;
spin_lock_irqsave(&tracepoint_reg_lock, flags);
if (tracepoint_reg_count <= 1) {
// while uninstall our tracepoint, unmark all processes
unmark_all_process();
} else {
// while uninstalling other tracepoint, mark our processes
unmark_all_process();
ksu_mark_running_process();
}
tracepoint_reg_count--;
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
return 0;
}
static struct kretprobe *syscall_regfunc_rp = NULL;
static struct kretprobe *syscall_unregfunc_rp = NULL;
#endif
#endif #endif
void ksu_sucompat_enable(void) void ksu_sucompat_enable(void)
{ {
#ifdef KSU_KPROBES_HOOK #ifdef KSU_SHOULD_USE_NEW_TP
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre); int ret;
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre); pr_info("sucompat: ksu_sucompat_enable called\n");
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
#ifdef CONFIG_COMPAT #ifdef CONFIG_KRETPROBES
su_kps[3] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre); // Register kretprobe for syscall_regfunc
su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre); syscall_regfunc_rp =
init_kretprobe("syscall_regfunc", syscall_regfunc_handler);
// Register kretprobe for syscall_unregfunc
syscall_unregfunc_rp =
init_kretprobe("syscall_unregfunc", syscall_unregfunc_handler);
#endif
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
ret = register_trace_sys_enter(sucompat_sys_enter_handler, NULL);
#ifndef CONFIG_KRETPROBES
unmark_all_process();
ksu_mark_running_process();
#endif
if (ret) {
pr_err("sucompat: failed to register sys_enter tracepoint: %d\n",
ret);
} else {
pr_info("sucompat: sys_enter tracepoint registered\n");
}
#endif #endif
#else #else
ksu_su_compat_enabled = true; ksu_su_compat_enabled = true;
@@ -298,11 +434,18 @@ void ksu_sucompat_enable(void)
void ksu_sucompat_disable(void) void ksu_sucompat_disable(void)
{ {
#ifdef KSU_KPROBES_HOOK #ifdef KSU_SHOULD_USE_NEW_TP
int i; pr_info("sucompat: ksu_sucompat_disable called\n");
for (i = 0; i < ARRAY_SIZE(su_kps); i++) { #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
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");
#endif
#ifdef CONFIG_KRETPROBES
destroy_kretprobe(&syscall_regfunc_rp);
destroy_kretprobe(&syscall_unregfunc_rp);
#endif
#else #else
ksu_su_compat_enabled = false; ksu_su_compat_enabled = false;
pr_info("deinit sucompat\n"); pr_info("deinit sucompat\n");
@@ -315,6 +458,7 @@ void ksu_sucompat_init(void)
if (ksu_register_feature_handler(&su_compat_handler)) { if (ksu_register_feature_handler(&su_compat_handler)) {
pr_err("Failed to register su_compat feature handler\n"); pr_err("Failed to register su_compat feature handler\n");
} }
if (ksu_su_compat_enabled) { if (ksu_su_compat_enabled) {
ksu_sucompat_enable(); ksu_sucompat_enable();
} }

View File

@@ -3,15 +3,47 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/version.h> #include <linux/version.h>
extern bool ksu_su_compat_enabled;
void ksu_sucompat_init(void); void ksu_sucompat_init(void);
void ksu_sucompat_exit(void); void ksu_sucompat_exit(void);
void ksu_sucompat_enable(void); void ksu_sucompat_enable(void);
void ksu_sucompat_disable(void); void ksu_sucompat_disable(void);
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, void ksu_mark_running_process(void);
void *argv, void *envp, int *flags);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && defined(KSU_KPROBE_HOOK)
#include <linux/thread_info.h>
static inline void ksu_set_task_tracepoint_flag(struct task_struct *t)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
set_task_syscall_work(t, SYSCALL_TRACEPOINT);
#else
set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
#endif
}
static inline void ksu_clear_task_tracepoint_flag(struct task_struct *t)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
clear_task_syscall_work(t, SYSCALL_TRACEPOINT);
#else
clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
#endif
}
#else
static inline void ksu_set_task_tracepoint_flag(struct task_struct *t)
{
return;
}
static inline void ksu_clear_task_tracepoint_flag(struct task_struct *t)
{
return;
}
#endif
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags);
#endif #endif

View File

@@ -50,8 +50,9 @@ bool always_allow(void)
bool allowed_for_su(void) bool allowed_for_su(void)
{ {
bool is_allowed = is_manager() || ksu_is_allow_uid_for_current(current_uid().val); bool is_allowed =
return is_allowed; is_manager() || ksu_is_allow_uid_for_current(current_uid().val);
return is_allowed;
} }
static void init_uid_scanner(void) static void init_uid_scanner(void)
@@ -219,7 +220,7 @@ static int do_uid_granted_root(void __user *arg)
return -EFAULT; return -EFAULT;
} }
cmd.granted = ksu_is_allow_uid_for_current(cmd.uid); cmd.granted = ksu_is_allow_uid_for_current(cmd.uid);
if (copy_to_user(arg, &cmd, sizeof(cmd))) { if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("uid_granted_root: copy_to_user failed\n"); pr_err("uid_granted_root: copy_to_user failed\n");
@@ -677,7 +678,7 @@ int ksu_install_fd(void)
// Install fd // Install fd
fd_install(fd, filp); fd_install(fd, filp);
pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid); pr_info("ksu fd[%d] installed for %s/%d\n", fd, current->comm, current->pid);
return fd; return fd;
} }

View File

@@ -11,6 +11,7 @@
#include "allowlist.h" #include "allowlist.h"
#include "klog.h" // IWYU pragma: keep #include "klog.h" // IWYU pragma: keep
#include "ksu.h" #include "ksu.h"
#include "apk_sign.h"
#include "manager.h" #include "manager.h"
#include "throne_tracker.h" #include "throne_tracker.h"
#include "kernel_compat.h" #include "kernel_compat.h"