Skip to content
Closed
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: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A Kernel based root solution for Android devices.

## Compatibility State

KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.14+) is also compatiable, but you need to build kernel yourself.
KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.4+) is also compatiable, but you need to build kernel yourself.

WSA and containter-based Android should also work with KernelSU integrated.

Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

## 兼容状态

KernelSU 官方支持 GKI 2.0 的设备(内核版本5.10以上);旧内核也是兼容的(最低4.14+),不过需要自己编译内核。
KernelSU 官方支持 GKI 2.0 的设备(内核版本5.10以上);旧内核也是兼容的(最低4.4+),不过需要自己编译内核。

WSA 和运行在容器上的 Android 也可以与 KernelSU 一起工作。

Expand Down
83 changes: 77 additions & 6 deletions kernel/allowlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ struct perm_data {

static struct list_head allow_list;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
#else
// filp_open return error if under encryption dir on Kernel4.4
#define KERNEL_SU_ALLOWLIST "/data/user_de/.ksu_allowlist"
#endif

static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
#ifndef FILP_OPEN_WORKS_IN_WORKER
static struct file *fp;
static DEFINE_MUTEX(fp_mutex);
#endif

bool persistent_allow_list(void);

Expand Down Expand Up @@ -125,13 +124,21 @@ void do_persistent_allow_list(struct work_struct *work)
struct list_head *pos = NULL;
loff_t off = 0;

#ifdef FILP_OPEN_WORKS_IN_WORKER
struct file *fp =
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);

if (IS_ERR(fp)) {
pr_err("save_allow_list creat file failed: %d\n", PTR_ERR(fp));
return;
}
#else
mutex_lock(&fp_mutex);
if (!fp) {
pr_err("save_allow_list fp wasn't opened successfully\n");
goto exit;
}
#endif

// store magic and version
if (kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
Expand All @@ -154,17 +161,24 @@ void do_persistent_allow_list(struct work_struct *work)
}

exit:
#ifdef FILP_OPEN_WORKS_IN_WORKER
filp_close(fp, 0);
#else
mutex_unlock(&fp_mutex);
#endif
}

void do_load_allow_list(struct work_struct *work)
{
loff_t off = 0;
ssize_t ret = 0;
#ifdef FILP_OPEN_WORKS_IN_WORKER
struct file *fp = NULL;
#endif
u32 magic;
u32 version;

#ifdef FILP_OPEN_WORKS_IN_WORKER
fp = filp_open("/data/adb", O_RDONLY, 0);
if (IS_ERR(fp)) {
int errno = PTR_ERR(fp);
Expand Down Expand Up @@ -198,6 +212,13 @@ void do_load_allow_list(struct work_struct *work)
#endif
return;
}
#else
mutex_lock(&fp_mutex);
if (!fp) {
pr_err("load_allow_list fp wasn't opened successfully\n");
goto unlock;
}
#endif /* FILP_OPEN_WORKS_IN_WORKER */

// verify magic
if (kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
Expand Down Expand Up @@ -231,7 +252,12 @@ void do_load_allow_list(struct work_struct *work)

exit:
ksu_show_allow_list();
#ifdef FILP_OPEN_WORKS_IN_WORKER
filp_close(fp, 0);
#else
unlock:
mutex_unlock(&fp_mutex);
#endif
}

void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
Expand Down Expand Up @@ -261,11 +287,47 @@ void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
// make sure allow list works cross boot
bool persistent_allow_list(void)
{
#ifndef FILP_OPEN_WORKS_IN_WORKER
mutex_lock(&fp_mutex);
if (fp)
filp_close(fp, 0);
fp = filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);

if (IS_ERR(fp)) {
pr_err("persistent_allow_list creat file failed: %d\n", PTR_ERR(fp));
fp = NULL;
mutex_unlock(&fp_mutex);
return false;
}
mutex_unlock(&fp_mutex);
#endif
return ksu_queue_work(&ksu_save_work);
}

bool ksu_load_allow_list(void)
{
#ifndef FILP_OPEN_WORKS_IN_WORKER
mutex_lock(&fp_mutex);
if (fp)
filp_close(fp, 0);

// load allowlist now!
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);

if (IS_ERR(fp)) {
int errno = PTR_ERR(fp);
fp = NULL;
mutex_unlock(&fp_mutex);
#ifdef CONFIG_KSU_DEBUG
if (errno == -ENOENT)
ksu_allow_uid(2000, true,
true); // allow adb shell by default
#endif
pr_err("ksu_load_allow_list open file failed: %d\n", errno);
return false;
}
mutex_unlock(&fp_mutex);
#endif /* FILP_OPEN_WORKS_IN_WORKER */
return ksu_queue_work(&ksu_load_work);
}

Expand All @@ -291,4 +353,13 @@ void ksu_allowlist_exit(void)
kfree(np);
}
mutex_unlock(&allowlist_mutex);
}

#ifndef FILP_OPEN_WORKS_IN_WORKER
mutex_lock(&fp_mutex);
if (fp) {
filp_close(fp, 0);
fp = NULL;
}
mutex_unlock(&fp_mutex);
#endif
}
25 changes: 24 additions & 1 deletion kernel/core_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include "ksud.h"
#include "manager.h"
#include "selinux/selinux.h"
#include "selinux/kernel_compat.h"
#include "uid_observer.h"
#include "kernel_compat.h"

extern int handle_sepolicy(unsigned long arg3, void __user *arg4);

