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
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ obj-y += manager.o
obj-y += core_hook.o
obj-y += ksud.o
obj-y += embed_ksud.o
obj-y += kernel_compat.o

obj-y += selinux/

Expand Down
24 changes: 15 additions & 9 deletions kernel/allowlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
#include "linux/list.h"
#include "linux/printk.h"
#include "linux/slab.h"

#include "linux/version.h"
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "kernel_compat.h"

#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 1 // u32
Expand All @@ -21,7 +22,12 @@ 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;
Expand Down Expand Up @@ -128,12 +134,12 @@ void do_persistent_allow_list(struct work_struct *work)
}

// store magic and version
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
if (kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}

if (kernel_write(fp, &version, sizeof(version), &off) !=
if (kernel_write_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
Expand All @@ -143,8 +149,8 @@ void do_persistent_allow_list(struct work_struct *work)
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list uid :%d, allow: %d\n", p->uid,
p->allow);
kernel_write(fp, &p->uid, sizeof(p->uid), &off);
kernel_write(fp, &p->allow, sizeof(p->allow), &off);
kernel_write_compat(fp, &p->uid, sizeof(p->uid), &off);
kernel_write_compat(fp, &p->allow, sizeof(p->allow), &off);
}

exit:
Expand Down Expand Up @@ -194,13 +200,13 @@ void do_load_allow_list(struct work_struct *work)
}

// verify magic
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
if (kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
magic != FILE_MAGIC) {
pr_err("allowlist file invalid: %d!\n", magic);
goto exit;
}

