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:
@@ -16,8 +16,10 @@ endif
|
||||
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
|
||||
obj-$(CONFIG_KSU_TRACEPOINT_HOOK) += ksu_trace_export.o
|
||||
@@ -123,7 +125,6 @@ ifdef KSU_EXPECTED_SIZE
|
||||
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
|
||||
$(info -- Custom KernelSU Manager signature size: $(KSU_EXPECTED_SIZE))
|
||||
endif
|
||||
|
||||
ifdef KSU_EXPECTED_HASH
|
||||
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
|
||||
$(info -- Custom KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
|
||||
|
||||
@@ -216,7 +216,9 @@ static int parse_apk_signature(char *path, bool check_multi_manager, int *signat
|
||||
unsigned char buffer[0x11] = { 0 };
|
||||
u32 size4;
|
||||
u64 size8, size_of_block;
|
||||
|
||||
loff_t pos;
|
||||
|
||||
bool v2_signing_valid = false;
|
||||
int v2_signing_blocks = 0;
|
||||
bool v3_signing_exist = false;
|
||||
|
||||
@@ -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);
|
||||
setup_groups(profile, newcreds);
|
||||
commit_creds(newcreds);
|
||||
|
||||
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);
|
||||
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,6 +685,13 @@ 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);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
39
kernel/include/ksu_creds.h
Normal file
39
kernel/include/ksu_creds.h
Normal file
@@ -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
|
||||
@@ -178,3 +178,33 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr,
|
||||
long count)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count);
|
||||
if (likely(ret >= 0))
|
||||
return ret;
|
||||
|
||||
// we faulted! fallback to slow path
|
||||
if (unlikely(!ksu_access_ok(unsafe_addr, count))) {
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_err("%s: faulted!\n", __func__);
|
||||
#endif
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
// why we don't do like how strncpy_from_user_nofault?
|
||||
ret = strncpy_from_user(dst, unsafe_addr, count);
|
||||
|
||||
if (ret >= count) {
|
||||
ret = count;
|
||||
dst[ret - 1] = '\0';
|
||||
} else if (likely(ret >= 0)) {
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
extern long ksu_strncpy_from_user_nofault(char *dst,
|
||||
const void __user *unsafe_addr,
|
||||
long count);
|
||||
extern long ksu_strncpy_from_user_retry(char *dst,
|
||||
const void __user *unsafe_addr,
|
||||
long count);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
||||
defined(CONFIG_IS_HW_HISI) || \
|
||||
@@ -47,9 +50,9 @@ extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
|
||||
size_t count, loff_t *pos);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
||||
#define ksu_access_ok(addr, size) (access_ok(addr, size))
|
||||
#define ksu_access_ok(addr, size) access_ok(addr, size)
|
||||
#else
|
||||
#define ksu_access_ok(addr, size) (access_ok(VERIFY_READ, addr, size))
|
||||
#define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -200,7 +200,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(
|
||||
ksu_strncpy_from_user_retry(
|
||||
first_arg, p, sizeof(first_arg));
|
||||
pr_info("/system/bin/init first arg: %s\n",
|
||||
first_arg);
|
||||
@@ -225,7 +225,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(
|
||||
ksu_strncpy_from_user_retry(
|
||||
first_arg, p, sizeof(first_arg));
|
||||
pr_info("/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "--second-stage")) {
|
||||
@@ -250,7 +250,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
}
|
||||
char env[256];
|
||||
// Reading environment variable strings from user space
|
||||
if (ksu_strncpy_from_user_nofault(
|
||||
if (ksu_strncpy_from_user_retry(
|
||||
env, p, sizeof(env)) < 0)
|
||||
continue;
|
||||
// Parsing environment variable names and values
|
||||
|
||||
@@ -20,7 +20,7 @@ static inline bool ksu_is_manager_uid_valid()
|
||||
|
||||
static inline bool is_manager()
|
||||
{
|
||||
return unlikely(ksu_is_any_manager(current_uid().val) || ksu_manager_uid == current_uid().val);
|
||||
return unlikely(ksu_is_any_manager(ksu_current_uid()) || ksu_manager_uid == ksu_current_uid());
|
||||
}
|
||||
|
||||
static inline uid_t ksu_get_manager_uid()
|
||||
|
||||
@@ -41,8 +41,7 @@ setup_kernelsu() {
|
||||
echo "[+] Setting up KernelSU..."
|
||||
# Clone the repository and rename it to KernelSU
|
||||
if [ ! -d "$GKI_ROOT/KernelSU" ]; then
|
||||
git clone https://github.com/SukiSU-Ultra/SukiSU-Ultra SukiSU-Ultra
|
||||
mv SukiSU-Ultra KernelSU
|
||||
git clone https://github.com/SukiSU-Ultra/SukiSU-Ultra KernelSU
|
||||
echo "[+] Repository cloned and renamed to KernelSU."
|
||||
fi
|
||||
cd "$GKI_ROOT/KernelSU"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define SH_PATH "/system/bin/sh"
|
||||
|
||||
static const char su[] = SU_PATH;
|
||||
const char ksud_path[] = KSUD_PATH;
|
||||
static const char ksud_path[] = KSUD_PATH;
|
||||
|
||||
extern void escape_to_root();
|
||||
|
||||
@@ -52,127 +52,91 @@ static inline char __user *ksud_user_path(void)
|
||||
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
|
||||
}
|
||||
|
||||
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
int *__unused_flags)
|
||||
static inline bool __is_su_allowed(const void *ptr_to_check)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_hook_state) {
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_sucompat_hook_state)
|
||||
return false;
|
||||
#endif
|
||||
if (likely(!ksu_is_allow_uid(ksu_current_uid())))
|
||||
return false;
|
||||
|
||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||
return 0;
|
||||
if (unlikely(!ptr_to_check))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#define is_su_allowed(ptr) __is_su_allowed((const void *)ptr)
|
||||
|
||||
char path[sizeof(su) + 1];
|
||||
static int ksu_sucompat_user_common(const char __user **filename_user,
|
||||
const char *syscall_name,
|
||||
const bool escalate)
|
||||
{
|
||||
char path[sizeof(su)]; // sizeof includes nullterm already!
|
||||
memset(path, 0, sizeof(path));
|
||||
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||
|
||||
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||
pr_info("faccessat su->sh!\n");
|
||||
ksu_strncpy_from_user_retry(path, *filename_user, sizeof(path));
|
||||
|
||||
if (memcmp(path, su, sizeof(su)))
|
||||
return 0;
|
||||
|
||||
if (escalate) {
|
||||
pr_info("%s su found\n", syscall_name);
|
||||
*filename_user = ksud_user_path();
|
||||
escape_to_root(); // escalate !!
|
||||
} else {
|
||||
pr_info("%s su->sh!\n", syscall_name);
|
||||
*filename_user = sh_user_path();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
int *__unused_flags)
|
||||
{
|
||||
if (!is_su_allowed(filename_user))
|
||||
return 0;
|
||||
|
||||
return ksu_sucompat_user_common(filename_user, "faccessat", false);
|
||||
}
|
||||
|
||||
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_hook_state) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!filename_user)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path[sizeof(su) + 1];
|
||||
memset(path, 0, sizeof(path));
|
||||
|
||||
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||
|
||||
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||
pr_info("newfstatat su->sh!\n");
|
||||
*filename_user = sh_user_path();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
|
||||
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
void *__never_use_argv, void *__never_use_envp,
|
||||
int *__never_use_flags)
|
||||
{
|
||||
struct filename *filename;
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_hook_state) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(!filename_ptr))
|
||||
if (!is_su_allowed(filename_user))
|
||||
return 0;
|
||||
|
||||
filename = *filename_ptr;
|
||||
if (IS_ERR(filename)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||
return 0;
|
||||
|
||||
if (!ksu_is_allow_uid(current_uid().val))
|
||||
return 0;
|
||||
|
||||
pr_info("do_execveat_common su found\n");
|
||||
memcpy((void *)filename->name, ksud_path, sizeof(ksud_path));
|
||||
|
||||
escape_to_root();
|
||||
|
||||
return 0;
|
||||
return ksu_sucompat_user_common(filename_user, "newfstatat", false);
|
||||
}
|
||||
|
||||
int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
||||
void *__never_use_argv, void *__never_use_envp,
|
||||
int *__never_use_flags)
|
||||
{
|
||||
char path[sizeof(su) + 1];
|
||||
|
||||
if (unlikely(!filename_user))
|
||||
if (!is_su_allowed(filename_user))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* nofault variant fails silently due to pagefault_disable
|
||||
* some cpus dont really have that good speculative execution
|
||||
* access_ok to substitute set_fs, we check if pointer is accessible
|
||||
*/
|
||||
if (!ksu_access_ok(*filename_user, sizeof(path)))
|
||||
return ksu_sucompat_user_common(filename_user, "sys_execve", true);
|
||||
}
|
||||
|
||||
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
void *__never_use_argv, void *__never_use_envp,
|
||||
int *__never_use_flags)
|
||||
{
|
||||
struct filename *filename;
|
||||
|
||||
if (!is_su_allowed(filename_ptr))
|
||||
return 0;
|
||||
|
||||
// success = returns number of bytes and should be less than path
|
||||
long len = strncpy_from_user(path, *filename_user, sizeof(path));
|
||||
if (len <= 0)
|
||||
filename = *filename_ptr;
|
||||
if (IS_ERR(filename))
|
||||
return 0;
|
||||
|
||||
// strncpy_from_user_nofault does this too
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
|
||||
if (likely(memcmp(path, su, sizeof(su))))
|
||||
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||
return 0;
|
||||
|
||||
if (!ksu_is_allow_uid(current_uid().val))
|
||||
return 0;
|
||||
|
||||
pr_info("sys_execve su found\n");
|
||||
*filename_user = ksud_user_path();
|
||||
pr_info("do_execveat_common su found\n");
|
||||
memcpy((void *)filename->name, ksud_path, sizeof(ksud_path));
|
||||
|
||||
escape_to_root();
|
||||
|
||||
@@ -185,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;
|
||||
@@ -212,9 +176,8 @@ static int ksu_inline_handle_devpts(struct inode *inode)
|
||||
int __ksu_handle_devpts(struct inode *inode)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_hook_state) {
|
||||
if (!ksu_sucompat_hook_state)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return ksu_inline_handle_devpts(inode);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user