new supercall impl (#511)

* refactor: replace throne tracker with ksud token

* use snprintf

* refactor: new supercall impl

- Import the sukisu command

* disable seccomp for supercall users

* kernel: fmt clear

* kernel: Enable macro protection for sulog

- Only enabled on kernel versions greater than 5.10.245

* kernel: Refactor kprobe hooks and implement LSM hooks for improved security handling

* debug mode

* kernel: Add functionality to generate and validate authentication tokens for cmd_su

* kernel: Simplified manual SU command processing for code

* kernel: replace renameat hook with fsnotify

* Revert "refactor: replace throne tracker with ksud token"

This reverts commit aa2cbbf9cd.

* kernel: fix compile

* kernel: fix compile below 6.0

* Fix compile err; Add become_manager

* kernel: install fd for manager automaticlly

- extend to import the corresponding command

* manager: new supercall impl

* temp changes for ksud

* ksud: fix compile

* fix wrong opcode

* kernel: fix compile

* kernel: Fixed hook type and KPM status retrieval errors

* kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10

When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end.

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>

* ksud: fix cargo check

* manager: Fixed an issue where the KSUD release and user-mode scanning switch failed to function correctly.

- kernel: fix spin lock mutual

kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10

When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end.

kernel: try introduce like susfs's method to fix prctl delay

* seccomp: allow reboot

* use u32

* update clang-format

* 4 spaces save the world

* ksud: Fix build on macOS

* manager: bump minimal supported kernel.

- When get_hook_type is empty, display “Unknown”.


* Fix ksud build (#2841)

* try fix ksud

* fix for macos

* remove any

* Fix ksud build, take 3

* try fix allowlist

* bring lsm hook back

* fix: a lot again

* Fix ksud build, take 4 (#2846)

Remove init_driver_fd function for non-linux/android targets

* manager: Return to the native method via KSUd installation

* Merge with susfs-mian format

---------

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: AlexLiuDev233 <wzylin11@outlook.com>
Co-authored-by: Wang Han <416810799@qq.com>
This commit is contained in:
ShirkNeko
2025-11-01 23:30:30 +08:00
committed by GitHub
parent 0da8ecb071
commit 320e08b8fb
49 changed files with 6061 additions and 5315 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.idea
.vscode
CLAUDE.md
.DS_Store

View File

@@ -56,8 +56,8 @@ ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
@@ -501,7 +501,7 @@ IncludeCategories:
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
@@ -511,7 +511,7 @@ MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
@@ -543,6 +543,6 @@ SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
TabWidth: 4
UseTab: Never
...

View File

@@ -3,8 +3,10 @@ kernelsu-objs += allowlist.o
kernelsu-objs += dynamic_manager.o
kernelsu-objs += apk_sign.o
kernelsu-objs += sucompat.o
kernelsu-objs += pkg_observer.o
kernelsu-objs += throne_tracker.o
kernelsu-objs += core_hook.o
kernelsu-objs += supercalls.o
kernelsu-objs += ksud.o
kernelsu-objs += embed_ksud.o
kernelsu-objs += kernel_compat.o
@@ -134,6 +136,11 @@ else
$(info -- KPM is disabled)
endif
# Check new vfs_getattr()
ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags" ; echo $$?),0)
ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR
endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function

View File

@@ -8,7 +8,9 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include <linux/compiler_types.h>
#endif
#include "ksu.h"
#include "klog.h" // IWYU pragma: keep
@@ -61,7 +63,7 @@ static void remove_uid_from_arr(uid_t uid)
kfree(temp_arr);
}
static void init_default_profiles()
static void init_default_profiles(void)
{
kernel_cap_t full_cap = CAP_FULL_SET;
@@ -93,7 +95,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
bool persistent_allow_list(void);
static bool persistent_allow_list(void);
void ksu_show_allow_list(void)
{
@@ -108,7 +110,7 @@ void ksu_show_allow_list(void)
}
#ifdef CONFIG_KSU_DEBUG
static void ksu_grant_root_to_shell()
static void ksu_grant_root_to_shell(void)
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
@@ -349,7 +351,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true;
}
void do_save_allow_list(struct work_struct *work)
static void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
@@ -379,7 +381,7 @@ void do_save_allow_list(struct work_struct *work)
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
pr_info("save allow list, name: %s uid: %d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
@@ -391,7 +393,7 @@ exit:
filp_close(fp, 0);
}
void do_load_allow_list(struct work_struct *work)
static void do_load_allow_list(struct work_struct *work)
{
loff_t off = 0;
ssize_t ret = 0;
@@ -481,7 +483,7 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
}
// make sure allow list works cross boot
bool persistent_allow_list(void)
static bool persistent_allow_list(void)
{
return ksu_queue_work(&ksu_save_work);
}

View File

@@ -171,7 +171,7 @@ static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, i
}
ksu_kernel_read_compat(fp, cert, *size4, pos);
unsigned char digest[SHA256_DIGEST_SIZE];
if (IS_ERR(ksu_sha256(cert, *size4, digest))) {
if (ksu_sha256(cert, *size4, digest) < 0 ) {
pr_info("sha256 error\n");
return false;
}
@@ -230,7 +230,8 @@ static bool has_v1_signature_file(struct file *fp)
fileName[header.file_name_length] = '\0';
// Check if the entry matches META-INF/MANIFEST.MF
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) == 0) {
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) ==
0) {
return true;
}
} else {
@@ -250,7 +251,9 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
unsigned char buffer[0x11] = { 0 };
u32 size4;
u64 size8, size_of_block;
loff_t pos;
bool v2_signing_valid = false;
int v2_signing_blocks = 0;
bool v3_signing_exist = false;

View File

@@ -19,10 +19,17 @@
#define __PT_IP_REG pc
#define PRCTL_SYMBOL "__arm64_sys_prctl"
#define REBOOT_SYMBOL "__arm64_sys_reboot"
#define SYS_READ_SYMBOL "__arm64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
/*LSM HOOK*/
#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid"
#define PRCTL_SYMBOL "__arm64_sys_prctl"
#define INODE_PERMISSION_SYMBOL "security_inode_permission"
#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check"
#define TASK_ALLOC_SYMBOL "security_task_alloc"
#elif defined(__x86_64__)
@@ -40,10 +47,17 @@
#define __PT_SP_REG sp
#define __PT_IP_REG ip
#define PRCTL_SYMBOL "__x64_sys_prctl"
#define REBOOT_SYMBOL "__x64_sys_reboot"
#define SYS_READ_SYMBOL "__x64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
/*LSM HOOK*/
#define SECURITY_TASK_FIX_SETUID_SYMBOL "security_task_fix_setuid"
#define PRCTL_SYMBOL "__x64_sys_prctl"
#define INODE_PERMISSION_SYMBOL "security_inode_permission"
#define BPRM_CHECK_SECURITY_SYMBOL "security_bprm_check"
#define TASK_ALLOC_SYMBOL "security_task_alloc"
#else
#error "Unsupported arch"

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
#include <linux/nsproxy.h>
#include <linux/sched/task.h>
#include <linux/uaccess.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
@@ -93,3 +95,58 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
return strncpy_from_user_nofault(dst, unsafe_addr, count);
}
struct action_cache {
DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR);
#ifdef SECCOMP_ARCH_COMPAT
DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR);
#endif
};
struct seccomp_filter {
refcount_t refs;
refcount_t users;
bool log;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
bool wait_killable_recv;
#endif
struct action_cache cache;
struct seccomp_filter *prev;
struct bpf_prog *prog;
struct notification *notif;
struct mutex notify_lock;
wait_queue_head_t wqh;
};
void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr)
{
if (!filter) {
return;
}
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
clear_bit(nr, filter->cache.allow_native);
}
#ifdef SECCOMP_ARCH_COMPAT
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
clear_bit(nr, filter->cache.allow_compat);
}
#endif
}
void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr)
{
if (!filter) {
return;
}
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
set_bit(nr, filter->cache.allow_native);
}
#ifdef SECCOMP_ARCH_COMPAT
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
set_bit(nr, filter->cache.allow_compat);
}
#endif
}

View File

@@ -94,4 +94,7 @@ static long ksu_copy_from_user_retry(void *to,
return copy_from_user(to, from, count);
}
extern void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr);
extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr);
#endif

View File

@@ -73,6 +73,8 @@ void kernelsu_exit(void)
{
ksu_allowlist_exit();
ksu_observer_exit();
ksu_throne_tracker_exit();
destroy_workqueue(ksu_workqueue);

View File

@@ -5,37 +5,14 @@
#include <linux/workqueue.h>
#define KERNEL_SU_VERSION KSU_VERSION
#define KERNEL_SU_OPTION 0xDEADBEEF
#define KERNEL_SU_OPTION 0xBADC0DE
#define CMD_GRANT_ROOT 0
#define CMD_BECOME_MANAGER 1
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5
#define CMD_GET_DENY_LIST 6
#define CMD_REPORT_EVENT 7
#define CMD_SET_SEPOLICY 8
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
#define CMD_IS_SU_ENABLED 14
#define CMD_ENABLE_SU 15
extern bool ksu_uid_scanner_enabled;
#ifdef CONFIG_KSU_MANUAL_SU
#define CMD_MANUAL_SU_REQUEST 50
#endif
#define CMD_GET_FULL_VERSION 0xC0FFEE1A
#define CMD_ENABLE_KPM 100
#define CMD_HOOK_TYPE 101
#define CMD_DYNAMIC_MANAGER 103
#define CMD_GET_MANAGERS 104
#define CMD_ENABLE_UID_SCANNER 105
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define EVENT_MODULE_MOUNTED 3
@@ -56,6 +33,10 @@
#define DYNAMIC_MANAGER_OP_GET 1
#define DYNAMIC_MANAGER_OP_CLEAR 2
#define UID_SCANNER_OP_GET_STATUS 0
#define UID_SCANNER_OP_TOGGLE 1
#define UID_SCANNER_OP_CLEAR_ENV 2
struct dynamic_manager_user_config {
unsigned int operation;
unsigned int size;

View File

@@ -1,3 +1,4 @@
#include "manager.h"
#include <asm/current.h>
#include <linux/compat.h>
#include <linux/cred.h>
@@ -73,6 +74,7 @@ void on_post_fs_data(void)
done = true;
pr_info("on_post_fs_data!\n");
ksu_load_allow_list();
ksu_observer_init();
// sanity check, this may influence the performance
stop_input_hook();

View File

@@ -13,18 +13,18 @@ extern void ksu_add_manager(uid_t uid, int signature_index);
extern void ksu_remove_manager(uid_t uid);
extern int ksu_get_manager_signature_index(uid_t uid);
static inline bool ksu_is_manager_uid_valid()
static inline bool ksu_is_manager_uid_valid(void)
{
return ksu_manager_uid != KSU_INVALID_UID;
}
static inline bool is_manager()
static inline bool is_manager(void)
{
return unlikely(ksu_is_any_manager(current_uid().val) ||
(ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val));
}
static inline uid_t ksu_get_manager_uid()
static inline uid_t ksu_get_manager_uid(void)
{
return ksu_manager_uid;
}
@@ -34,9 +34,12 @@ static inline void ksu_set_manager_uid(uid_t uid)
ksu_manager_uid = uid;
}
static inline void ksu_invalidate_manager_uid()
static inline void ksu_invalidate_manager_uid(void)
{
ksu_manager_uid = KSU_INVALID_UID;
}
int ksu_observer_init(void);
void ksu_observer_exit(void);
#endif

View File

@@ -3,6 +3,11 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)
#define mmap_lock mmap_sem
#endif
#define ksu_task_is_dead(t) ((t)->exit_state != 0)

