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:
@@ -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(¤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)
|
||||
@@ -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(¤t->sighand->siglock);
|
||||
setup_groups(profile, newcreds);
|
||||
commit_creds(newcreds);
|
||||
|
||||
disable_seccomp();
|
||||
spin_unlock_irq(¤t->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;
|
||||
|
||||
Reference in New Issue
Block a user