You've already forked KernelSU-Next
mirror of
https://github.com/KernelSU-Next/KernelSU-Next.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
3 Commits
f0934e6b90
...
kpm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1b1a9e627 | ||
|
|
6159cea2f7 | ||
|
|
2e56870e77 |
21
.github/workflows/build-manager.yml
vendored
21
.github/workflows/build-manager.yml
vendored
@@ -33,6 +33,17 @@ jobs:
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-kpmmgr:
|
||||
needs: build-lkm
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-linux-android
|
||||
os: ubuntu-latest
|
||||
uses: ./.github/workflows/kpmmgr.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-ksud:
|
||||
needs: build-susfsd
|
||||
strategy:
|
||||
@@ -109,6 +120,16 @@ jobs:
|
||||
mkdir -p app/src/main/jniLibs/x86_64
|
||||
cp -f ../x86_64/susfsd ../manager/app/src/main/jniLibs/x86_64/libsusfsd.so
|
||||
|
||||
- name: Download arm64 kpmmgr
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: kpmmgr-aarch64-linux-android
|
||||
path: .
|
||||
|
||||
- name: Copy kpmmgr to app jniLibs
|
||||
run: |
|
||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||
cp -f ../arm64-v8a/kpmmgr ../manager/app/src/main/jniLibs/arm64-v8a/libkpmmgr.so
|
||||
|
||||
- name: Download arm64 ksud_overlayfs
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
40
.github/workflows/kpmmgr.yml
vendored
Normal file
40
.github/workflows/kpmmgr.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Build kpmmgr
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "mian" ]
|
||||
paths:
|
||||
- '.github/workflows/kpmmgr.yml'
|
||||
- 'userspace/kpmmgr/**'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
default: self-hosted
|
||||
|
||||
jobs:
|
||||
build-susfs:
|
||||
name: Build userspace kpmmgr
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build kpmmgr
|
||||
working-directory: ./userspace/kpmmgr
|
||||
run: |
|
||||
$ANDROID_NDK_HOME/ndk-build
|
||||
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kpmmgr-aarch64-linux-android
|
||||
path: ./userspace/kpmmgr/libs
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
6
kernel/kpm/Makefile
Normal 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
102
kernel/kpm/compact.c
Normal 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
6
kernel/kpm/compact.h
Normal 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
184
kernel/kpm/kpm.c
Normal 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
44
kernel/kpm/kpm.h
Normal 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
289
kernel/kpm/super_access.c
Normal 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
39
kernel/kpm/super_access.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -313,3 +313,8 @@ JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
|
||||
return set_su_enabled(enabled);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_isKPMEnabled(JNIEnv *env, jobject) {
|
||||
return is_KPM_enable();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define CMD_IS_SU_ENABLED 14
|
||||
#define CMD_ENABLE_SU 15
|
||||
#define CMD_HOOK_MODE 16
|
||||
#define CMD_ENABLE_KPM 100
|
||||
|
||||
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
||||
int32_t result = 0;
|
||||
@@ -103,4 +104,9 @@ bool is_su_enabled() {
|
||||
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
|
||||
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool is_KPM_enable() {
|
||||
bool enabled = false;
|
||||
return ksuctl(CMD_ENABLE_KPM, &enabled, nullptr), enabled;
|
||||
}
|
||||
@@ -85,4 +85,6 @@ bool set_su_enabled(bool enabled);
|
||||
|
||||
bool is_su_enabled();
|
||||
|
||||
bool is_KPM_enable();
|
||||
|
||||
#endif //KERNELSU_KSU_H
|
||||
|
||||
@@ -81,6 +81,12 @@ object Natives {
|
||||
external fun isSuEnabled(): Boolean
|
||||
external fun setSuEnabled(enabled: Boolean): Boolean
|
||||
|
||||
/**
|
||||
* Check if the KPM (Kernel Package Manager) is enabled.
|
||||
* @return true if KPM is enabled, false otherwise.
|
||||
*/
|
||||
external fun isKPMEnabled(): Boolean
|
||||
|
||||
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
||||
private const val NOBODY_UID = 9999
|
||||
|
||||
|
||||
@@ -645,4 +645,72 @@ fun launchApp(packageName: String) {
|
||||
fun restartApp(packageName: String) {
|
||||
forceStopApp(packageName)
|
||||
launchApp(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
fun getKpmmgrPath(): String {
|
||||
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libkpmmgr.so"
|
||||
}
|
||||
|
||||
|
||||
fun loadKpmModule(path: String, args: String? = null): String {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} load $path ${args ?: ""}"
|
||||
return ShellUtils.fastCmd(shell, cmd)
|
||||
}
|
||||
|
||||
fun unloadKpmModule(name: String): String {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} unload $name"
|
||||
return ShellUtils.fastCmd(shell, cmd)
|
||||
}
|
||||
|
||||
fun getKpmModuleCount(): Int {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} num"
|
||||
val result = ShellUtils.fastCmd(shell, cmd)
|
||||
return result.trim().toIntOrNull() ?: 0
|
||||
}
|
||||
|
||||
fun runCmd(shell : Shell, cmd : String) : String {
|
||||
return shell.newJob()
|
||||
.add(cmd)
|
||||
.to(mutableListOf<String>(), null)
|
||||
.exec().out
|
||||
.joinToString("\n")
|
||||
}
|
||||
|
||||
fun listKpmModules(): String {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} list"
|
||||
return try {
|
||||
runCmd(shell, cmd).trim()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to list KPM modules", e)
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
fun getKpmModuleInfo(name: String): String {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} info $name"
|
||||
return try {
|
||||
runCmd(shell, cmd).trim()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to get KPM module info: $name", e)
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
fun controlKpmModule(name: String, args: String? = null): Int {
|
||||
val shell = getRootShell()
|
||||
val cmd = """${getKpmmgrPath()} control $name "${args ?: ""}""""
|
||||
val result = runCmd(shell, cmd)
|
||||
return result.trim().toIntOrNull() ?: -1
|
||||
}
|
||||
|
||||
fun getKpmVersion(): String {
|
||||
val shell = getRootShell()
|
||||
val cmd = "${getKpmmgrPath()} version"
|
||||
val result = ShellUtils.fastCmd(shell, cmd)
|
||||
return result.trim()
|
||||
}
|
||||
|
||||
2
userspace/kpmmgr/.gitignore
vendored
Normal file
2
userspace/kpmmgr/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/obj
|
||||
/libs
|
||||
6
userspace/kpmmgr/jni/Android.mk
Normal file
6
userspace/kpmmgr/jni/Android.mk
Normal file
@@ -0,0 +1,6 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := kpmmgr
|
||||
LOCAL_SRC_FILES := kpmmgr.c
|
||||
include $(BUILD_EXECUTABLE)
|
||||
3
userspace/kpmmgr/jni/Application.mk
Normal file
3
userspace/kpmmgr/jni/Application.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
APP_ABI := arm64-v8a
|
||||
APP_PLATFORM := android-24
|
||||
APP_STL := none
|
||||
118
userspace/kpmmgr/jni/kpmmgr.c
Normal file
118
userspace/kpmmgr/jni/kpmmgr.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define KERNEL_SU_OPTION 0xDEADBEEF
|
||||
#define KSU_OPTIONS 0xdeadbeef
|
||||
|
||||
// KPM控制代码
|
||||
#define CMD_KPM_CONTROL 28
|
||||
#define CMD_KPM_CONTROL_MAX 7
|
||||
|
||||
// 控制代码
|
||||
// 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
|
||||
|
||||
#define CONTROL_CODE(n) (n)
|
||||
|
||||
void print_usage(const char *prog) {
|
||||
printf("Usage: %s <command> [args]\n", prog);
|
||||
printf("Commands:\n");
|
||||
printf(" load <path> <args> Load a KPM module\n");
|
||||
printf(" unload <name> Unload a KPM module\n");
|
||||
printf(" num Get number of loaded modules\n");
|
||||
printf(" list List loaded KPM modules\n");
|
||||
printf(" info <name> Get info of a KPM module\n");
|
||||
printf(" control <name> <args> Send control command to a KPM module\n");
|
||||
printf(" version Print KPM Loader version\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
int out = -1; // 存储返回值
|
||||
|
||||
if (strcmp(argv[1], "load") == 0 && argc >= 3) {
|
||||
// 加载 KPM 模块
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_LOAD), argv[2], (argc > 3 ? argv[3] : NULL), &out);
|
||||
if(out > 0) {
|
||||
printf("Success");
|
||||
}
|
||||
} else if (strcmp(argv[1], "unload") == 0 && argc >= 3) {
|
||||
// 卸载 KPM 模块
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_UNLOAD), argv[2], NULL, &out);
|
||||
} else if (strcmp(argv[1], "num") == 0) {
|
||||
// 获取加载的 KPM 数量
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_NUM), NULL, NULL, &out);
|
||||
printf("%d", out);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "list") == 0) {
|
||||
// 获取模块列表
|
||||
char buffer[1024] = {0};
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_LIST), buffer, sizeof(buffer), &out);
|
||||
if (out >= 0) {
|
||||
printf("%s", buffer);
|
||||
}
|
||||
} else if (strcmp(argv[1], "info") == 0 && argc >= 3) {
|
||||
// 获取指定模块信息
|
||||
char buffer[256] = {0};
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_INFO), argv[2], buffer, &out);
|
||||
if (out >= 0) {
|
||||
printf("%s\n", buffer);
|
||||
}
|
||||
} else if (strcmp(argv[1], "control") == 0 && argc >= 4) {
|
||||
// 控制 KPM 模块
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_CONTROL), argv[2], argv[3], &out);
|
||||
} else if (strcmp(argv[1], "version") == 0) {
|
||||
char buffer[1024] = {0};
|
||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_VERSION), buffer, sizeof(buffer), &out);
|
||||
if (out >= 0) {
|
||||
printf("%s", buffer);
|
||||
}
|
||||
} else {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (out < 0) {
|
||||
printf("Error: %s\n", strerror(-out));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user