133
kernel/pkg_observer.c Normal file
View File

@@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/fsnotify_backend.h>
#include <linux/slab.h>
#include <linux/rculist.h>
#include <linux/version.h>
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "throne_tracker.h"
#include "throne_comm.h"
#define MASK_SYSTEM (FS_CREATE | FS_MOVE | FS_EVENT_ON_CHILD)
struct watch_dir {
const char *path;
u32 mask;
struct path kpath;
struct inode *inode;
struct fsnotify_mark *mark;
};
static struct fsnotify_group *g;
static int ksu_handle_inode_event(struct fsnotify_mark *mark, u32 mask,
struct inode *inode, struct inode *dir,
const struct qstr *file_name, u32 cookie)
{
if (!file_name)
return 0;
if (mask & FS_ISDIR)
return 0;
if (file_name->len == 13 &&
!memcmp(file_name->name, "packages.list", 13)) {
pr_info("packages.list detected: %d\n", mask);
if (ksu_uid_scanner_enabled) {
ksu_request_userspace_scan();
}
track_throne();
}
return 0;
}
static const struct fsnotify_ops ksu_ops = {
.handle_inode_event = ksu_handle_inode_event,
};
static int add_mark_on_inode(struct inode *inode, u32 mask,
struct fsnotify_mark **out)
{
struct fsnotify_mark *m;
m = kzalloc(sizeof(*m), GFP_KERNEL);
if (!m)
return -ENOMEM;
fsnotify_init_mark(m, g);
m->mask = mask;
if (fsnotify_add_inode_mark(m, inode, 0)) {
fsnotify_put_mark(m);
return -EINVAL;
}
*out = m;
return 0;
}
static int watch_one_dir(struct watch_dir *wd)
{
int ret = kern_path(wd->path, LOOKUP_FOLLOW, &wd->kpath);
if (ret) {
pr_info("path not ready: %s (%d)\n", wd->path, ret);
return ret;
}
wd->inode = d_inode(wd->kpath.dentry);
ihold(wd->inode);
ret = add_mark_on_inode(wd->inode, wd->mask, &wd->mark);
if (ret) {
pr_err("Add mark failed for %s (%d)\n", wd->path, ret);
path_put(&wd->kpath);
iput(wd->inode);
wd->inode = NULL;
return ret;
}
pr_info("watching %s\n", wd->path);
return 0;
}
static void unwatch_one_dir(struct watch_dir *wd)
{
if (wd->mark) {
fsnotify_destroy_mark(wd->mark, g);
fsnotify_put_mark(wd->mark);
wd->mark = NULL;
}
if (wd->inode) {
iput(wd->inode);
wd->inode = NULL;
}
if (wd->kpath.dentry) {
path_put(&wd->kpath);
memset(&wd->kpath, 0, sizeof(wd->kpath));
}
}
static struct watch_dir g_watch = { .path = "/data/system",
.mask = MASK_SYSTEM };
int ksu_observer_init(void)
{
int ret = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
g = fsnotify_alloc_group(&ksu_ops, 0);
#else
g = fsnotify_alloc_group(&ksu_ops);
#endif
if (IS_ERR(g))
return PTR_ERR(g);
ret = watch_one_dir(&g_watch);
pr_info("observer init done\n");
return 0;
}
void ksu_observer_exit(void)
{
unwatch_one_dir(&g_watch);
fsnotify_put_group(g);
pr_info("observer exit done\n");
}

View File

