diff --git a/kernel/Makefile b/kernel/Makefile index 65063cfa..28abb795 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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/ diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 1cf5ab2a..1c4a3756 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -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 @@ -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; @@ -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; @@ -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: @@ -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; @@ -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); diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index 6002ef58..38b23495 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -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) @@ -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; } @@ -41,17 +42,17 @@ 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; } @@ -59,37 +60,37 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash) 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; @@ -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; diff --git a/kernel/kernel_compat.c b/kernel/kernel_compat.c new file mode 100644 index 00000000..59057eea --- /dev/null +++ b/kernel/kernel_compat.c @@ -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 +} \ No newline at end of file diff --git a/kernel/kernel_compat.h b/kernel/kernel_compat.h new file mode 100644 index 00000000..703586bb --- /dev/null +++ b/kernel/kernel_compat.h @@ -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); \ No newline at end of file diff --git a/kernel/ksud.c b/kernel/ksud.c index fe6efc2f..e84cf493 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -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 diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index 959d7288..758950db 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -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; } @@ -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 diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 292c29f1..be8a35c0 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -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" @@ -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; @@ -71,6 +76,10 @@ bool getenforce() #else return false; #endif +#else + return selinux_enabled; +#endif + } bool is_ksu_domain() diff --git a/kernel/sucompat.c b/kernel/sucompat.c index b6a65f2d..22c9fd49 100644 --- a/kernel/sucompat.c +++ b/kernel/sucompat.c @@ -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); } @@ -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, }; @@ -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, }; diff --git a/kernel/uid_observer.c b/kernel/uid_observer.c index 20c93c25..7b9fcfd7 100644 --- a/kernel/uid_observer.c +++ b/kernel/uid_observer.c @@ -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; @@ -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);