kernel: add wrapper for creds, refine disable_seccomp, revert some changes (#131)

1. Wrapper for creds:
* Some older kernel does not have {.val}, so, for nicer compatibility support and clean code,
make some wrapper for credential use.
* After this change, do not use current_uid().val, instead, use ksu_current_uid(). For more
info, check kernel/include/ksu_creds.h.

2. Refine disable_seccomp (need to add k6.11+ support)
https://github.com/tiann/KernelSU/pull/2708
https://github.com/tiann/KernelSU/issues/2706

3. Revert "Handle unmount for isolated process correctly"
Reason: https://github.com/tiann/KernelSU/pull/2696#issuecomment-3181866301

4. consolidate most of the gaps

Co-authored-by: Wang Han <416810799@qq.com>
This commit is contained in:
M. Faris
2025-08-16 11:19:30 +07:00
committed by ShirkNeko
parent 665091f37d
commit ff6a68221f
11 changed files with 227 additions and 175 deletions

View File

@@ -51,8 +51,10 @@
static bool ksu_module_mounted = false;
// selinux/rules.c
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
// sucompat.c
static bool ksu_su_compat_enabled = true;
extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
@@ -63,10 +65,10 @@ static inline bool is_allow_su()
// we are manager, allow!
return true;
}
return ksu_is_allow_uid(current_uid().val);
return ksu_is_allow_uid(ksu_current_uid());
}
static inline bool is_unsupported_app_uid(uid_t uid)
static inline bool is_unsupported_uid(uid_t uid)
{
#define LAST_APPLICATION_UID 19999
uid_t appid = uid % 100000;
@@ -121,7 +123,12 @@ static void setup_groups(struct root_profile *profile, struct cred *cred)
static void disable_seccomp(void)
{
assert_spin_locked(&current->sighand->siglock);
struct task_struct *tsk = get_current();
pr_info("%s++\n", __func__);
spin_lock_irq(&tsk->sighand->siglock);
assert_spin_locked(&tsk->sighand->siglock);
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
@@ -131,40 +138,56 @@ static void disable_seccomp(void)
#endif
#ifdef CONFIG_SECCOMP
current->seccomp.mode = 0;
current->seccomp.filter = NULL;
tsk->seccomp.mode = 0;
if (tsk->seccomp.filter == NULL) {
pr_warn("tsk->seccomp.filter is NULL already!\n");
goto out;
}
// 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
put_seccomp_filter(tsk);
tsk->seccomp.filter = NULL;
#endif
#endif
out:
spin_unlock_irq(&tsk->sighand->siglock);
pr_info("%s--\n", __func__);
}
void escape_to_root(void)
{
struct cred *cred;
cred = prepare_creds();
if (!cred) {
struct cred *newcreds = prepare_creds();
if (newcreds == NULL) {
pr_err("%s: failed to allocate new cred.\n", __func__);
return;
}
if (cred->euid.val == 0) {
if (ksu_cred_euid(newcreds) == 0) {
pr_warn("Already root, don't escape!\n");
abort_creds(cred);
abort_creds(newcreds);
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
struct root_profile *profile =
ksu_get_root_profile(ksu_cred_uid(newcreds));
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
ksu_cred_uid(newcreds) = profile->uid;
ksu_cred_suid(newcreds) = profile->uid;
ksu_cred_euid(newcreds) = profile->uid;
ksu_cred_fsuid(newcreds) = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
cred->securebits = 0;
ksu_cred_gid(newcreds) = profile->gid;
ksu_cred_fsgid(newcreds) = profile->gid;
ksu_cred_sgid(newcreds) = profile->gid;
ksu_cred_egid(newcreds) = profile->gid;
// no wrapper, ignore it.
newcreds->securebits = 0;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
@@ -174,23 +197,17 @@ void escape_to_root(void)
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
memcpy(&newcreds->cap_effective, &cap_for_ksud,
sizeof(newcreds->cap_effective));
memcpy(&newcreds->cap_permitted, &profile->capabilities.effective,
sizeof(newcreds->cap_permitted));
memcpy(&newcreds->cap_bset, &profile->capabilities.effective,
sizeof(newcreds->cap_bset));
setup_groups(profile, cred);
commit_creds(cred);
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
spin_lock_irq(&current->sighand->siglock);
setup_groups(profile, newcreds);
commit_creds(newcreds);
disable_seccomp();
spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain);
}
@@ -201,7 +218,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
return 0;
}
if (current_uid().val != 1000) {
if (ksu_current_uid() != 1000) {
// skip non system uid
return 0;
}
@@ -269,14 +286,14 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
// TODO: find it in throne tracker!
uid_t current_uid_val = current_uid().val;
uid_t current_uid_val = ksu_current_uid();
uid_t manager_uid = ksu_get_manager_uid();
if (current_uid_val != manager_uid &&
current_uid_val % 100000 == manager_uid) {
ksu_set_manager_uid(current_uid_val);
}
bool from_root = 0 == current_uid().val;
bool from_root = 0 == ksu_current_uid();
bool from_manager = is_manager();
if (!from_root && !from_manager) {
@@ -300,7 +317,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (arg2 == CMD_GRANT_ROOT) {
if (is_allow_su()) {
pr_info("allow root for: %d\n", current_uid().val);
pr_info("allow root for: %d\n", ksu_current_uid());
escape_to_root();
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("grant_root: prctl reply error\n");
@@ -499,8 +516,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
const char *hook_type;
#if defined(CONFIG_KSU_KPROBES_HOOK)
hook_type = "Kprobes";
#elif defined(CONFIG_KSU_TRACEPOINT_HOOK)
hook_type = "Tracepoint";
@@ -598,7 +613,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
bool enabled = (arg3 != 0);
if (enabled == ksu_su_compat_enabled) {
pr_info("cmd enable su but no need to change.\n");
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
@@ -617,13 +632,14 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
static bool is_non_appuid(kuid_t uid)
static bool is_appuid(kuid_t uid)
{
#define PER_USER_RANGE 100000
#define FIRST_APPLICATION_UID 10000
#define LAST_APPLICATION_UID 19999
uid_t appid = uid.val % PER_USER_RANGE;
return appid < FIRST_APPLICATION_UID;
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
}
static bool should_umount(struct path *path)
@@ -634,7 +650,7 @@ static bool should_umount(struct path *path)
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n",
current_uid().val);
ksu_current_uid());
return false;
}
@@ -651,8 +667,8 @@ static void ksu_path_umount(const char *mnt, struct path *path, int flags)
int ret = path_umount(path, flags);
pr_info("%s: path: %s ret: %d\n", __func__, mnt, ret);
}
#define ksu_umount_mnt(mnt, path, flags) (ksu_path_umount(mnt, path, flags))
#else
// TODO: Search a way to make this works without set_fs functions
static void ksu_sys_umount(const char *mnt, int flags)
{
char __user *usermnt = (char __user *)mnt;
@@ -669,7 +685,14 @@ static void ksu_sys_umount(const char *mnt, int flags)
set_fs(old_fs);
pr_info("%s: path: %s ret: %d\n", __func__, usermnt, ret);
}
#endif
#define ksu_umount_mnt(mnt, __unused, flags) \
({ \
path_put(__unused); \
ksu_sys_umount(mnt, flags); \
})
#endif
static void try_umount(const char *mnt, bool check_mnt, int flags)
{
@@ -691,11 +714,7 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
return;
}
#ifdef KSU_HAS_PATH_UMOUNT
ksu_path_umount(mnt, &path, flags);
#else
ksu_sys_umount(mnt, flags);
#endif
ksu_umount_mnt(mnt, &path, flags);
}
int ksu_handle_setuid(struct cred *new, const struct cred *old)
@@ -717,33 +736,29 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0;
}
if (is_non_appuid(new_uid)) {
#ifdef CONFIG_KSU_DEBUG
pr_info("handle setuid ignore non application uid: %d\n", new_uid.val);
#endif
if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) {
// pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val);
return 0;
}
// isolated process may be directly forked from zygote, always unmount
if (is_unsupported_app_uid(new_uid.val)) {
#ifdef CONFIG_KSU_DEBUG
pr_info("handle umount for unsupported application uid: %d\n", new_uid.val);
#endif
goto do_umount;
}
if (ksu_is_allow_uid(new_uid.val)) {
#ifdef CONFIG_KSU_DEBUG
pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
#endif
// pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
return 0;
}
do_umount:
if (!ksu_uid_should_umount(new_uid.val)) {
return 0;
} else {
#ifdef CONFIG_KSU_DEBUG
pr_info("uid: %d should not umount!\n", current_uid().val);
#endif
}
// check old process's selinux context, if it is not zygote, ignore it!
// because some su apps may setuid to untrusted_app but they are in global mount namespace
// when we umount for such process, that is a disaster!
if (!is_zygote(old->security)) {
bool is_zygote_child = is_zygote(old->security);
if (!is_zygote_child) {
pr_info("handle umount ignore non zygote child: %d\n",
current->pid);
return 0;