@@ -15,6 +15,23 @@ extern struct timezone sys_tz;
#define SULOG_COMM_LEN 256
#define DEDUP_SECS 10
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
#include <linux/rtc.h>
static inline void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
{
struct rtc_time rtc_tm;
rtc_time64_to_tm(totalsecs, &rtc_tm);
result->tm_sec = rtc_tm.tm_sec;
result->tm_min = rtc_tm.tm_min;
result->tm_hour = rtc_tm.tm_hour;
result->tm_mday = rtc_tm.tm_mday;
result->tm_mon = rtc_tm.tm_mon;
result->tm_year = rtc_tm.tm_year;
}
#endif
struct dedup_key {
u32 crc;
uid_t uid;

609
kernel/supercalls.c Normal file
View File

@@ -0,0 +1,609 @@
#include "supercalls.h"
#include <linux/anon_inodes.h>
#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include "allowlist.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "manager.h"
#include "sulog.h"
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "throne_comm.h"
#include "dynamic_manager.h"
#ifdef CONFIG_KSU_MANUAL_SU
#include "manual_su.h"
#endif
// Forward declarations from core_hook.c
extern void escape_to_root(void);
extern void nuke_ext4_sysfs(void);
extern bool ksu_module_mounted;
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
extern void ksu_sucompat_init(void);
extern void ksu_sucompat_exit(void);
// Forward declaration for anon_ksu_fops
static const struct file_operations anon_ksu_fops;
static bool ksu_su_compat_enabled = true;
bool ksu_uid_scanner_enabled = false;
// Permission check functions
bool perm_check_manager(void)
{
return is_manager();
}
bool perm_check_root(void)
{
return current_uid().val == 0;
}
bool perm_check_basic(void)
{
return current_uid().val == 0 || is_manager();
}
bool perm_check_all(void)
{
return true; // No permission check
}
static void init_uid_scanner(void)
{
ksu_uid_init();
do_load_throne_state(NULL);
if (ksu_uid_scanner_enabled) {
int ret = ksu_throne_comm_init();
if (ret != 0) {
pr_err("Failed to initialize throne communication: %d\n", ret);
}
}
}
static int do_grant_root(void __user *arg)
{
// Check if current UID is allowed
bool is_allowed = is_manager() || ksu_is_allow_uid(current_uid().val);
if (!is_allowed) {
return -EPERM;
}
pr_info("allow root for: %d\n", current_uid().val);
escape_to_root();
return 0;
}
static int do_get_info(void __user *arg)
{
struct ksu_get_info_cmd cmd = {.version = KERNEL_SU_VERSION, .flags = 0};
#ifdef MODULE
cmd.flags |= 0x1;
#endif
if (is_manager()) {
cmd.flags |= 0x2;
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_version: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_report_event(void __user *arg)
{
struct ksu_report_event_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
switch (cmd.event) {
case EVENT_POST_FS_DATA: {
static bool post_fs_data_lock = false;
if (!post_fs_data_lock) {
post_fs_data_lock = true;
pr_info("post-fs-data triggered\n");
on_post_fs_data();
init_uid_scanner();
#if __SULOG_GATE
ksu_sulog_init();
#endif
ksu_dynamic_manager_init();
}
break;
}
case EVENT_BOOT_COMPLETED: {
static bool boot_complete_lock = false;
if (!boot_complete_lock) {
boot_complete_lock = true;
pr_info("boot_complete triggered\n");
}
break;
}
case EVENT_MODULE_MOUNTED: {
ksu_module_mounted = true;
pr_info("module mounted!\n");
nuke_ext4_sysfs();
break;
}
default:
break;
}
return 0;
}
static int do_set_sepolicy(void __user *arg)
{
struct ksu_set_sepolicy_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
return handle_sepolicy(cmd.cmd, (void __user *)cmd.arg);
}
static int do_check_safemode(void __user *arg)
{
struct ksu_check_safemode_cmd cmd;
cmd.in_safe_mode = ksu_is_safe_mode();
if (cmd.in_safe_mode) {
pr_warn("safemode enabled!\n");
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("check_safemode: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_get_allow_list(void __user *arg)
{
struct ksu_get_allow_list_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, true);
if (!success) {
return -EFAULT;
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_allow_list: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_get_deny_list(void __user *arg)
{
struct ksu_get_allow_list_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, false);
if (!success) {
return -EFAULT;
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_deny_list: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_uid_granted_root(void __user *arg)
{
struct ksu_uid_granted_root_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
cmd.granted = ksu_is_allow_uid(cmd.uid);
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("uid_granted_root: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_uid_should_umount(void __user *arg)
{
struct ksu_uid_should_umount_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
return -EFAULT;
}
cmd.should_umount = ksu_uid_should_umount(cmd.uid);
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("uid_should_umount: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_get_manager_uid(void __user *arg)
{
struct ksu_get_manager_uid_cmd cmd;
cmd.uid = ksu_get_manager_uid();
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_manager_uid: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_get_app_profile(void __user *arg)
{
struct ksu_get_app_profile_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("get_app_profile: copy_from_user failed\n");
return -EFAULT;
}
if (!ksu_get_app_profile(&cmd.profile)) {
return -ENOENT;
}
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_app_profile: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_set_app_profile(void __user *arg)
{
struct ksu_set_app_profile_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("set_app_profile: copy_from_user failed\n");
return -EFAULT;
}
if (!ksu_set_app_profile(&cmd.profile, true)) {
#if __SULOG_GATE
ksu_sulog_report_manager_operation("SET_APP_PROFILE",
current_uid().val, cmd.profile.current_uid);
#endif
return -EFAULT;
}
return 0;
}
static int do_is_su_enabled(void __user *arg)
{
struct ksu_is_su_enabled_cmd cmd;
cmd.enabled = ksu_su_compat_enabled;
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("is_su_enabled: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_enable_su(void __user *arg)
{
struct ksu_enable_su_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("enable_su: copy_from_user failed\n");
return -EFAULT;
}
if (cmd.enable == ksu_su_compat_enabled) {
pr_info("enable_su: no need to change\n");
return 0;
}
if (cmd.enable) {
ksu_sucompat_init();
} else {
ksu_sucompat_exit();
}
ksu_su_compat_enabled = cmd.enable;
return 0;
}
// 100. GET_FULL_VERSION - Get full version string
static int do_get_full_version(void __user *arg)
{
struct ksu_get_full_version_cmd cmd = {0};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
strscpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full));
#else
strlcpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full));
#endif
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_full_version: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
// 101. HOOK_TYPE - Get hook type
static int do_get_hook_type(void __user *arg)
{
struct ksu_hook_type_cmd cmd = {0};
const char *type = "Kprobes";
#if defined(CONFIG_KSU_TRACEPOINT_HOOK)
type = "Tracepoint";
#elif defined(CONFIG_KSU_MANUAL_HOOK)
type = "Manual";
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
strscpy(cmd.hook_type, type, sizeof(cmd.hook_type));
#else
strlcpy(cmd.hook_type, type, sizeof(cmd.hook_type));
#endif
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_hook_type: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
// 102. ENABLE_KPM - Check if KPM is enabled
static int do_enable_kpm(void __user *arg)
{
struct ksu_enable_kpm_cmd cmd;
cmd.enabled = IS_ENABLED(CONFIG_KPM);
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("enable_kpm: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_dynamic_manager(void __user *arg)
{
struct ksu_dynamic_manager_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("dynamic_manager: copy_from_user failed\n");
return -EFAULT;
}
int ret = ksu_handle_dynamic_manager(&cmd.config);
if (ret)
return ret;
if (cmd.config.operation == DYNAMIC_MANAGER_OP_GET &&
copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("dynamic_manager: copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_get_managers(void __user *arg)
{
struct ksu_get_managers_cmd cmd;
int ret = ksu_get_active_managers(&cmd.manager_info);
if (ret)
return ret;
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
pr_err("get_managers: copy_from_user failed\n");
return -EFAULT;
}
return 0;
}
static int do_enable_uid_scanner(void __user *arg)
{
struct ksu_enable_uid_scanner_cmd cmd;
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
pr_err("enable_uid_scanner: copy_from_user failed\n");
return -EFAULT;
}
switch (cmd.operation) {
case UID_SCANNER_OP_GET_STATUS: {
bool status = ksu_uid_scanner_enabled;
if (copy_to_user((void __user *)cmd.status_ptr, &status, sizeof(status))) {
pr_err("enable_uid_scanner: copy status failed\n");
return -EFAULT;
}
break;
}
case UID_SCANNER_OP_TOGGLE: {
bool enabled = cmd.enabled;
if (enabled == ksu_uid_scanner_enabled) {
pr_info("enable_uid_scanner: no need to change, already %s\n",
enabled ? "enabled" : "disabled");
break;
}
if (enabled) {
// Enable UID scanner
int ret = ksu_throne_comm_init();
if (ret != 0) {
pr_err("enable_uid_scanner: failed to initialize: %d\n", ret);
return -EFAULT;
}
pr_info("enable_uid_scanner: enabled\n");
} else {
// Disable UID scanner
ksu_throne_comm_exit();
pr_info("enable_uid_scanner: disabled\n");
}
ksu_uid_scanner_enabled = enabled;
ksu_throne_comm_save_state();
break;
}
case UID_SCANNER_OP_CLEAR_ENV: {
// Clear environment (force exit)
ksu_throne_comm_exit();
ksu_uid_scanner_enabled = false;
ksu_throne_comm_save_state();
pr_info("enable_uid_scanner: environment cleared\n");
break;
}
default:
pr_err("enable_uid_scanner: invalid operation\n");
return -EINVAL;
}
return 0;
}
// IOCTL handlers mapping table
static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
{ .cmd = KSU_IOCTL_GRANT_ROOT, .handler = do_grant_root, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_GET_INFO, .handler = do_get_info, .perm_check = perm_check_all},
{ .cmd = KSU_IOCTL_REPORT_EVENT, .handler = do_report_event, .perm_check = perm_check_root},
{ .cmd = KSU_IOCTL_SET_SEPOLICY, .handler = do_set_sepolicy, .perm_check = perm_check_root},
{ .cmd = KSU_IOCTL_CHECK_SAFEMODE, .handler = do_check_safemode, .perm_check = perm_check_all},
{ .cmd = KSU_IOCTL_GET_ALLOW_LIST, .handler = do_get_allow_list, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_GET_DENY_LIST, .handler = do_get_deny_list, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .handler = do_uid_granted_root, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .handler = do_uid_should_umount, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_GET_MANAGER_UID, .handler = do_get_manager_uid, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_GET_APP_PROFILE, .handler = do_get_app_profile, .perm_check = perm_check_manager},
{ .cmd = KSU_IOCTL_SET_APP_PROFILE, .handler = do_set_app_profile, .perm_check = perm_check_manager},
{ .cmd = KSU_IOCTL_IS_SU_ENABLED, .handler = do_is_su_enabled, .perm_check = perm_check_manager},
{ .cmd = KSU_IOCTL_ENABLE_SU, .handler = do_enable_su, .perm_check = perm_check_manager},
{ .cmd = KSU_IOCTL_GET_FULL_VERSION, .handler = do_get_full_version, .perm_check = perm_check_manager},
{ .cmd = KSU_IOCTL_HOOK_TYPE, .handler = do_get_hook_type, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_ENABLE_KPM, .handler = do_enable_kpm, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .handler = do_dynamic_manager, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_GET_MANAGERS, .handler = do_get_managers, .perm_check = perm_check_basic},
{ .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .handler = do_enable_uid_scanner, .perm_check = perm_check_basic},
{ .cmd = 0, .handler = NULL, .perm_check = NULL} // Sentinel
};
// IOCTL dispatcher
static long anon_ksu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int i;
#ifdef CONFIG_KSU_DEBUG
pr_info("ksu ioctl: cmd=0x%x from uid=%d\n", cmd, current_uid().val);
#endif
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
if (cmd == ksu_ioctl_handlers[i].cmd) {
// Check permission first
if (ksu_ioctl_handlers[i].perm_check &&
!ksu_ioctl_handlers[i].perm_check()) {
pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n",
cmd, current_uid().val);
return -EPERM;
}
// Execute handler
return ksu_ioctl_handlers[i].handler(argp);
}
}
pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd);
return -ENOTTY;
}
// File release handler
static int anon_ksu_release(struct inode *inode, struct file *filp)
{
pr_info("ksu fd released\n");
return 0;
}
// File operations structure
static const struct file_operations anon_ksu_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = anon_ksu_ioctl,
.compat_ioctl = anon_ksu_ioctl,
.release = anon_ksu_release,
};
// Install KSU fd to current process
int ksu_install_fd(void)
{
struct file *filp;
int fd;
// Get unused fd
fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0) {
pr_err("ksu_install_fd: failed to get unused fd\n");
return fd;
}
// Create anonymous inode file
filp = anon_inode_getfile("[ksu_driver]", &anon_ksu_fops, NULL, O_RDWR | O_CLOEXEC);
if (IS_ERR(filp)) {
pr_err("ksu_install_fd: failed to create anon inode file\n");
put_unused_fd(fd);
return PTR_ERR(filp);
}
// Install fd
fd_install(fd, filp);
pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid);
return fd;
}

142
kernel/supercalls.h Normal file
View File

@@ -0,0 +1,142 @@
#ifndef __KSU_H_SUPERCALLS
#define __KSU_H_SUPERCALLS
#include <linux/types.h>
#include <linux/ioctl.h>
#include "ksu.h"
// Magic numbers for reboot hook to install fd
#define KSU_INSTALL_MAGIC1 0xDEADBEEF
#define KSU_INSTALL_MAGIC2 0xCAFEBABE
// Command structures for ioctl
struct ksu_become_daemon_cmd {
__u8 token[65]; // Input: daemon token (null-terminated)
};
struct ksu_get_info_cmd {
__u32 version; // Output: KERNEL_SU_VERSION
__u32 flags; // Output: flags (bit 0: MODULE mode)
};
struct ksu_report_event_cmd {
__u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
};
struct ksu_set_sepolicy_cmd {
__u64 cmd; // Input: sepolicy command
__aligned_u64 arg; // Input: sepolicy argument pointer
};
struct ksu_check_safemode_cmd {
__u8 in_safe_mode; // Output: true if in safe mode, false otherwise
};
struct ksu_get_allow_list_cmd {
__u32 uids[128]; // Output: array of allowed/denied UIDs
__u32 count; // Output: number of UIDs in array
__u8 allow; // Input: true for allow list, false for deny list
};
struct ksu_uid_granted_root_cmd {
__u32 uid; // Input: target UID to check
__u8 granted; // Output: true if granted, false otherwise
};
struct ksu_uid_should_umount_cmd {
__u32 uid; // Input: target UID to check
__u8 should_umount; // Output: true if should umount, false otherwise
};
struct ksu_get_manager_uid_cmd {
__u32 uid; // Output: manager UID
};
struct ksu_get_app_profile_cmd {
struct app_profile profile; // Input/Output: app profile structure
};
struct ksu_set_app_profile_cmd {
struct app_profile profile; // Input: app profile structure
};
struct ksu_is_su_enabled_cmd {
__u8 enabled; // Output: true if su compat enabled
};
struct ksu_enable_su_cmd {
__u8 enable; // Input: true to enable, false to disable
};
// Other command structures
struct ksu_get_full_version_cmd {
char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string
};
struct ksu_hook_type_cmd {
char hook_type[32]; // Output: hook type string
};
struct ksu_enable_kpm_cmd {
__u8 enabled; // Output: true if KPM is enabled
};
struct ksu_dynamic_manager_cmd {
struct dynamic_manager_user_config config; // Input/Output: dynamic manager config
};
struct ksu_get_managers_cmd {
struct manager_list_info manager_info; // Output: manager list information
};
struct ksu_enable_uid_scanner_cmd {
__u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV)
__u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE)
void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS)
};
// IOCTL command definitions
#define KSU_IOCTL_GRANT_ROOT _IO('K', 1)
#define KSU_IOCTL_GET_INFO _IOR('K', 2, struct ksu_get_info_cmd)
#define KSU_IOCTL_REPORT_EVENT _IOW('K', 3, struct ksu_report_event_cmd)
#define KSU_IOCTL_SET_SEPOLICY _IOWR('K', 4, struct ksu_set_sepolicy_cmd)
#define KSU_IOCTL_CHECK_SAFEMODE _IOR('K', 5, struct ksu_check_safemode_cmd)
#define KSU_IOCTL_GET_ALLOW_LIST _IOWR('K', 6, struct ksu_get_allow_list_cmd)
#define KSU_IOCTL_GET_DENY_LIST _IOWR('K', 7, struct ksu_get_allow_list_cmd)
#define KSU_IOCTL_UID_GRANTED_ROOT _IOWR('K', 8, struct ksu_uid_granted_root_cmd)
#define KSU_IOCTL_UID_SHOULD_UMOUNT _IOWR('K', 9, struct ksu_uid_should_umount_cmd)
#define KSU_IOCTL_GET_MANAGER_UID _IOR('K', 10, struct ksu_get_manager_uid_cmd)
#define KSU_IOCTL_GET_APP_PROFILE _IOWR('K', 11, struct ksu_get_app_profile_cmd)
#define KSU_IOCTL_SET_APP_PROFILE _IOW('K', 12, struct ksu_set_app_profile_cmd)
#define KSU_IOCTL_IS_SU_ENABLED _IOR('K', 13, struct ksu_is_su_enabled_cmd)
#define KSU_IOCTL_ENABLE_SU _IOW('K', 14, struct ksu_enable_su_cmd)
// Other IOCTL command definitions
#define KSU_IOCTL_GET_FULL_VERSION _IOR('K', 100, struct ksu_get_full_version_cmd)
#define KSU_IOCTL_HOOK_TYPE _IOR('K', 101, struct ksu_hook_type_cmd)
#define KSU_IOCTL_ENABLE_KPM _IOR('K', 102, struct ksu_enable_kpm_cmd)
#define KSU_IOCTL_DYNAMIC_MANAGER _IOWR('K', 103, struct ksu_dynamic_manager_cmd)
#define KSU_IOCTL_GET_MANAGERS _IOWR('K', 104, struct ksu_get_managers_cmd)
#define KSU_IOCTL_ENABLE_UID_SCANNER _IOWR('K', 105, struct ksu_enable_uid_scanner_cmd)
// IOCTL handler types
typedef int (*ksu_ioctl_handler_t)(void __user *arg);
typedef bool (*ksu_perm_check_t)(void);
// Permission check functions
bool perm_check_manager(void);
bool perm_check_root(void);
bool perm_check_basic(void);
bool perm_check_all(void);
// IOCTL command mapping
struct ksu_ioctl_cmd_map {
unsigned int cmd;
ksu_ioctl_handler_t handler;
ksu_perm_check_t perm_check; // Permission check function
};
// Install KSU fd to current process
int ksu_install_fd(void);
#endif // __KSU_H_SUPERCALLS

View File

@@ -8,6 +8,7 @@
#include "klog.h"
#include "throne_comm.h"
#include "kernel_compat.h"
#include "ksu.h"
#define PROC_UID_SCANNER "ksu_uid_scanner"
#define UID_SCANNER_STATE_FILE "/data/adb/ksu/.uid_scanner"
@@ -18,7 +19,6 @@ static struct work_struct scan_work;
static struct work_struct ksu_state_save_work;
static struct work_struct ksu_state_load_work;
extern bool ksu_uid_scanner_enabled;
// Signal userspace to rescan
static bool need_rescan = false;
@@ -145,6 +145,7 @@ static ssize_t uid_scanner_write(struct file *file, const char __user *buffer,
return count;
}
#ifdef KSU_COMPAT_HAS_PROC_OPS
static const struct proc_ops uid_scanner_proc_ops = {
.proc_open = uid_scanner_open,
.proc_read = seq_read,
@@ -152,6 +153,16 @@ static const struct proc_ops uid_scanner_proc_ops = {
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#else
static const struct file_operations uid_scanner_proc_ops = {
.owner = THIS_MODULE,
.open = uid_scanner_open,
.read = seq_read,
.write = uid_scanner_write,
.llseek = seq_lseek,
.release = single_release,
};
#endif
int ksu_throne_comm_init(void)
{

View File

@@ -289,8 +289,23 @@ FILLDIR_RETURN_TYPE user_data_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE;
}
/*
4.11, also backported on lineage common kernel 4.9 !!
int vfs_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
4.10
int vfs_getattr(struct path *path, struct kstat *stat)
basically no mask and flags for =< 4.10
*/
struct kstat stat;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) || defined(KSU_HAS_NEW_VFS_GETATTR)
err = vfs_getattr(&path, &stat, STATX_UID, AT_STATX_SYNC_AS_STAT);
#else
err = vfs_getattr(&path, &stat);
#endif
path_put(&path);
if (err) {
@@ -393,7 +408,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
return FILLDIR_ACTOR_CONTINUE; // Skip staging package
}
if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir,
namelen, name) >= DATA_PATH_LEN) {
pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen,
@@ -416,7 +430,11 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
} else {
if ((namelen == 8) && (strncmp(name, "base.apk", namelen) == 0)) {
struct apk_path_hash *pos, *n;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
unsigned int hash = full_name_hash(dirpath, strlen(dirpath));
#else
unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath));
#endif
list_for_each_entry(pos, &apk_path_hash_list, list) {
if (hash == pos->hash) {
pos->exists = true;
@@ -441,7 +459,6 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
apk_data->exists = true;
list_add_tail(&apk_data->list, &apk_path_hash_list);
}
} else if (is_manager_apk(dirpath)) {
crown_manager(dirpath, my_ctx->private_data, 0);
*my_ctx->stop = 1;
@@ -556,9 +573,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
return exist;
}
extern bool ksu_uid_scanner_enabled;
void track_throne()
void track_throne(void)
{
struct list_head uid_list;
struct uid_data *np, *n;
@@ -636,12 +651,12 @@ out:
}
}
void ksu_throne_tracker_init()
void ksu_throne_tracker_init(void)
{
// nothing to do
}
void ksu_throne_tracker_exit()
void ksu_throne_tracker_exit(void)
{
// nothing to do
}

