diff --git a/kernel/Makefile b/kernel/Makefile index 761c06a733d6..11b6a26cc5bd 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -11,8 +11,10 @@ kernelsu-objs += kernel_compat.o kernelsu-objs += selinux/selinux.o kernelsu-objs += selinux/sepolicy.o kernelsu-objs += selinux/rules.o + ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h +ccflags-y += -include $(srctree)/$(src)/include/ksu_creds.h obj-$(CONFIG_KSU) += kernelsu.o diff --git a/kernel/core_hook.c b/kernel/core_hook.c index b5488ad8109e..3d344bc33a4f 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -62,10 +62,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; @@ -120,7 +120,12 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) static void disable_seccomp(void) { - assert_spin_locked(¤t->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) @@ -130,40 +135,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)); + + 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->uid.val = profile->uid; - cred->suid.val = profile->uid; - cred->euid.val = profile->uid; - cred->fsuid.val = profile->uid; + ksu_cred_gid(newcreds) = profile->gid; + ksu_cred_fsgid(newcreds) = profile->gid; + ksu_cred_sgid(newcreds) = profile->gid; + ksu_cred_egid(newcreds) = profile->gid; - cred->gid.val = profile->gid; - cred->fsgid.val = profile->gid; - cred->sgid.val = profile->gid; - cred->egid.val = profile->gid; - cred->securebits = 0; + // no wrapper, ignore it. + newcreds->securebits = 0; BUILD_BUG_ON(sizeof(profile->capabilities.effective) != sizeof(kernel_cap_t)); @@ -173,23 +194,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)); - - setup_groups(profile, cred); - - commit_creds(cred); - - // Refer to kernel/seccomp.c: seccomp_set_mode_strict - // When disabling Seccomp, ensure that current->sighand->siglock is held during the operation. - spin_lock_irq(¤t->sighand->siglock); + 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, newcreds); + commit_creds(newcreds); + disable_seccomp(); - spin_unlock_irq(¤t->sighand->siglock); - setup_selinux(profile->selinux_domain); } @@ -200,7 +215,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; } @@ -268,14 +283,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) { @@ -299,7 +314,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"); @@ -511,13 +526,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) @@ -528,7 +544,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; } @@ -614,33 +630,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)) { + // pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); + return 0; } - if (ksu_is_allow_uid(new_uid.val)) { + if (!ksu_uid_should_umount(new_uid.val)) { + return 0; + } else { #ifdef CONFIG_KSU_DEBUG - pr_info("handle setuid ignore allowed application: %d\n", new_uid.val); + pr_info("uid: %d should not umount!\n", current_uid().val); #endif - return 0; } -do_umount: // 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; diff --git a/kernel/include/ksu_creds.h b/kernel/include/ksu_creds.h new file mode 100644 index 000000000000..bdcba952dc5c --- /dev/null +++ b/kernel/include/ksu_creds.h @@ -0,0 +1,39 @@ +/* + * KernelSU creds wrapper + * + * Provide a wrapper for a few credentials use (e.g current_uid().val), + * so it would be easier to maintain + * some older linux versions. + */ + +#ifndef __KSU_H_CREDS +#define __KSU_H_CREDS + +#include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \ + defined(CONFIG_UIDGID_STRICT_TYPE_CHECKS)) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) +#define ksu_cred_uid(x) ((x)->uid.val) +#define ksu_cred_suid(x) ((x)->suid.val) +#define ksu_cred_euid(x) ((x)->euid.val) +#define ksu_cred_fsuid(x) ((x)->fsuid.val) +#define ksu_cred_gid(x) ((x)->gid.val) +#define ksu_cred_fsgid(x) ((x)->fsgid.val) +#define ksu_cred_sgid(x) ((x)->sgid.val) +#define ksu_cred_egid(x) ((x)->egid.val) +#define ksu_current_uid() (current_uid().val) +#else +#define ksu_cred_uid(x) ((x)->uid) +#define ksu_cred_suid(x) ((x)->suid) +#define ksu_cred_euid(x) ((x)->euid) +#define ksu_cred_fsuid(x) ((x)->fsuid) +#define ksu_cred_gid(x) ((x)->gid) +#define ksu_cred_fsgid(x) ((x)->fsgid) +#define ksu_cred_sgid(x) ((x)->sgid) +#define ksu_cred_egid(x) ((x)->egid) +#define ksu_current_uid() (current_uid()) +#endif + +#endif diff --git a/kernel/manager.h b/kernel/manager.h index be5bbced6f73..48c143671fc8 100644 --- a/kernel/manager.h +++ b/kernel/manager.h @@ -15,7 +15,7 @@ static inline bool ksu_is_manager_uid_valid() static inline bool is_manager() { - return unlikely(ksu_manager_uid == current_uid().val); + return unlikely(ksu_manager_uid == ksu_current_uid()); } static inline uid_t ksu_get_manager_uid() diff --git a/kernel/sucompat.c b/kernel/sucompat.c index 5b0a6d1c5e11..8b20b1a443cd 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -58,7 +58,7 @@ static inline bool __is_su_allowed(const void *ptr_to_check) if (!ksu_sucompat_hook_state) return false; #endif - if (likely(!ksu_is_allow_uid(current_uid().val))) + if (likely(!ksu_is_allow_uid(ksu_current_uid()))) return false; if (unlikely(!ptr_to_check)) @@ -149,7 +149,7 @@ static int ksu_inline_handle_devpts(struct inode *inode) return 0; } - uid_t uid = current_uid().val; + uid_t uid = ksu_current_uid(); if (uid % 100000 < 10000) { // not untrusted_app, ignore it return 0;