kernel: backport to 4.4 (#166)

These changes make KernelSU work on kernel4.4
[link](https://github.com/F-19-F/android_kernel_oneplus_msm8998).
LINUX_VERSION_CODE macro changes have been vertied on 4.4 4.9 4.14.
For kernel 4.4,just pick two commits
* [introduce
KernelSU](2993524f2f)
* [allow init exec ksud under
nosuid](3df9df42a6)
This commit is contained in:
f19
2023-02-01 19:48:36 +08:00
committed by GitHub
parent 417ff8a6c5
commit 4f2b8b7077
10 changed files with 104 additions and 32 deletions

View File

@@ -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/

View File

@@ -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);

View File

@@ -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;

30
kernel/kernel_compat.c Normal file
View File

@@ -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
kernel/kernel_compat.h Normal file
View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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,
};

View File

@@ -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);