Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
130 changes: 71 additions & 59 deletions kernel/core_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -120,7 +120,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)
Expand All @@ -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));
Expand All @@ -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(&current->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(&current->sighand->siglock);

setup_selinux(profile->selinux_domain);
}

Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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");
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions kernel/include/ksu_creds.h
Original file line number Diff line number Diff line change
@@ -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 <linux/cred.h>
#include <linux/version.h>

#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
2 changes: 1 addition & 1 deletion kernel/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions kernel/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down