if (kernel_read(fp, &version, sizeof(version), &off) !=
if (kernel_read_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("allowlist read version: %d failed\n", version);
goto exit;
Expand All @@ -211,12 +217,12 @@ void do_load_allow_list(struct work_struct *work)
while (true) {
u32 uid;
bool allow = false;
ret = kernel_read(fp, &uid, sizeof(uid), &off);
ret = kernel_read_compat(fp, &uid, sizeof(uid), &off);
if (ret <= 0) {
pr_info("load_allow_list read err: %d\n", ret);
break;
}
ret = kernel_read(fp, &allow, sizeof(allow), &off);
ret = kernel_read_compat(fp, &allow, sizeof(allow), &off);

pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);

Expand Down
33 changes: 17 additions & 16 deletions kernel/apk_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"

static __always_inline int
check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
Expand All @@ -25,10 +26,10 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
for (int i = 0;; ++i) {
unsigned short n;
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
kernel_read(fp, &n, 2, &pos);
kernel_read_compat(fp, &n, 2, &pos);
if (n == i) {
pos -= 22;
kernel_read(fp, &size4, 4, &pos);
kernel_read_compat(fp, &size4, 4, &pos);
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
break;
}
Expand All @@ -41,55 +42,55 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)

pos += 12;
// offset
kernel_read(fp, &size4, 0x4, &pos);
kernel_read_compat(fp, &size4, 0x4, &pos);
pos = size4 - 0x18;

kernel_read(fp, &size8, 0x8, &pos);
kernel_read(fp, buffer, 0x10, &pos);
kernel_read_compat(fp, &size8, 0x8, &pos);
kernel_read_compat(fp, buffer, 0x10, &pos);
if (strcmp((char *)buffer, "APK Sig Block 42")) {
goto clean;
}

pos = size4 - (size8 + 0x8);
kernel_read(fp, &size_of_block, 0x8, &pos);
kernel_read_compat(fp, &size_of_block, 0x8, &pos);
if (size_of_block != size8) {
goto clean;
}

for (;;) {
uint32_t id;
uint32_t offset;
kernel_read(fp, &size8, 0x8, &pos); // sequence length
kernel_read_compat(fp, &size8, 0x8, &pos); // sequence length
if (size8 == size_of_block) {
break;
}
kernel_read(fp, &id, 0x4, &pos); // id
kernel_read_compat(fp, &id, 0x4, &pos); // id
offset = 4;
pr_info("id: 0x%08x\n", id);
if ((id ^ 0xdeadbeefu) == 0xafa439f5u ||
(id ^ 0xdeadbeefu) == 0x2efed62f) {
kernel_read(fp, &size4, 0x4,
kernel_read_compat(fp, &size4, 0x4,
&pos); // signer-sequence length
kernel_read(fp, &size4, 0x4, &pos); // signer length
kernel_read(fp, &size4, 0x4,
kernel_read_compat(fp, &size4, 0x4, &pos); // signer length
kernel_read_compat(fp, &size4, 0x4,
&pos); // signed data length
offset += 0x4 * 3;

kernel_read(fp, &size4, 0x4,
kernel_read_compat(fp, &size4, 0x4,
&pos); // digests-sequence length
pos += size4;
offset += 0x4 + size4;

kernel_read(fp, &size4, 0x4,
kernel_read_compat(fp, &size4, 0x4,
&pos); // certificates length
kernel_read(fp, &size4, 0x4,
kernel_read_compat(fp, &size4, 0x4,
&pos); // certificate length
offset += 0x4 * 2;
#if 0
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
kernel_read_compat(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
Expand All @@ -99,7 +100,7 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
kernel_read_compat(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
Expand Down
30 changes: 30 additions & 0 deletions kernel/kernel_compat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "linux/version.h"
#include "linux/init.h"
#include "linux/fs.h"
ssize_t kernel_read_compat(struct file *p, void *buf, size_t count, loff_t *pos){
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_read(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_read(p, offset, (char *)buf, count);
if (pos && result > 0)
{
*pos = offset + result;
}
return result;
#endif
}

ssize_t kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos){
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_write(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_write(p, buf, count, offset);
if (pos && result > 0)
{
*pos = offset + result;
}
return result;
#endif
}
3 changes: 3 additions & 0 deletions kernel/kernel_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "linux/fs.h"
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);
2 changes: 1 addition & 1 deletion kernel/ksud.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ static struct kprobe execve_kp = {
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
.symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) && \
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
.symbol_name = "do_execveat_common",
#endif
Expand Down
11 changes: 9 additions & 2 deletions kernel/selinux/rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@
static struct policydb *get_policydb(void)
{
struct policydb *db;
// selinux_state does not exists before 4.19
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
struct selinux_policy *policy = rcu_dereference(selinux_state.policy);
db = &policy->policydb;
#else
struct selinux_ss *ss = rcu_dereference(selinux_state.ss);
db = &ss->policydb;
#endif
#else
db = &policydb;
#endif
return db;
}
Expand Down Expand Up @@ -69,12 +74,14 @@ void apply_kernelsu_rules()
// Android 10+:
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
// Kernel 4.4
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
// Android 9-:
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
ksu_allow(db, "kernel", "system_data_file", "file", ALL);

ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
// our ksud triggered by init
ksu_allow(db, "init", "adb_data_file", "file", "execute");
ksu_allow(db, "init", "adb_data_file", "file", ALL);
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);

// copied from Magisk rules
Expand Down
11 changes: 10 additions & 1 deletion kernel/selinux/selinux.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "selinux.h"
#include "objsec.h"

#include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep

#define KERNEL_SU_DOMAIN "u:r:su:s0"
Expand Down Expand Up @@ -53,13 +53,18 @@ if (!is_domain_permissive) {

void setenforce(bool enforce)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
selinux_state.enforcing = enforce;
#endif
#else
selinux_enabled = enforce;
#endif
}

bool getenforce()
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
if (selinux_state.disabled) {
return false;
Expand All @@ -71,6 +76,10 @@ bool getenforce()
#else
return false;
#endif
#else
return selinux_enabled;
#endif

}

bool is_ksu_domain()
Expand Down
16 changes: 15 additions & 1 deletion kernel/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,16 @@ static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)

static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *dfd = (int *)PT_REGS_PARM1(regs);
// static int vfs_statx(int dfd, const char __user *filename, int flags,struct kstat *stat, u32 request_mask)
int *dfd = (int *)&PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
int *flags = (int *)&PT_REGS_PARM3(regs);
#else
// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag)
int *flags = (int *)&PT_REGS_PARM4(regs);
#endif


return ksu_handle_stat(dfd, filename_user, flags);
}
Expand Down Expand Up @@ -165,7 +172,11 @@ static struct kprobe faccessat_kp = {
};

static struct kprobe newfstatat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
.symbol_name = "vfs_statx",
#else
.symbol_name = "vfs_fstatat",
#endif
.pre_handler = newfstatat_handler_pre,
};

Expand All @@ -178,6 +189,9 @@ static struct kprobe execve_kp = {
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
.symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
.symbol_name = "do_execveat_common",
#endif
.pre_handler = execve_handler_pre,
};
Expand Down
5 changes: 3 additions & 2 deletions kernel/uid_observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "ksu.h"
#include "manager.h"
#include "uid_observer.h"
#include "kernel_compat.h"

#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
static struct work_struct ksu_update_uid_work;
Expand Down Expand Up @@ -54,13 +55,13 @@ static void do_update_uid(struct work_struct *work)
loff_t line_start = 0;
char buf[128];
for (;;) {
ssize_t count = kernel_read(fp, &chr, sizeof(chr), &pos);
ssize_t count = kernel_read_compat(fp, &chr, sizeof(chr), &pos);
if (count != sizeof(chr))
break;
if (chr != '\n')
continue;

count = kernel_read(fp, buf, sizeof(buf), &line_start);
count = kernel_read_compat(fp, buf, sizeof(buf), &line_start);

struct uid_data *data =
kmalloc(sizeof(struct uid_data), GFP_ATOMIC);
Expand Down