kernel: add KPM support with related structures and commands

Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: liankong <xhsw.new@qq.com>
Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-06-11 19:45:00 +08:00
committed by Rifat Azad
parent 10f7d5cf50
commit 2e56870e77
11 changed files with 706 additions and 0 deletions

View File

@@ -40,4 +40,13 @@ config KSU_LSM_SECURITY_HOOKS
Disabling this is mostly only useful for kernel 4.1 and older.
Make sure to implement manual hooks on security/security.c.
config KPM
bool "Enable SukiSU KPM"
depends on KSU && 64BIT
default n
help
Enabling this option will activate the KPM feature of SukiSU.
This option is suitable for scenarios where you need to force KPM to be enabled.
but it may affect system stability.
endmenu

View File

@@ -16,6 +16,8 @@ ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-
obj-$(CONFIG_KSU) += kernelsu.o
obj-$(CONFIG_KPM) += kpm/
# .git is a text file while the module is imported by 'git submodule add'.
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow)

View File

@@ -47,6 +47,8 @@
#include "throne_tracker.h"
#include "kernel_compat.h"
#include "kpm/kpm.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) || defined(KSU_COMPAT_GET_CRED_RCU)
#define KSU_GET_CRED_RCU
#endif
@@ -450,6 +452,26 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
#ifdef CONFIG_KPM
// KPM Control
if(sukisu_is_kpm_control_code(arg2)) {
int res;
pr_info("KPM: calling before arg2=%d\n", (int) arg2);
res = sukisu_handle_kpm(arg2, arg3, arg4, arg5);
return 0;
}
#endif
// KPM info
if (arg2 == CMD_ENABLE_KPM) {
bool KPM_Enabled = IS_ENABLED(CONFIG_KPM);
if (copy_to_user((void __user *)arg3, &KPM_Enabled, sizeof(KPM_Enabled)))
pr_info("KPM: copy_to_user() failed\n");
return 0;
}
// all other cmds are for 'root manager'
if (!from_manager) {
return 0;

6
kernel/kpm/Makefile Normal file
View File

@@ -0,0 +1,6 @@
obj-y += kpm.o
obj-y += compact.o
obj-y += super_access.o
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function

102
kernel/kpm/compact.c Normal file
View File

@@ -0,0 +1,102 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kernfs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/elf.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <asm/cacheflush.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/set_memory.h>
#include <linux/version.h>
#include <linux/export.h>
#include <linux/slab.h>
#include "kpm.h"
#include "compact.h"
#include "../allowlist.h"
#include "../manager.h"
unsigned long sukisu_compact_find_symbol(const char* name);
// ======================================================================
// 兼容函数 for KPM
static
int sukisu_is_su_allow_uid(uid_t uid) {
return ksu_is_allow_uid(uid) ? 1 : 0;
}
static
int sukisu_get_ap_mod_exclude(uid_t uid) {
// Not supported
return 0;
}
static
int sukisu_is_uid_should_umount(uid_t uid) {
return ksu_uid_should_umount(uid) ? 1 : 0;
}
static
int sukisu_is_current_uid_manager() {
return is_manager();
}
static
uid_t sukisu_get_manager_uid() {
return ksu_manager_uid;
}
// ======================================================================
struct CompactAddressSymbol {
const char* symbol_name;
void* addr;
};
static struct CompactAddressSymbol address_symbol [] = {
{ "kallsyms_lookup_name", &kallsyms_lookup_name },
{ "compact_find_symbol", &sukisu_compact_find_symbol },
{ "is_run_in_sukisu_ultra", (void*)1 },
{ "is_su_allow_uid", &sukisu_is_su_allow_uid },
{ "get_ap_mod_exclude", &sukisu_get_ap_mod_exclude },
{ "is_uid_should_umount", &sukisu_is_uid_should_umount },
{ "is_current_uid_manager", &sukisu_is_current_uid_manager },
{ "get_manager_uid", &sukisu_get_manager_uid }
};
unsigned long sukisu_compact_find_symbol(const char* name) {
int i;
unsigned long addr;
// 先自己在地址表部分查出来
for(i = 0; i < (sizeof(address_symbol) / sizeof(struct CompactAddressSymbol)); i++) {
struct CompactAddressSymbol* symbol = &address_symbol[i];
if(strcmp(name, symbol->symbol_name) == 0) {
return (unsigned long) symbol->addr;
}
}
// 通过内核来查
addr = kallsyms_lookup_name(name);
if(addr) {
return addr;
}
return 0;
}
EXPORT_SYMBOL(sukisu_compact_find_symbol);

6
kernel/kpm/compact.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef ___SUKISU_KPM_COMPACT_H
#define ___SUKISU_KPM_COMPACT_H
unsigned long sukisu_compact_find_symbol(const char* name);
#endif

184
kernel/kpm/kpm.c Normal file
View File

@@ -0,0 +1,184 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2025 Liankong (xhsw.new@outlook.com). All Rights Reserved.
* 本代码由GPL-2授权
*
* 适配KernelSU的KPM 内核模块加载器兼容实现
*
* 集成了 ELF 解析、内存布局、符号处理、重定位(支持 ARM64 重定位类型)
* 并参照KernelPatch的标准KPM格式实现加载和控制
*/
#include <linux/export.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kernfs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/elf.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <asm/cacheflush.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/set_memory.h>
#include <linux/version.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <asm/insn.h>
#include <linux/kprobes.h>
#include <linux/stacktrace.h>
#include <linux/kallsyms.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) && defined(CONFIG_MODULES)
#include <linux/moduleloader.h> // 需要启用 CONFIG_MODULES
#endif
#include "kpm.h"
#include "compact.h"
#ifndef NO_OPTIMIZE
#if defined(__GNUC__) && !defined(__clang__)
#define NO_OPTIMIZE __attribute__((optimize("O0")))
#elif defined(__clang__)
#define NO_OPTIMIZE __attribute__((optnone))
#else
#define NO_OPTIMIZE
#endif
#endif
// ============================================================================================
noinline
NO_OPTIMIZE
void sukisu_kpm_load_module_path(const char* path, const char* args, void* ptr, void __user* result) {
// This is a KPM module stub.
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_load_module_path). path=%s args=%s ptr=%p\n", path, args, ptr);
__asm__ volatile("nop"); // 精确控制循环不被优化
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_unload_module(const char* name, void* ptr, void __user* result) {
// This is a KPM module stub.
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_unload_module). name=%s ptr=%p\n", name, ptr);
__asm__ volatile("nop"); // 精确控制循环不被优化
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_num(void __user* result) {
// This is a KPM module stub.
int res = 0;
printk("KPM: Stub function called (sukisu_kpm_num).\n");
__asm__ volatile("nop"); // 精确控制循环不被优化
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_info(const char* name, void __user* out, void __user* result) {
// This is a KPM module stub.
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_info). name=%s buffer=%p\n", name, out);
__asm__ volatile("nop"); // 精确控制循环不被优化
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_list(void __user* out, unsigned int bufferSize, void __user* result) {
// This is a KPM module stub.
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_list). buffer=%p size=%d\n", out, bufferSize);
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_control(void __user* name, void __user* args, void __user* result) {
// This is a KPM module stub.
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_control). name=%p args=%p\n", name, args);
__asm__ volatile("nop"); // 精确控制循环不被优化
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
noinline
NO_OPTIMIZE
void sukisu_kpm_version(void __user* out, unsigned int bufferSize, void __user* result) {
int res = -1;
printk("KPM: Stub function called (sukisu_kpm_version). buffer=%p size=%d\n", out, bufferSize);
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
}
EXPORT_SYMBOL(sukisu_kpm_load_module_path);
EXPORT_SYMBOL(sukisu_kpm_unload_module);
EXPORT_SYMBOL(sukisu_kpm_num);
EXPORT_SYMBOL(sukisu_kpm_info);
EXPORT_SYMBOL(sukisu_kpm_list);
EXPORT_SYMBOL(sukisu_kpm_version);
EXPORT_SYMBOL(sukisu_kpm_control);
noinline
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
if(arg2 == SUKISU_KPM_LOAD) {
char kernel_load_path[256] = { 0 };
char kernel_args_buffer[256] = { 0 };
if(arg3 == 0) {
return -1;
}
strncpy_from_user((char*)&kernel_load_path, (const char __user *)arg3, 255);
if(arg4 != 0) {
strncpy_from_user((char*)&kernel_args_buffer, (const char __user *)arg4, 255);
}
sukisu_kpm_load_module_path((const char*)&kernel_load_path, (const char*) &kernel_args_buffer, NULL, (void __user*) arg5);
} else if(arg2 == SUKISU_KPM_UNLOAD) {
char kernel_name_buffer[256] = { 0 };
if(arg3 == 0) {
return -1;
}
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
sukisu_kpm_unload_module((const char*) &kernel_name_buffer, NULL, (void __user*) arg5);
} else if(arg2 == SUKISU_KPM_NUM) {
sukisu_kpm_num((void __user*) arg5);
} else if(arg2 == SUKISU_KPM_INFO) {
char kernel_name_buffer[256] = { 0 };
if(arg3 == 0 || arg4 == 0) {
return -1;
}
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
sukisu_kpm_info((const char*) &kernel_name_buffer, (char __user*) arg4, (void __user*) arg5);
} else if(arg2 == SUKISU_KPM_LIST) {
sukisu_kpm_list((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
} else if(arg2 == SUKISU_KPM_VERSION) {
sukisu_kpm_version((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
} else if(arg2 == SUKISU_KPM_CONTROL) {
sukisu_kpm_control((char __user*) arg3, (char __user*) arg4, (void __user*) arg5);
}
return 0;
}
int sukisu_is_kpm_control_code(unsigned long arg2) {
return (arg2 >= CMD_KPM_CONTROL && arg2 <= CMD_KPM_CONTROL_MAX) ? 1 : 0;
}
EXPORT_SYMBOL(sukisu_handle_kpm);

44
kernel/kpm/kpm.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef ___SUKISU_KPM_H
#define ___SUKISU_KPM_H
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
int sukisu_is_kpm_control_code(unsigned long arg2);
// KPM控制代码
#define CMD_KPM_CONTROL 28
#define CMD_KPM_CONTROL_MAX 35
// 控制代码
// prctl(xxx, 28, "PATH", "ARGS")
// success return 0, error return -N
#define SUKISU_KPM_LOAD 28
// prctl(xxx, 29, "NAME")
// success return 0, error return -N
#define SUKISU_KPM_UNLOAD 29
// num = prctl(xxx, 30)
// error return -N
// success return +num or 0
#define SUKISU_KPM_NUM 30
// prctl(xxx, 31, Buffer, BufferSize)
// success return +out, error return -N
#define SUKISU_KPM_LIST 31
// prctl(xxx, 32, "NAME", Buffer[256])
// success return +out, error return -N
#define SUKISU_KPM_INFO 32
// prctl(xxx, 33, "NAME", "ARGS")
// success return KPM's result value
// error return -N
#define SUKISU_KPM_CONTROL 33
// prctl(xxx, 34, buffer, bufferSize)
// success return KPM's result value
// error return -N
#define SUKISU_KPM_VERSION 34
#endif

289
kernel/kpm/super_access.c Normal file
View File

@@ -0,0 +1,289 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kernfs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/elf.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <asm/cacheflush.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/set_memory.h>
#include <linux/version.h>
#include <linux/export.h>
#include <linux/slab.h>
#include "kpm.h"
#include "compact.h"
#include <linux/types.h>
#include <linux/stddef.h>
// 结构体成员元数据
struct DynamicStructMember {
const char* name;
size_t size;
size_t offset;
};
// 结构体元数据(包含总大小)
struct DynamicStructInfo {
const char* name;
size_t count;
size_t total_size;
struct DynamicStructMember* members;
};
// 定义结构体元数据的宏(直接使用 struct 名称)
#define DYNAMIC_STRUCT_BEGIN(struct_name) \
static struct DynamicStructMember struct_name##_members[] = {
#define DEFINE_MEMBER(struct_name, member) \
{ \
.name = #member, \
.size = sizeof(((struct struct_name*)0)->member), \
.offset = offsetof(struct struct_name, member) \
},
#define DYNAMIC_STRUCT_END(struct_name) \
}; \
static struct DynamicStructInfo struct_name##_info = { \
.name = #struct_name, \
.count = sizeof(struct_name##_members) / sizeof(struct DynamicStructMember), \
.total_size = sizeof(struct struct_name), \
.members = struct_name##_members \
};
// ==================================================================================
#include <linux/version.h>
#define KERNEL_VERSION_6_1 KERNEL_VERSION(6, 1, 0)
#define KERNEL_VERSION_5_15 KERNEL_VERSION(5, 15, 0)
#include <../fs/mount.h>
#include <linux/mount.h>
// 定义元数据
DYNAMIC_STRUCT_BEGIN(mount)
DEFINE_MEMBER(mount, mnt_parent)
DEFINE_MEMBER(mount, mnt)
DEFINE_MEMBER(mount, mnt_id)
DEFINE_MEMBER(mount, mnt_group_id)
DEFINE_MEMBER(mount, mnt_expiry_mark)
DEFINE_MEMBER(mount, mnt_master)
DEFINE_MEMBER(mount, mnt_devname)
DYNAMIC_STRUCT_END(mount)
DYNAMIC_STRUCT_BEGIN(vfsmount)
DEFINE_MEMBER(vfsmount, mnt_root)
DEFINE_MEMBER(vfsmount, mnt_sb)
DEFINE_MEMBER(vfsmount, mnt_flags)
DYNAMIC_STRUCT_END(vfsmount)
DYNAMIC_STRUCT_BEGIN(mnt_namespace)
DEFINE_MEMBER(mnt_namespace, ns)
DEFINE_MEMBER(mnt_namespace, root)
DEFINE_MEMBER(mnt_namespace, seq)
DEFINE_MEMBER(mnt_namespace, mounts)
#if LINUX_VERSION_CODE < KERNEL_VERSION_5_15
DEFINE_MEMBER(mnt_namespace, count)
#endif
DYNAMIC_STRUCT_END(mnt_namespace)
#include <linux/kprobes.h>
#ifdef CONFIG_KPROBES
DYNAMIC_STRUCT_BEGIN(kprobe)
DEFINE_MEMBER(kprobe, addr)
DEFINE_MEMBER(kprobe, symbol_name)
DEFINE_MEMBER(kprobe, offset)
DEFINE_MEMBER(kprobe, pre_handler)
DEFINE_MEMBER(kprobe, post_handler)
#if LINUX_VERSION_CODE < KERNEL_VERSION_5_15
DEFINE_MEMBER(kprobe, fault_handler)
#endif
DEFINE_MEMBER(kprobe, flags)
DYNAMIC_STRUCT_END(kprobe)
#endif
#include <linux/mm.h>
#include <linux/mm_types.h>
DYNAMIC_STRUCT_BEGIN(vm_area_struct)
DEFINE_MEMBER(vm_area_struct,vm_start)
DEFINE_MEMBER(vm_area_struct,vm_end)
DEFINE_MEMBER(vm_area_struct,vm_flags)
DEFINE_MEMBER(vm_area_struct,anon_vma)
DEFINE_MEMBER(vm_area_struct,vm_pgoff)
DEFINE_MEMBER(vm_area_struct,vm_file)
DEFINE_MEMBER(vm_area_struct,vm_private_data)
#ifdef CONFIG_ANON_VMA_NAME
DEFINE_MEMBER(vm_area_struct, anon_name)
#endif
DEFINE_MEMBER(vm_area_struct, vm_ops)
DYNAMIC_STRUCT_END(vm_area_struct)
DYNAMIC_STRUCT_BEGIN(vm_operations_struct)
DEFINE_MEMBER(vm_operations_struct, open)
DEFINE_MEMBER(vm_operations_struct, close)
DEFINE_MEMBER(vm_operations_struct, name)
DEFINE_MEMBER(vm_operations_struct, access)
DYNAMIC_STRUCT_END(vm_operations_struct)
#include <linux/netlink.h>
DYNAMIC_STRUCT_BEGIN(netlink_kernel_cfg)
DEFINE_MEMBER(netlink_kernel_cfg, groups)
DEFINE_MEMBER(netlink_kernel_cfg, flags)
DEFINE_MEMBER(netlink_kernel_cfg, input)
DEFINE_MEMBER(netlink_kernel_cfg, cb_mutex)
DEFINE_MEMBER(netlink_kernel_cfg, bind)
DEFINE_MEMBER(netlink_kernel_cfg, unbind)
#if LINUX_VERSION_CODE < KERNEL_VERSION_6_1
DEFINE_MEMBER(netlink_kernel_cfg, compare)
#endif
DYNAMIC_STRUCT_END(netlink_kernel_cfg)
#include <linux/sched.h>
DYNAMIC_STRUCT_BEGIN(task_struct)
DEFINE_MEMBER(task_struct, pid)
DEFINE_MEMBER(task_struct, tgid)
DEFINE_MEMBER(task_struct, cred)
DEFINE_MEMBER(task_struct, real_cred)
DEFINE_MEMBER(task_struct, comm)
DEFINE_MEMBER(task_struct, parent)
DEFINE_MEMBER(task_struct, group_leader)
DEFINE_MEMBER(task_struct, mm)
DEFINE_MEMBER(task_struct, active_mm)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
DEFINE_MEMBER(task_struct, pids[PIDTYPE_PID].pid)
#else
DEFINE_MEMBER(task_struct, thread_pid)
#endif
DEFINE_MEMBER(task_struct, files)
DEFINE_MEMBER(task_struct, seccomp)
#ifdef CONFIG_THREAD_INFO_IN_TASK
DEFINE_MEMBER(task_struct, thread_info)
#endif
#ifdef CONFIG_CGROUPS
DEFINE_MEMBER(task_struct, cgroups)
#endif
#ifdef CONFIG_SECURITY
DEFINE_MEMBER(task_struct, security)
#endif
DEFINE_MEMBER(task_struct, thread)
DYNAMIC_STRUCT_END(task_struct)
// =====================================================================================================================
#define STRUCT_INFO(name) &(name##_info)
static
struct DynamicStructInfo* dynamic_struct_infos[] = {
STRUCT_INFO(mount),
STRUCT_INFO(vfsmount),
STRUCT_INFO(mnt_namespace),
#ifdef CONFIG_KPROBES
STRUCT_INFO(kprobe),
#endif
STRUCT_INFO(vm_area_struct),
STRUCT_INFO(vm_operations_struct),
STRUCT_INFO(netlink_kernel_cfg),
STRUCT_INFO(task_struct)
};
// return 0 if successful
// return -1 if struct not defined
int sukisu_super_find_struct(
const char* struct_name,
size_t* out_size,
int* out_members
) {
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
struct DynamicStructInfo* info = dynamic_struct_infos[i];
if(strcmp(struct_name, info->name) == 0) {
if(out_size)
*out_size = info->total_size;
if(out_members)
*out_members = info->count;
return 0;
}
}
return -1;
}
EXPORT_SYMBOL(sukisu_super_find_struct);
// Dynamic access struct
// return 0 if successful
// return -1 if struct not defined
// return -2 if member not defined
int sukisu_super_access (
const char* struct_name,
const char* member_name,
size_t* out_offset,
size_t* out_size
) {
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
struct DynamicStructInfo* info = dynamic_struct_infos[i];
if(strcmp(struct_name, info->name) == 0) {
for (size_t i1 = 0; i1 < info->count; i1++) {
if (strcmp(info->members[i1].name, member_name) == 0) {
if(out_offset)
*out_offset = info->members[i].offset;
if(out_size)
*out_size = info->members[i].size;
return 0;
}
}
return -2;
}
}
return -1;
}
EXPORT_SYMBOL(sukisu_super_access);
// 动态 container_of 宏
#define DYNAMIC_CONTAINER_OF(offset, member_ptr) ({ \
(offset != (size_t)-1) ? (void*)((char*)(member_ptr) - offset) : NULL; \
})
// Dynamic container_of
// return 0 if success
// return -1 if current struct not defined
// return -2 if target member not defined
int sukisu_super_container_of(
const char* struct_name,
const char* member_name,
void* ptr,
void** out_ptr
) {
if(ptr == NULL) {
return -3;
}
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
struct DynamicStructInfo* info = dynamic_struct_infos[i];
if(strcmp(struct_name, info->name) == 0) {
for (size_t i1 = 0; i1 < info->count; i1++) {
if (strcmp(info->members[i1].name, member_name) == 0) {
*out_ptr = (void*) DYNAMIC_CONTAINER_OF(info->members[i1].offset, ptr);
return 0;
}
}
return -2;
}
}
return -1;
}
EXPORT_SYMBOL(sukisu_super_container_of);

39
kernel/kpm/super_access.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef __SUKISU_SUPER_ACCESS_H
#define __SUKISU_SUPER_ACCESS_H
#include <linux/types.h>
#include <linux/stddef.h>
#include "kpm.h"
#include "compact.h"
// return 0 if successful
// return -1 if struct not defined
int sukisu_super_find_struct(
const char* struct_name,
size_t* out_size,
int* out_members
);
// Dynamic access struct
// return 0 if successful
// return -1 if struct not defined
// return -2 if member not defined
int sukisu_super_access (
const char* struct_name,
const char* member_name,
size_t* out_offset,
size_t* out_size
);
// Dynamic container_of
// return 0 if success
// return -1 if current struct not defined
// return -2 if target member not defined
int sukisu_super_container_of(
const char* struct_name,
const char* member_name,
void* ptr,
void** out_ptr
);
#endif

View File

@@ -25,6 +25,9 @@
#define CMD_ENABLE_SU 15
#define CMD_HOOK_MODE 16
// This is used to check if the kernel supports KPM
#define CMD_ENABLE_KPM 100
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define EVENT_MODULE_MOUNTED 3