View File

@@ -6,17 +6,12 @@
#include <android/log.h>
#include <string.h>
NativeBridge(becomeManager, jboolean, jstring pkg) {
const char* cpkg = GetEnvironment()->GetStringUTFChars(env, pkg, JNI_FALSE);
bool result = become_manager(cpkg);
GetEnvironment()->ReleaseStringUTFChars(env, pkg, cpkg);
return result;
}
NativeBridgeNP(getVersion, jint) {
return get_version();
uint32_t version = get_version();
if (version > INT32_MAX) {
LogDebug("Version overflow: %u", version);
}
return (jint)version;
}
// get VERSION FULL
@@ -27,15 +22,18 @@ NativeBridgeNP(getFullVersion, jstring) {
}
NativeBridgeNP(getAllowList, jintArray) {
int uids[1024];
int size = 0;
bool result = get_allow_list(uids, &size);
LogDebug("getAllowList: %d, size: %d", result, size);
struct ksu_get_allow_list_cmd cmd = {};
bool result = get_allow_list(&cmd);
if (result) {
jintArray array = GetEnvironment()->NewIntArray(env, size);
GetEnvironment()->SetIntArrayRegion(env, array, 0, size, uids);
jsize array_size = (jsize)cmd.count;
if (array_size < 0 || (unsigned int)array_size != cmd.count) {
LogDebug("Invalid array size: %u", cmd.count);
return GetEnvironment()->NewIntArray(env, 0);
}
jintArray array = GetEnvironment()->NewIntArray(env, array_size);
GetEnvironment()->SetIntArrayRegion(env, array, 0, array_size, (const jint *)(cmd.uids));
return array;
}
@@ -51,6 +49,10 @@ NativeBridgeNP(isLkmMode, jboolean) {
return is_lkm_mode();
}
NativeBridgeNP(isManager, jboolean) {
return is_manager();
}
static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) {
jclass cls = GetEnvironment()->GetObjectClass(env, list);
jmethodID add = GetEnvironment()->GetMethodID(env, cls, "add", "(Ljava/lang/Object;)Z");
@@ -124,7 +126,7 @@ NativeBridge(getAppProfile, jobject, jstring pkg, jint uid) {
strcpy(profile.key, key);
profile.current_uid = uid;
bool useDefaultProfile = !get_app_profile(key, &profile);
bool useDefaultProfile = get_app_profile(&profile) != 0;
jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$Profile");
jmethodID constructor = GetEnvironment()->GetMethodID(env, cls, "<init>", "()V");
@@ -305,8 +307,8 @@ NativeBridgeNP(isKPMEnabled, jboolean) {
// Get HOOK type
NativeBridgeNP(getHookType, jstring) {
char hook_type[16];
get_hook_type(hook_type, sizeof(hook_type));
char hook_type[32] = { 0 };
get_hook_type((char *) &hook_type);
return GetEnvironment()->NewStringUTF(env, hook_type);
}

View File

@@ -7,6 +7,11 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <android/log.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include "prelude.h"
#include "ksu.h"
@@ -21,170 +26,193 @@ extern const char* zako_file_verrcidx2str(uint8_t index);
#endif // __aarch64__ || _M_ARM64 || __arm__ || _M_ARM
#define KERNEL_SU_OPTION 0xDEADBEEF
static int fd = -1;
#define CMD_GRANT_ROOT 0
#define CMD_BECOME_MANAGER 1
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_SU_LIST 5
#define CMD_GET_DENY_LIST 6
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_IS_UID_GRANTED_ROOT 12
#define CMD_IS_UID_SHOULD_UMOUNT 13
#define CMD_IS_SU_ENABLED 14
#define CMD_ENABLE_SU 15
#define CMD_GET_VERSION_FULL 0xC0FFEE1A
#define CMD_ENABLE_KPM 100
#define CMD_HOOK_TYPE 101
#define CMD_DYNAMIC_MANAGER 103
#define CMD_GET_MANAGERS 104
#define CMD_ENABLE_UID_SCANNER 105
#define DYNAMIC_MANAGER_OP_SET 0
#define DYNAMIC_MANAGER_OP_GET 1
#define DYNAMIC_MANAGER_OP_CLEAR 2
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
int32_t rtn = prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result);
return result == KERNEL_SU_OPTION && rtn == -1;
}
bool become_manager(const char* pkg) {
char param[128];
uid_t uid = getuid();
uint32_t userId = uid / 100000;
if (userId == 0) {
sprintf(param, "/data/data/%s", pkg);
} else {
snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg);
static inline int scan_driver_fd() {
const char *kName = "[ksu_driver]";
DIR *fd_dir = opendir("/proc/self/fd");
if (!fd_dir) {
return -1;
}
return ksuctl(CMD_BECOME_MANAGER, param, NULL);
}
int found = -1;
struct dirent *de;
char path[64];
char target[PATH_MAX];
// cache the result to avoid unnecessary syscall
static bool is_lkm;
int get_version() {
int32_t version = -1;
int32_t flags = 0;
ksuctl(CMD_GET_VERSION, &version, &flags);
if (!is_lkm && (flags & 0x1)) {
is_lkm = true;
while ((de = readdir(fd_dir)) != NULL) {
if (de->d_name[0] == '.') {
continue;
}
return version;
char *endptr = nullptr;
long fd_long = strtol(de->d_name, &endptr, 10);
if (!de->d_name[0] || *endptr != '\0' || fd_long < 0 || fd_long > INT_MAX) {
continue;
}
snprintf(path, sizeof(path), "/proc/self/fd/%s", de->d_name);
ssize_t n = readlink(path, target, sizeof(target) - 1);
if (n < 0) {
continue;
}
target[n] = '\0';
const char *base = strrchr(target, '/');
base = base ? base + 1 : target;
if (strstr(base, kName)) {
found = (int)fd_long;
break;
}
}
closedir(fd_dir);
return found;
}
void get_full_version(char* buff) {
ksuctl(CMD_GET_VERSION_FULL, buff, NULL);
static int ksuctl(unsigned long op, void* arg) {
if (fd < 0) {
fd = scan_driver_fd();
}
return ioctl(fd, op, arg);
}
bool get_allow_list(int *uids, int *size) {
return ksuctl(CMD_GET_SU_LIST, uids, size);
static struct ksu_get_info_cmd g_version = {0};
struct ksu_get_info_cmd get_info() {
if (!g_version.version) {
ksuctl(KSU_IOCTL_GET_INFO, &g_version);
}
return g_version;
}
uint32_t get_version() {
auto info = get_info();
return info.version;
}
bool get_allow_list(struct ksu_get_allow_list_cmd *cmd) {
return ksuctl(KSU_IOCTL_GET_ALLOW_LIST, cmd) == 0;
}
bool is_safe_mode() {
return ksuctl(CMD_CHECK_SAFEMODE, NULL, NULL);
struct ksu_check_safemode_cmd cmd = {};
ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &cmd);
return cmd.in_safe_mode;
}
bool is_lkm_mode() {
// you should call get_version first!
return is_lkm;
auto info = get_info();
return (info.flags & 0x1) != 0;
}
bool is_manager() {
auto info = get_info();
return (info.flags & 0x2) != 0;
}
bool uid_should_umount(int uid) {
int should;
return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, (void*) ((size_t) uid), &should) && should;
struct ksu_uid_should_umount_cmd cmd = {};
cmd.uid = uid;
ksuctl(KSU_IOCTL_UID_SHOULD_UMOUNT, &cmd);
return cmd.should_umount;
}
bool set_app_profile(const struct app_profile* profile) {
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, NULL);
bool set_app_profile(const struct app_profile *profile) {
struct ksu_set_app_profile_cmd cmd = {};
cmd.profile = *profile;
return ksuctl(KSU_IOCTL_SET_APP_PROFILE, &cmd) == 0;
}
bool get_app_profile(char* key, struct app_profile* profile) {
return ksuctl(CMD_GET_APP_PROFILE, profile, NULL);
int get_app_profile(struct app_profile *profile) {
struct ksu_get_app_profile_cmd cmd = {.profile = *profile};
int ret = ksuctl(KSU_IOCTL_GET_APP_PROFILE, &cmd);
*profile = cmd.profile;
return ret;
}
bool set_su_enabled(bool enabled) {
return ksuctl(CMD_ENABLE_SU, (void*) enabled, NULL);
struct ksu_enable_su_cmd cmd = {.enable = enabled};
return ksuctl(KSU_IOCTL_ENABLE_SU, &cmd) == 0;
}
bool is_su_enabled() {
int enabled = true;
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
ksuctl(CMD_IS_SU_ENABLED, &enabled, NULL);
return enabled;
struct ksu_is_su_enabled_cmd cmd = {};
return ksuctl(KSU_IOCTL_IS_SU_ENABLED, &cmd) == 0 && cmd.enabled;
}
bool is_KPM_enable() {
int enabled = false;
ksuctl(CMD_ENABLE_KPM, &enabled, NULL);
return enabled;
void get_full_version(char* buff) {
struct ksu_get_full_version_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_GET_FULL_VERSION, &cmd) == 0) {
strncpy(buff, cmd.version_full, KSU_FULL_VERSION_STRING - 1);
buff[KSU_FULL_VERSION_STRING - 1] = '\0';
} else {
buff[0] = '\0';
}
}
bool get_hook_type(char* hook_type, size_t size) {
if (hook_type == NULL || size == 0) {
bool is_KPM_enable(void)
{
struct ksu_enable_kpm_cmd cmd = {};
return ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled;
}
void get_hook_type(char *buff)
{
struct ksu_hook_type_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) {
strncpy(buff, cmd.hook_type, 32 - 1);
buff[32 - 1] = '\0';
} else {
strcpy(buff, "Unknown");
}
}
bool set_dynamic_manager(unsigned int size, const char *hash)
{
struct ksu_dynamic_manager_cmd cmd = {0};
cmd.config.operation = DYNAMIC_MANAGER_OP_SET;
cmd.config.size = size;
strlcpy(cmd.config.hash, hash, sizeof(cmd.config.hash));
return ksuctl(KSU_IOCTL_DYNAMIC_MANAGER, &cmd) == 0;
}
bool get_dynamic_manager(struct dynamic_manager_user_config *cfg)
{
if (!cfg)
return false;
}
static char cached_hook_type[16] = {0};
if (cached_hook_type[0] == '\0') {
if (!ksuctl(CMD_HOOK_TYPE, cached_hook_type, NULL)) {
strcpy(cached_hook_type, "Unknown");
}
}
struct ksu_dynamic_manager_cmd cmd = {0};
cmd.config.operation = DYNAMIC_MANAGER_OP_GET;
strncpy(hook_type, cached_hook_type, size);
hook_type[size - 1] = '\0';
if (ksuctl(KSU_IOCTL_DYNAMIC_MANAGER, &cmd) != 0)
return false;
*cfg = cmd.config;
return true;
}
bool set_dynamic_manager(unsigned int size, const char* hash) {
if (hash == NULL) {
bool clear_dynamic_manager(void)
{
struct ksu_dynamic_manager_cmd cmd = {0};
cmd.config.operation = DYNAMIC_MANAGER_OP_CLEAR;
return ksuctl(KSU_IOCTL_DYNAMIC_MANAGER, &cmd) == 0;
}
bool get_managers_list(struct manager_list_info *info)
{
if (!info)
return false;
}
struct dynamic_manager_user_config config;
config.operation = DYNAMIC_MANAGER_OP_SET;
config.size = size;
strncpy(config.hash, hash, sizeof(config.hash) - 1);
config.hash[sizeof(config.hash) - 1] = '\0';
return ksuctl(CMD_DYNAMIC_MANAGER, &config, NULL);
}
bool get_dynamic_manager(struct dynamic_manager_user_config* config) {
if (config == NULL) {
struct ksu_get_managers_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_GET_MANAGERS, &cmd) != 0)
return false;
}
config->operation = DYNAMIC_MANAGER_OP_GET;
return ksuctl(CMD_DYNAMIC_MANAGER, config, NULL);
*info = cmd.manager_info;
return true;
}
bool clear_dynamic_manager() {
struct dynamic_manager_user_config config;
config.operation = DYNAMIC_MANAGER_OP_CLEAR;
return ksuctl(CMD_DYNAMIC_MANAGER, &config, NULL);
}
bool get_managers_list(struct manager_list_info* info) {
if (info == NULL) {
return false;
}
return ksuctl(CMD_GET_MANAGERS, info, NULL);
}
bool verify_module_signature(const char* input) {
#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
@@ -193,13 +221,13 @@ bool verify_module_signature(const char* input) {
return false;
}
int fd = zako_sys_file_open(input);
if (fd < 0) {
int file_fd = zako_sys_file_open(input);
if (file_fd < 0) {
LogDebug("verify_module_signature: failed to open file: %s", input);
return false;
}
uint32_t results = zako_file_verify_esig(fd, 0);
uint32_t results = zako_file_verify_esig(file_fd, 0);
if (results != 0) {
/* If important error occured, verification process should
@@ -233,7 +261,7 @@ bool verify_module_signature(const char* input) {
}
exit:
close(fd);
close(file_fd);
LogDebug("verify_module_signature: path=%s, results=0x%x, success=%s",
input, results, (results == 0) ? "true" : "false");
return results == 0;
@@ -243,16 +271,31 @@ bool verify_module_signature(const char* input) {
#endif
}
bool is_uid_scanner_enabled() {
bool is_uid_scanner_enabled(void)
{
bool status = false;
ksuctl(CMD_ENABLE_UID_SCANNER, (void*)0, &status);
return status;
struct ksu_enable_uid_scanner_cmd cmd = {
.operation = UID_SCANNER_OP_GET_STATUS,
.status_ptr = (__u64)(uintptr_t)&status
};
return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd) == 0 != 0 && status;
}
bool set_uid_scanner_enabled(bool enabled) {
return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)1, (void*)enabled);
bool set_uid_scanner_enabled(bool enabled)
{
struct ksu_enable_uid_scanner_cmd cmd = {
.operation = UID_SCANNER_OP_TOGGLE,
.enabled = enabled
};
return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd);
}
bool clear_uid_scanner_environment() {
return ksuctl(CMD_ENABLE_UID_SCANNER, (void*)2, NULL);
bool clear_uid_scanner_environment(void)
{
struct ksu_enable_uid_scanner_cmd cmd = {
.operation = UID_SCANNER_OP_CLEAR_ENV
};
return ksuctl(KSU_IOCTL_ENABLE_UID_SCANNER, &cmd);
}

View File

@@ -8,14 +8,11 @@
#include "prelude.h"
#include <linux/capability.h>
#include <sys/types.h>
#include <sys/ioctl.h>
bool become_manager(const char *);
#define KSU_FULL_VERSION_STRING 255
void get_full_version(char* buff);
int get_version();
bool get_allow_list(int *uids, int *size);
uint32_t get_version();
bool uid_should_umount(int uid);
@@ -23,6 +20,10 @@ bool is_safe_mode();
bool is_lkm_mode();
bool is_manager();
void get_full_version(char* buff);
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
@@ -33,6 +34,10 @@ bool is_lkm_mode();
#define DYNAMIC_MANAGER_OP_GET 1
#define DYNAMIC_MANAGER_OP_CLEAR 2
#define UID_SCANNER_OP_GET_STATUS 0
#define UID_SCANNER_OP_TOGGLE 1
#define UID_SCANNER_OP_CLEAR_ENV 2
struct dynamic_manager_user_config {
unsigned int operation;
unsigned int size;
@@ -98,7 +103,7 @@ struct manager_list_info {
bool set_app_profile(const struct app_profile* profile);
bool get_app_profile(char* key, struct app_profile* profile);
int get_app_profile(struct app_profile* profile);
bool set_su_enabled(bool enabled);
@@ -106,8 +111,7 @@ bool is_su_enabled();
bool is_KPM_enable();
bool get_hook_type(char* hook_type, size_t size);
void get_hook_type(char* hook_type);
bool set_dynamic_manager(unsigned int size, const char* hash);
@@ -125,4 +129,119 @@ bool set_uid_scanner_enabled(bool enabled);
bool clear_uid_scanner_environment();
struct ksu_become_daemon_cmd {
__u8 token[65]; // Input: daemon token (null-terminated)
};
struct ksu_get_info_cmd {
__u32 version; // Output: KERNEL_SU_VERSION
__u32 flags; // Output: flags (bit 0: MODULE mode)
};
struct ksu_report_event_cmd {
__u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
};
struct ksu_set_sepolicy_cmd {
__u64 cmd; // Input: sepolicy command
__aligned_u64 arg; // Input: sepolicy argument pointer
};
struct ksu_check_safemode_cmd {
__u8 in_safe_mode; // Output: true if in safe mode, false otherwise
};
struct ksu_get_allow_list_cmd {
__u32 uids[128]; // Output: array of allowed/denied UIDs
__u32 count; // Output: number of UIDs in array
__u8 allow; // Input: true for allow list, false for deny list
};
struct ksu_uid_granted_root_cmd {
__u32 uid; // Input: target UID to check
__u8 granted; // Output: true if granted, false otherwise
};
struct ksu_uid_should_umount_cmd {
__u32 uid; // Input: target UID to check
__u8 should_umount; // Output: true if should umount, false otherwise
};
struct ksu_get_manager_uid_cmd {
__u32 uid; // Output: manager UID
};
struct ksu_set_manager_uid_cmd {
__u32 uid; // Input: new manager UID
};
struct ksu_get_app_profile_cmd {
struct app_profile profile; // Input/Output: app profile structure
};
struct ksu_set_app_profile_cmd {
struct app_profile profile; // Input: app profile structure
};
struct ksu_is_su_enabled_cmd {
__u8 enabled; // Output: true if su compat enabled
};
struct ksu_enable_su_cmd {
__u8 enable; // Input: true to enable, false to disable
};
// Other command structures
struct ksu_get_full_version_cmd {
char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string
};
struct ksu_hook_type_cmd {
char hook_type[32]; // Output: hook type string
};
struct ksu_enable_kpm_cmd {
__u8 enabled; // Output: true if KPM is enabled
};
struct ksu_dynamic_manager_cmd {
struct dynamic_manager_user_config config; // Input/Output: dynamic manager config
};
struct ksu_get_managers_cmd {
struct manager_list_info manager_info; // Output: manager list information
};
struct ksu_enable_uid_scanner_cmd {
__u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV)
__u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE)
__u64 status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS)
};
// IOCTL command definitions
#define KSU_IOCTL_GRANT_ROOT _IO('K', 1)
#define KSU_IOCTL_GET_INFO _IOR('K', 2, struct ksu_get_info_cmd)
#define KSU_IOCTL_REPORT_EVENT _IOW('K', 3, struct ksu_report_event_cmd)
#define KSU_IOCTL_SET_SEPOLICY _IOWR('K', 4, struct ksu_set_sepolicy_cmd)
#define KSU_IOCTL_CHECK_SAFEMODE _IOR('K', 5, struct ksu_check_safemode_cmd)
#define KSU_IOCTL_GET_ALLOW_LIST _IOWR('K', 6, struct ksu_get_allow_list_cmd)
#define KSU_IOCTL_GET_DENY_LIST _IOWR('K', 7, struct ksu_get_allow_list_cmd)
#define KSU_IOCTL_UID_GRANTED_ROOT _IOWR('K', 8, struct ksu_uid_granted_root_cmd)
#define KSU_IOCTL_UID_SHOULD_UMOUNT _IOWR('K', 9, struct ksu_uid_should_umount_cmd)
#define KSU_IOCTL_GET_MANAGER_UID _IOR('K', 10, struct ksu_get_manager_uid_cmd)
#define KSU_IOCTL_GET_APP_PROFILE _IOWR('K', 11, struct ksu_get_app_profile_cmd)
#define KSU_IOCTL_SET_APP_PROFILE _IOW('K', 12, struct ksu_set_app_profile_cmd)
#define KSU_IOCTL_IS_SU_ENABLED _IOR('K', 13, struct ksu_is_su_enabled_cmd)
#define KSU_IOCTL_ENABLE_SU _IOW('K', 14, struct ksu_enable_su_cmd)
// Other IOCTL command definitions
#define KSU_IOCTL_GET_FULL_VERSION _IOR('K', 100, struct ksu_get_full_version_cmd)
#define KSU_IOCTL_HOOK_TYPE _IOR('K', 101, struct ksu_hook_type_cmd)
#define KSU_IOCTL_ENABLE_KPM _IOR('K', 102, struct ksu_enable_kpm_cmd)
#define KSU_IOCTL_DYNAMIC_MANAGER _IOWR('K', 103, struct ksu_dynamic_manager_cmd)
#define KSU_IOCTL_GET_MANAGERS _IOWR('K', 104, struct ksu_get_managers_cmd)
#define KSU_IOCTL_ENABLE_UID_SCANNER _IOWR('K', 105, struct ksu_enable_uid_scanner_cmd)
bool get_allow_list(struct ksu_get_allow_list_cmd*);
#endif //KERNELSU_KSU_H

View File

@@ -16,17 +16,15 @@ object Natives {
// 10946: add capabilities
// 10977: change groups_count and groups to avoid overflow write
// 11071: Fix the issue of failing to set a custom SELinux type.
const val MINIMAL_SUPPORTED_KERNEL = 11071
const val MINIMAL_SUPPORTED_KERNEL_FULL = "v3.1.8"
// 11640: Support query working mode, LKM or GKI
// when MINIMAL_SUPPORTED_KERNEL > 11640, we can remove this constant.
const val MINIMAL_SUPPORTED_KERNEL_LKM = 11648
// 12143: breaking: new supercall impl
const val MINIMAL_SUPPORTED_KERNEL = 12143
// 12040: Support disable sucompat mode
const val MINIMAL_SUPPORTED_SU_COMPAT = 12040
const val KERNEL_SU_DOMAIN = "u:r:su:s0"
const val MINIMAL_SUPPORTED_KERNEL_FULL = "v3.1.8"
const val MINIMAL_SUPPORTED_KPM = 12800
const val MINIMAL_SUPPORTED_DYNAMIC_MANAGER = 13215
@@ -66,8 +64,6 @@ object Natives {
System.loadLibrary("kernelsu")
}
// become root manager, return true if success.
external fun becomeManager(pkg: String?): Boolean
val version: Int
external get
@@ -81,6 +77,9 @@ object Natives {
val isLkmMode: Boolean
external get
val isManager: Boolean
external get
external fun uidShouldUmount(uid: Int): Boolean
/**
@@ -99,6 +98,7 @@ object Natives {
*/
external fun isSuEnabled(): Boolean
external fun setSuEnabled(enabled: Boolean): Boolean
external fun grantRoot(): Boolean
external fun isKPMEnabled(): Boolean
external fun getHookType(): String

View File

@@ -74,7 +74,7 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
val isManager = Natives.becomeManager(packageName)
val isManager = Natives.isManager
if (isManager) {
install()
}

View File

@@ -15,7 +15,6 @@ import com.ramcosta.composedestinations.spec.RouteOrDirection
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
import com.sukisu.ultra.Natives
import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.MainActivity
import com.sukisu.ultra.ui.activity.util.*
import com.sukisu.ultra.ui.activity.util.AppData.getKpmVersionUse
@@ -29,7 +28,7 @@ import com.sukisu.ultra.ui.util.*
@Composable
fun BottomBar(navController: NavHostController) {
val navigator = navController.rememberDestinationsNavigator()
val isFullFeatured = AppData.isFullFeatured(ksuApp.packageName)
val isFullFeatured = AppData.isFullFeatured()
val kpmVersion = getKpmVersionUse()
val cardColor = MaterialTheme.colorScheme.surfaceContainer
val activity = LocalContext.current as MainActivity

View File

@@ -175,8 +175,8 @@ object AppData {
/**
* 检查是否是完整功能模式
*/
fun isFullFeatured(packageName: String): Boolean {
val isManager = Natives.becomeManager(packageName)
fun isFullFeatured(): Boolean {
val isManager = Natives.isManager
return isManager && !Natives.requireNewKernel() && rootAvailable()
}
}

View File

@@ -8,7 +8,7 @@ import com.sukisu.ultra.ksuApp
fun KsuIsValid(
content: @Composable () -> Unit
) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val isManager = Natives.isManager
val ksuVersion = if (isManager) Natives.version else null
if (ksuVersion != null) {

View File

@@ -2,6 +2,7 @@ package com.sukisu.ultra.ui.screen
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
@@ -48,8 +49,9 @@ import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.getCardColors
import com.sukisu.ultra.ui.theme.getCardElevation
import com.sukisu.ultra.ui.util.*
import com.topjohnwu.superuser.ShellUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.time.LocalDateTime
@@ -179,127 +181,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
// UID 扫描开关
if (Natives.version >= Natives.MINIMAL_SUPPORTED_UID_SCANNER) {
var uidAutoScanEnabled by rememberSaveable {
mutableStateOf(prefs.getBoolean("uid_auto_scan", false))
}
var uidMultiUserScanEnabled by rememberSaveable {
mutableStateOf(prefs.getBoolean("uid_multi_user_scan", false))
}
LaunchedEffect(Unit) {
uidAutoScanEnabled = Natives.isUidScannerEnabled()
uidMultiUserScanEnabled = getUidMultiUserScan()
prefs.edit {
putBoolean("uid_auto_scan", uidAutoScanEnabled)
putBoolean("uid_multi_user_scan", uidMultiUserScanEnabled)
}
}
// 用户态扫描应用列表开关
SwitchItem(
icon = Icons.Filled.Scanner,
title = stringResource(R.string.uid_auto_scan_title),
summary = stringResource(R.string.uid_auto_scan_summary),
checked = uidAutoScanEnabled,
onCheckedChange = { enabled ->
scope.launch {
try {
if (setUidAutoScan(enabled)) {
uidAutoScanEnabled = enabled
prefs.edit { putBoolean("uid_auto_scan", enabled) }
if (!enabled) {
uidMultiUserScanEnabled = false
prefs.edit { putBoolean("uid_multi_user_scan", false) }
}
} else {
snackBarHost.showSnackbar(context.getString(R.string.uid_scanner_setting_failed))
}
} catch (e: Exception) {
snackBarHost.showSnackbar(
context.getString(
R.string.uid_scanner_setting_error,
e.message ?: ""
)
)
}
}
}
)
// 多用户应用扫描开关 - 仅在启用用户态扫描时显示
AnimatedVisibility(
visible = uidAutoScanEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
SwitchItem(
icon = Icons.Filled.Groups,
title = stringResource(R.string.uid_multi_user_scan_title),
summary = stringResource(R.string.uid_multi_user_scan_summary),
checked = uidMultiUserScanEnabled,
onCheckedChange = { enabled ->
scope.launch {
try {
if (setUidMultiUserScan(enabled)) {
uidMultiUserScanEnabled = enabled
prefs.edit { putBoolean("uid_multi_user_scan", enabled) }
} else {
snackBarHost.showSnackbar(context.getString(R.string.uid_scanner_setting_failed))
}
} catch (e: Exception) {
snackBarHost.showSnackbar(
context.getString(
R.string.uid_scanner_setting_error,
e.message ?: ""
)
)
}
}
}
)
}
// 清理运行环境
AnimatedVisibility(
visible = uidAutoScanEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val confirmDialog = rememberConfirmDialog()
val scope = rememberCoroutineScope()
SettingItem(
icon = Icons.Filled.CleaningServices,
title = stringResource(R.string.clean_runtime_environment),
summary = stringResource(R.string.clean_runtime_environment_summary),
onClick = {
scope.launch {
val result = confirmDialog.awaitConfirm(
title = context.getString(R.string.clean_runtime_environment),
content = context.getString(R.string.clean_runtime_environment_confirm)
)
if (result == ConfirmResult.Confirmed) {
val cleanResult = cleanRuntimeEnvironment()
if (cleanResult) {
uidAutoScanEnabled = false
prefs.edit { putBoolean("uid_auto_scan", false) }
uidMultiUserScanEnabled = false
prefs.edit { putBoolean("uid_multi_user_scan", false) }
Natives.setUidScannerEnabled(false)
snackBarHost.showSnackbar(context.getString(R.string.clean_runtime_environment_success))
} else {
snackBarHost.showSnackbar(context.getString(R.string.clean_runtime_environment_failed))
}
}
}
}
)
}
UidScannerSection(prefs, snackBarHost, scope, context)
}
}
)
@@ -453,7 +335,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
)
}
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
val lkmMode = Natives.isLkmMode
if (lkmMode) {
UninstallItem(navigator) {
loadingDialog.withLoading(it)
@@ -481,24 +363,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
fun cleanRuntimeEnvironment(): Boolean {
val shell = getRootShell()
return try {
try {
ShellUtils.fastCmd(shell, "/data/adb/uid_scanner stop")
} catch (_: Exception) {
}
ShellUtils.fastCmdResult(shell, "rm -rf /data/misc/user_uid")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/uid_scanner")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/ksu/bin/user_uid")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/service.d/uid_scanner.sh")
Natives.clearUidScannerEnvironment()
true
} catch (_: Exception) {
false
}
}
@Composable
private fun SettingsGroupCard(
title: String,
@@ -961,3 +825,124 @@ private fun TopBar(
scrollBehavior = scrollBehavior
)
}
@Composable
private fun UidScannerSection(
prefs: SharedPreferences,
snackBarHost: SnackbarHostState,
scope: CoroutineScope,
context: Context
) {
if (Natives.version < Natives.MINIMAL_SUPPORTED_UID_SCANNER) return
val realAuto = Natives.isUidScannerEnabled()
val realMulti = getUidMultiUserScan()
var autoOn by remember { mutableStateOf(realAuto) }
var multiOn by remember { mutableStateOf(realMulti) }
LaunchedEffect(Unit) {
autoOn = realAuto
multiOn = realMulti
prefs.edit {
putBoolean("uid_auto_scan", autoOn)
putBoolean("uid_multi_user_scan", multiOn)
}
}
SwitchItem(
icon = Icons.Filled.Scanner,
title = stringResource(R.string.uid_auto_scan_title),
summary = stringResource(R.string.uid_auto_scan_summary),
checked = autoOn,
onCheckedChange = { target ->
autoOn = target
if (!target) multiOn = false
scope.launch(Dispatchers.IO) {
setUidAutoScan(target)
val actual = Natives.isUidScannerEnabled() || readUidScannerFile()
withContext(Dispatchers.Main) {
autoOn = actual
if (!actual) multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", actual)
putBoolean("uid_multi_user_scan", multiOn)
}
if (actual != target) {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
SwitchItem(
icon = Icons.Filled.Groups,
title = stringResource(R.string.uid_multi_user_scan_title),
summary = stringResource(R.string.uid_multi_user_scan_summary),
checked = multiOn,
onCheckedChange = { target ->
scope.launch(Dispatchers.IO) {
val ok = setUidMultiUserScan(target)
withContext(Dispatchers.Main) {
if (ok) {
multiOn = target
prefs.edit { putBoolean("uid_multi_user_scan", target) }
} else {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
}
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val confirmDialog = rememberConfirmDialog()
SettingItem(
icon = Icons.Filled.CleaningServices,
title = stringResource(R.string.clean_runtime_environment),
summary = stringResource(R.string.clean_runtime_environment_summary),
onClick = {
scope.launch {
if (confirmDialog.awaitConfirm(
title = context.getString(R.string.clean_runtime_environment),
content = context.getString(R.string.clean_runtime_environment_confirm)
) == ConfirmResult.Confirmed
) {
if (cleanRuntimeEnvironment()) {
autoOn = false
multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", false)
putBoolean("uid_multi_user_scan", false)
}
Natives.setUidScannerEnabled(false)
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_success)
)
} else {
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_failed)
)
}
}
}
}
)
}
}

View File

@@ -21,6 +21,7 @@ import com.sukisu.ultra.Natives
import com.sukisu.ultra.ksuApp
import org.json.JSONArray
import java.io.File
import java.util.concurrent.CountDownLatch
/**
@@ -34,7 +35,7 @@ private fun getKsuDaemonPath(): String {
}
object KsuCli {
val SHELL: Shell = createRootShell()
var SHELL: Shell = createRootShell()
val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
}
@@ -578,11 +579,10 @@ fun getUidScannerDaemonPath(): String {
return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libuid_scanner.so"
}
private const val targetPath = "/data/adb/uid_scanner"
fun ensureUidScannerExecutable(): Boolean {
val shell = getRootShell()
val uidScannerPath = getUidScannerDaemonPath()
val targetPath = "/data/adb/uid_scanner"
if (!ShellUtils.fastCmdResult(shell, "test -f $targetPath")) {
val copyResult = ShellUtils.fastCmdResult(shell, "cp $uidScannerPath $targetPath")
if (!copyResult) {
@@ -593,7 +593,6 @@ fun ensureUidScannerExecutable(): Boolean {
val result = ShellUtils.fastCmdResult(shell, "chmod 755 $targetPath")
return result
}
private const val targetPath = "/data/adb/uid_scanner"
fun setUidAutoScan(enabled: Boolean): Boolean {
val shell = getRootShell()
@@ -634,3 +633,30 @@ fun getUidMultiUserScan(): Boolean {
false
}
}
fun cleanRuntimeEnvironment(): Boolean {
val shell = getRootShell()
return try {
try {
ShellUtils.fastCmd(shell, "/data/adb/uid_scanner stop")
} catch (_: Exception) {
}
ShellUtils.fastCmdResult(shell, "rm -rf /data/misc/user_uid")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/uid_scanner")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/ksu/bin/user_uid")
ShellUtils.fastCmdResult(shell, "rm -rf /data/adb/service.d/uid_scanner.sh")
Natives.clearUidScannerEnvironment()
true
} catch (_: Exception) {
false
}
}
fun readUidScannerFile(): Boolean {
val shell = getRootShell()
return try {
ShellUtils.fastCmd(shell, "cat /data/adb/ksu/.uid_scanner").trim() == "1"
} catch (_: Exception) {
false
}
}

View File

@@ -121,18 +121,12 @@ class HomeViewModel : ViewModel() {
try {
val kernelVersion = getKernelVersion()
val isManager = try {
Natives.becomeManager(ksuApp.packageName ?: "com.sukisu.ultra")
Natives.isManager
} catch (_: Exception) {
false
}
val ksuVersion = if (isManager) {
try {
Natives.version
} catch (_: Exception) {
null
}
} else null
val ksuVersion = if (isManager) Natives.version else null
val fullVersion = try {
Natives.getFullVersion()
@@ -163,13 +157,7 @@ class HomeViewModel : ViewModel() {
}
val lkmMode = ksuVersion?.let {
try {
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) {
Natives.isLkmMode
} else null
} catch (_: Exception) {
null
}
if (kernelVersion.isGKI()) Natives.isLkmMode else null
}
val isRootAvailable = try {
@@ -346,7 +334,7 @@ class HomeViewModel : ViewModel() {
try {
// 检查KSU状态是否发生变化
val currentKsuVersion = try {
if (Natives.becomeManager(ksuApp.packageName ?: "com.sukisu.ultra")) {
if (Natives.isManager) {
Natives.version
} else null
} catch (_: Exception) {

View File

@@ -17,7 +17,7 @@ class KsuLibSuProvider : IProvider {
override fun isAvailable() = true
override suspend fun isAuthorized() = Natives.becomeManager(ksuApp.packageName)
override suspend fun isAuthorized() = Natives.isManager
private val serviceIntent
get() = PlatformIntent(

View File

@@ -1,10 +1,133 @@
const EVENT_POST_FS_DATA: u64 = 1;
const EVENT_BOOT_COMPLETED: u64 = 2;
const EVENT_MODULE_MOUNTED: u64 = 3;
use std::fs;
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::os::fd::RawFd;
use std::sync::OnceLock;
// Event constants
const EVENT_POST_FS_DATA: u32 = 1;
const EVENT_BOOT_COMPLETED: u32 = 2;
const EVENT_MODULE_MOUNTED: u32 = 3;
const KSU_IOCTL_GRANT_ROOT: u32 = 0x4B01; // _IO('K', 1)
const KSU_IOCTL_GET_INFO: u32 = 0x80084b02; // _IOR('K', 2, struct ksu_get_info_cmd)
const KSU_IOCTL_REPORT_EVENT: u32 = 0x40044b03; // _IOW('K', 3, struct ksu_report_event_cmd)
const KSU_IOCTL_SET_SEPOLICY: u32 = 0xc0104b04; // _IOWR('K', 4, struct ksu_set_sepolicy_cmd)
const KSU_IOCTL_CHECK_SAFEMODE: u32 = 0x80014b05; // _IOR('K', 5, struct ksu_check_safemode_cmd)
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct GetInfoCmd {
version: u32,
flags: u32,
}
#[repr(C)]
struct ReportEventCmd {
event: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct SetSepolicyCmd {
pub cmd: u64,
pub arg: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct CheckSafemodeCmd {
in_safe_mode: u8,
}
// Global driver fd cache
#[cfg(any(target_os = "linux", target_os = "android"))]
static DRIVER_FD: OnceLock<RawFd> = OnceLock::new();
#[cfg(any(target_os = "linux", target_os = "android"))]
static INFO_CACHE: OnceLock<GetInfoCmd> = OnceLock::new();
const KSU_INSTALL_MAGIC1: u32 = 0xDEADBEEF;
const KSU_INSTALL_MAGIC2: u32 = 0xCAFEBABE;
#[cfg(any(target_os = "linux", target_os = "android"))]
fn scan_driver_fd() -> Option<RawFd> {
let fd_dir = fs::read_dir("/proc/self/fd").ok()?;
for entry in fd_dir.flatten() {
if let Ok(fd_num) = entry.file_name().to_string_lossy().parse::<i32>() {
let link_path = format!("/proc/self/fd/{}", fd_num);
if let Ok(target) = fs::read_link(&link_path) {
let target_str = target.to_string_lossy();
if target_str.contains("[ksu_driver]") {
return Some(fd_num);
}
}
}
}
None
}
// Get cached driver fd
#[cfg(any(target_os = "linux", target_os = "android"))]
fn init_driver_fd() -> Option<RawFd> {
let fd = scan_driver_fd();
if fd.is_none() {
let mut fd = -1;
unsafe {
libc::syscall(
libc::SYS_reboot,
KSU_INSTALL_MAGIC1,
KSU_INSTALL_MAGIC2,
0,
&mut fd,
);
};
if fd >= 0 { Some(fd) } else { None }
} else {
fd
}
}
// ioctl wrapper using libc
#[cfg(any(target_os = "linux", target_os = "android"))]
fn ksuctl<T>(request: u32, arg: *mut T) -> std::io::Result<i32> {
use std::io;
let fd = *DRIVER_FD.get_or_init(|| init_driver_fd().unwrap_or(-1));
unsafe {
#[cfg(not(target_env = "gnu"))]
let ret = libc::ioctl(fd as libc::c_int, request as i32, arg);
#[cfg(target_env = "gnu")]
let ret = libc::ioctl(fd as libc::c_int, request as u64, arg);
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(ret)
}
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn ksuctl<T>(_request: u32, _arg: *mut T) -> std::io::Result<i32> {
Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
}
// API implementations
#[cfg(any(target_os = "linux", target_os = "android"))]
fn get_info() -> GetInfoCmd {
*INFO_CACHE.get_or_init(|| {
let mut cmd = GetInfoCmd {
version: 0,
flags: 0,
};
let _ = ksuctl(KSU_IOCTL_GET_INFO, &mut cmd as *mut _);
cmd
})
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn get_version() -> i32 {
rustix::process::ksu_get_version()
get_info().version as i32
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
@@ -13,22 +136,24 @@ pub fn get_version() -> i32 {
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn report_event(event: u64) {
rustix::process::ksu_report_event(event)
pub fn grant_root() -> std::io::Result<()> {
ksuctl(KSU_IOCTL_GRANT_ROOT, std::ptr::null_mut::<u8>())?;
Ok(())
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn report_event(_event: u64) {}
pub fn grant_root() -> std::io::Result<()> {
Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn check_kernel_safemode() -> bool {
rustix::process::ksu_check_kernel_safemode()
fn report_event(event: u32) {
let mut cmd = ReportEventCmd { event };
let _ = ksuctl(KSU_IOCTL_REPORT_EVENT, &mut cmd as *mut _);
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub fn check_kernel_safemode() -> bool {
false
}
fn report_event(_event: u32) {}
pub fn report_post_fs_data() {
report_event(EVENT_POST_FS_DATA);
@@ -41,3 +166,21 @@ pub fn report_boot_complete() {
pub fn report_module_mounted() {
report_event(EVENT_MODULE_MOUNTED);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn check_kernel_safemode() -> bool {
let mut cmd = CheckSafemodeCmd { in_safe_mode: 0 };
let _ = ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &mut cmd as *mut _);
cmd.in_safe_mode != 0
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub fn check_kernel_safemode() -> bool {
false
}
pub fn set_sepolicy(cmd: &SetSepolicyCmd) -> std::io::Result<()> {
let mut ioctl_cmd = *cmd;
ksuctl(KSU_IOCTL_SET_SEPOLICY, &mut ioctl_cmd as *mut _)?;
Ok(())
}

View File

@@ -20,7 +20,7 @@ fn parse_single_word(input: &str) -> IResult<&str, &str> {
take_while1(is_sepolicy_char).parse(input)
}
fn parse_bracket_objs<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
fn parse_bracket_objs(input: &str) -> IResult<&str, SeObject<'_>> {
let (input, (_, words, _)) = (
tag("{"),
take_while_m_n(1, 100, |c: char| is_sepolicy_char(c) || c.is_whitespace()),
@@ -30,12 +30,12 @@ fn parse_bracket_objs<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
Ok((input, words.split_whitespace().collect()))
}
fn parse_single_obj<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
fn parse_single_obj(input: &str) -> IResult<&str, SeObject<'_>> {
let (input, word) = take_while1(is_sepolicy_char).parse(input)?;
Ok((input, vec![word]))
}
fn parse_star<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
fn parse_star(input: &str) -> IResult<&str, SeObject<'_>> {
let (input, _) = tag("*").parse(input)?;
Ok((input, vec!["*"]))
}
@@ -43,12 +43,12 @@ fn parse_star<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
// 1. a single sepolicy word
// 2. { obj1 obj2 obj3 ...}
// 3. *
fn parse_seobj<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
fn parse_seobj(input: &str) -> IResult<&str, SeObject<'_>> {
let (input, strs) = alt((parse_single_obj, parse_bracket_objs, parse_star)).parse(input)?;
Ok((input, strs))
}
fn parse_seobj_no_star<'a>(input: &'a str) -> IResult<&'a str, SeObject<'a>> {
fn parse_seobj_no_star(input: &str) -> IResult<&str, SeObject<'_>> {
let (input, strs) = alt((parse_single_obj, parse_bracket_objs)).parse(input)?;
Ok((input, strs))
}
@@ -697,7 +697,12 @@ fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>, strict: bool) -> Resul
let policies: Vec<AtomicStatement> = statement.try_into()?;
for policy in policies {
if !rustix::process::ksu_set_policy(&FfiPolicy::from(policy)) {
let ffi_policy = FfiPolicy::from(policy);
let cmd = crate::ksucalls::SetSepolicyCmd {
cmd: 0,
arg: &ffi_policy as *const _ as u64,
};
if crate::ksucalls::set_sepolicy(&cmd).is_err() {
log::warn!("apply rule: {statement:?} failed.");
if strict {
return Err(anyhow::anyhow!("apply rule {:?} failed.", statement));

View File

@@ -17,7 +17,7 @@ use crate::{
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn grant_root(global_mnt: bool) -> Result<()> {
rustix::process::ksu_grant_root()?;
crate::ksucalls::grant_root()?;
let mut command = Command::new("sh");
let command = unsafe {