diff --git a/kernel/Kconfig b/kernel/Kconfig index ab6dd5c9..fa0c9001 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -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 diff --git a/kernel/Makefile b/kernel/Makefile index aa380e9a..9c82c918 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 2fbb42a1..7984928b 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -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; diff --git a/kernel/kpm/Makefile b/kernel/kpm/Makefile new file mode 100644 index 00000000..3f75542d --- /dev/null +++ b/kernel/kpm/Makefile @@ -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 \ No newline at end of file diff --git a/kernel/kpm/compact.c b/kernel/kpm/compact.c new file mode 100644 index 00000000..9bece752 --- /dev/null +++ b/kernel/kpm/compact.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 包含 ARM64 重定位类型定义 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); diff --git a/kernel/kpm/compact.h b/kernel/kpm/compact.h new file mode 100644 index 00000000..01e8fa88 --- /dev/null +++ b/kernel/kpm/compact.h @@ -0,0 +1,6 @@ +#ifndef ___SUKISU_KPM_COMPACT_H +#define ___SUKISU_KPM_COMPACT_H + +unsigned long sukisu_compact_find_symbol(const char* name); + +#endif \ No newline at end of file diff --git a/kernel/kpm/kpm.c b/kernel/kpm/kpm.c new file mode 100644 index 00000000..39c09ad1 --- /dev/null +++ b/kernel/kpm/kpm.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 包含 ARM64 重定位类型定义 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) && defined(CONFIG_MODULES) +#include // 需要启用 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); \ No newline at end of file diff --git a/kernel/kpm/kpm.h b/kernel/kpm/kpm.h new file mode 100644 index 00000000..f9f98848 --- /dev/null +++ b/kernel/kpm/kpm.h @@ -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 \ No newline at end of file diff --git a/kernel/kpm/super_access.c b/kernel/kpm/super_access.c new file mode 100644 index 00000000..7a61e22f --- /dev/null +++ b/kernel/kpm/super_access.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 包含 ARM64 重定位类型定义 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kpm.h" +#include "compact.h" +#include +#include + +// 结构体成员元数据 +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 + +#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 + +// 定义元数据 +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 + +#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 +#include + +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 + +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 +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); \ No newline at end of file diff --git a/kernel/kpm/super_access.h b/kernel/kpm/super_access.h new file mode 100644 index 00000000..2514be89 --- /dev/null +++ b/kernel/kpm/super_access.h @@ -0,0 +1,39 @@ +#ifndef __SUKISU_SUPER_ACCESS_H +#define __SUKISU_SUPER_ACCESS_H + +#include +#include +#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 \ No newline at end of file diff --git a/kernel/ksu.h b/kernel/ksu.h index af81a43d..f7955038 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -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