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
b74e953ad2
...
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:
|
with:
|
||||||
os: ${{ matrix.os }}
|
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:
|
build-ksud:
|
||||||
needs: build-susfsd
|
needs: build-susfsd
|
||||||
strategy:
|
strategy:
|
||||||
@@ -109,6 +120,16 @@ jobs:
|
|||||||
mkdir -p app/src/main/jniLibs/x86_64
|
mkdir -p app/src/main/jniLibs/x86_64
|
||||||
cp -f ../x86_64/susfsd ../manager/app/src/main/jniLibs/x86_64/libsusfsd.so
|
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
|
- name: Download arm64 ksud_overlayfs
|
||||||
uses: actions/download-artifact@v4
|
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.
|
Disabling this is mostly only useful for kernel 4.1 and older.
|
||||||
Make sure to implement manual hooks on security/security.c.
|
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
|
endmenu
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-
|
|||||||
|
|
||||||
obj-$(CONFIG_KSU) += kernelsu.o
|
obj-$(CONFIG_KSU) += kernelsu.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_KPM) += kpm/
|
||||||
|
|
||||||
# .git is a text file while the module is imported by 'git submodule add'.
|
# .git is a text file while the module is imported by 'git submodule add'.
|
||||||
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
|
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)
|
$(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 "throne_tracker.h"
|
||||||
#include "kernel_compat.h"
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
|
#include "kpm/kpm.h"
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) || defined(KSU_COMPAT_GET_CRED_RCU)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) || defined(KSU_COMPAT_GET_CRED_RCU)
|
||||||
#define KSU_GET_CRED_RCU
|
#define KSU_GET_CRED_RCU
|
||||||
#endif
|
#endif
|
||||||
@@ -450,6 +452,26 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||||||
return 0;
|
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'
|
// all other cmds are for 'root manager'
|
||||||
if (!from_manager) {
|
if (!from_manager) {
|
||||||
return 0;
|
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_ENABLE_SU 15
|
||||||
#define CMD_HOOK_MODE 16
|
#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_POST_FS_DATA 1
|
||||||
#define EVENT_BOOT_COMPLETED 2
|
#define EVENT_BOOT_COMPLETED 2
|
||||||
#define EVENT_MODULE_MOUNTED 3
|
#define EVENT_MODULE_MOUNTED 3
|
||||||
|
|||||||
@@ -313,3 +313,8 @@ JNIEXPORT jboolean JNICALL
|
|||||||
Java_com_rifsxd_ksunext_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
|
Java_com_rifsxd_ksunext_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
|
||||||
return set_su_enabled(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_IS_SU_ENABLED 14
|
||||||
#define CMD_ENABLE_SU 15
|
#define CMD_ENABLE_SU 15
|
||||||
#define CMD_HOOK_MODE 16
|
#define CMD_HOOK_MODE 16
|
||||||
|
#define CMD_ENABLE_KPM 100
|
||||||
|
|
||||||
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
||||||
int32_t result = 0;
|
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.
|
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
|
||||||
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
|
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
|
||||||
return enabled;
|
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_su_enabled();
|
||||||
|
|
||||||
|
bool is_KPM_enable();
|
||||||
|
|
||||||
#endif //KERNELSU_KSU_H
|
#endif //KERNELSU_KSU_H
|
||||||
|
|||||||
@@ -81,6 +81,12 @@ object Natives {
|
|||||||
external fun isSuEnabled(): Boolean
|
external fun isSuEnabled(): Boolean
|
||||||
external fun setSuEnabled(enabled: Boolean): 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 NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
||||||
private const val NOBODY_UID = 9999
|
private const val NOBODY_UID = 9999
|
||||||
|
|
||||||
|
|||||||
@@ -645,4 +645,72 @@ fun launchApp(packageName: String) {
|
|||||||
fun restartApp(packageName: String) {
|
fun restartApp(packageName: String) {
|
||||||
forceStopApp(packageName)
|
forceStopApp(packageName)
|
||||||
launchApp(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