Expand Down Expand Up @@ -253,12 +255,33 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
bool allow = arg2 == CMD_ALLOW_SU;
bool success = false;
uid_t uid = (uid_t)arg3;
#ifndef FILP_OPEN_WORKS_IN_WORKER
struct ksu_cred_t old_cred;
if (!ksu_save_cred(&old_cred)) {
pr_err("failed to save manager cred\n");
goto show;
}
if(!ksu_tmp_root_begin()) {
pr_err("cannot switch to root\n");
goto show;
}
#endif
success = ksu_allow_uid(uid, allow, true);
#ifndef FILP_OPEN_WORKS_IN_WORKER
ksu_tmp_root_end();
if (!ksu_restore_cred(&old_cred)) {
pr_err("failed to restore manager cred\n");
BUG();
}
#endif
if (success) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
#ifndef FILP_OPEN_WORKS_IN_WORKER
show:
#endif
ksu_show_allow_list();
} else if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
u32 array[128];
Expand Down Expand Up @@ -395,4 +418,4 @@ void ksu_core_exit(void)
pr_info("ksu_kprobe_exit\n");
ksu_kprobe_exit();
#endif
}
}
14 changes: 13 additions & 1 deletion kernel/kernel_compat.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
#ifndef __KSU_H_KERNEL_COMPAT
#define __KSU_H_KERNEL_COMPAT

#include "linux/fs.h"
#include "linux/version.h"

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
#define FILP_OPEN_WORKS_IN_WORKER
#elif defined(MODULE)
#warning building as module may not work due to Kprobes bugs on old kernels
#endif

extern ssize_t kernel_read_compat(struct file *p, void* buf, size_t count, loff_t *pos);
extern ssize_t kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos);
extern ssize_t kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos);
#endif
7 changes: 7 additions & 0 deletions kernel/ksu.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "linux/fs.h"
#include "linux/module.h"
#include "linux/workqueue.h"
#include "linux/version.h"

#include "allowlist.h"
#include "arch.h"
Expand Down Expand Up @@ -32,6 +33,9 @@ int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,

extern void ksu_enable_sucompat();
extern void ksu_enable_ksud();
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
extern void ksu_enable_selinux_compat();
#endif

int __init kernelsu_init(void)
{
Expand All @@ -56,6 +60,9 @@ int __init kernelsu_init(void)
#ifdef CONFIG_KPROBES
ksu_enable_sucompat();
ksu_enable_ksud();
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
ksu_enable_selinux_compat();
#endif
#else
#warning("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html")
#endif
Expand Down
41 changes: 37 additions & 4 deletions kernel/ksud.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "ksud.h"
#include "selinux/selinux.h"

#if defined(CONFIG_KPROBES) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
#define APPLY_RULES_IN_WORKER
#endif

static const char KERNEL_SU_RC[] =
"\n"

Expand All @@ -40,6 +44,9 @@ static const char KERNEL_SU_RC[] =

static void stop_vfs_read_hook();
static void stop_execve_hook();
#ifdef APPLY_RULES_IN_WORKER
static void ksu_apply_rules();
#endif

#ifdef CONFIG_KPROBES
static struct work_struct stop_vfs_read_work;
Expand All @@ -49,6 +56,10 @@ static bool vfs_read_hook = true;
static bool execveat_hook = true;
#endif

#ifdef APPLY_RULES_IN_WORKER
static struct work_struct apply_rules_work;
#endif

void on_post_fs_data(void)
{
static bool done = false;
Expand Down Expand Up @@ -91,15 +102,21 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
// 1: /system/bin/init selinux_setup
// 2: /system/bin/init second_stage
pr_info("/system/bin/init second_stage executed\n");
#ifdef APPLY_RULES_IN_WORKER
ksu_apply_rules();
#else
apply_kernelsu_rules();
#endif
}
}

if (first_app_process &&
!memcmp(filename->name, app_process, sizeof(app_process) - 1)) {
first_app_process = false;
pr_info("exec app_process, /data prepared!\n");
#ifdef FILP_OPEN_WORKS_IN_WORKER
on_post_fs_data(); // we keep this for old ksud
#endif
stop_execve_hook();
}

Expand Down Expand Up @@ -212,11 +229,9 @@ static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
.symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
.symbol_name = "do_execveat_common",
#endif
.pre_handler = execve_handler_pre,
Expand All @@ -236,6 +251,13 @@ static void do_stop_execve_hook(struct work_struct *work)
{
unregister_kprobe(&execve_kp);
}

#ifdef APPLY_RULES_IN_WORKER
static void do_apply_kernelsu_rules(struct work_struct *work)
{
apply_kernelsu_rules();
}
#endif
#endif

static void stop_vfs_read_hook()
Expand All @@ -258,6 +280,14 @@ static void stop_execve_hook()
#endif
}

#ifdef APPLY_RULES_IN_WORKER
static void ksu_apply_rules()
{
bool ret = schedule_work(&apply_rules_work);
pr_info("apply kernelsu rules: %d!\n", ret);
}
#endif

// ksud: module support
void ksu_enable_ksud()
{
Expand All @@ -272,5 +302,8 @@ void ksu_enable_ksud()

INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
#ifdef APPLY_RULES_IN_WORKER
INIT_WORK(&apply_rules_work, do_apply_kernelsu_rules);
#endif
#endif
}
3 changes: 2 additions & 1 deletion kernel/selinux/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
obj-y += selinux.o
obj-y += sepolicy.o
obj-y += rules.o
obj-y += kernel_compat.o


ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement -Wno-unused-function
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux
ccflags-y += -I$(objtree)/security/selinux
Loading