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 aa2cbbf.

* 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-02 01:11:38 +08:00
parent d7b55bf8b1
commit afc8b53ca6
32 changed files with 5762 additions and 5244 deletions

View File

@@ -4,6 +4,7 @@
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/version.h>
#include "ksu.h"
#include "klog.h"
#include "throne_comm.h"
@@ -18,198 +19,196 @@ 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;
static void rescan_work_fn(struct work_struct *work)
{
// Signal userspace through proc interface
need_rescan = true;
pr_info("requested userspace uid rescan\n");
// Signal userspace through proc interface
need_rescan = true;
pr_info("requested userspace uid rescan\n");
}
void ksu_request_userspace_scan(void)
{
if (scanner_wq) {
queue_work(scanner_wq, &scan_work);
}
if (scanner_wq) {
queue_work(scanner_wq, &scan_work);
}
}
void ksu_handle_userspace_update(void)
{
// Called when userspace notifies update complete
need_rescan = false;
pr_info("userspace uid list updated\n");
// Called when userspace notifies update complete
need_rescan = false;
pr_info("userspace uid list updated\n");
}
static void do_save_throne_state(struct work_struct *work)
{
struct file *fp;
char state_char = ksu_uid_scanner_enabled ? '1' : '0';
loff_t off = 0;
struct file *fp;
char state_char = ksu_uid_scanner_enabled ? '1' : '0';
loff_t off = 0;
fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (IS_ERR(fp)) {
pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp));
return;
}
fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (IS_ERR(fp)) {
pr_err("save_throne_state create file failed: %ld\n", PTR_ERR(fp));
return;
}
if (ksu_kernel_write_compat(fp, &state_char, sizeof(state_char), &off) != sizeof(state_char)) {
pr_err("save_throne_state write failed\n");
goto exit;
}
if (ksu_kernel_write_compat(fp, &state_char, sizeof(state_char), &off) != sizeof(state_char)) {
pr_err("save_throne_state write failed\n");
goto exit;
}
pr_info("throne state saved: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled");
pr_info("throne state saved: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled");
exit:
filp_close(fp, 0);
filp_close(fp, 0);
}
void do_load_throne_state(struct work_struct *work)
{
struct file *fp;
char state_char;
loff_t off = 0;
ssize_t ret;
struct file *fp;
char state_char;
loff_t off = 0;
ssize_t ret;
fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_info("throne state file not found, using default: disabled\n");
ksu_uid_scanner_enabled = false;
return;
}
fp = ksu_filp_open_compat(UID_SCANNER_STATE_FILE, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_info("throne state file not found, using default: disabled\n");
ksu_uid_scanner_enabled = false;
return;
}
ret = ksu_kernel_read_compat(fp, &state_char, sizeof(state_char), &off);
if (ret != sizeof(state_char)) {
pr_err("load_throne_state read err: %zd\n", ret);
ksu_uid_scanner_enabled = false;
goto exit;
}
ret = ksu_kernel_read_compat(fp, &state_char, sizeof(state_char), &off);
if (ret != sizeof(state_char)) {
pr_err("load_throne_state read err: %zd\n", ret);
ksu_uid_scanner_enabled = false;
goto exit;
}
ksu_uid_scanner_enabled = (state_char == '1');
pr_info("throne state loaded: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled");
ksu_uid_scanner_enabled = (state_char == '1');
pr_info("throne state loaded: %s\n", ksu_uid_scanner_enabled ? "enabled" : "disabled");
exit:
filp_close(fp, 0);
filp_close(fp, 0);
}
bool ksu_throne_comm_load_state(void)
{
return ksu_queue_work(&ksu_state_load_work);
return ksu_queue_work(&ksu_state_load_work);
}
void ksu_throne_comm_save_state(void)
{
ksu_queue_work(&ksu_state_save_work);
ksu_queue_work(&ksu_state_save_work);
}
static int uid_scanner_show(struct seq_file *m, void *v)
{
if (need_rescan) {
seq_puts(m, "RESCAN\n");
} else {
seq_puts(m, "OK\n");
}
return 0;
if (need_rescan) {
seq_puts(m, "RESCAN\n");
} else {
seq_puts(m, "OK\n");
}
return 0;
}
static int uid_scanner_open(struct inode *inode, struct file *file)
{
return single_open(file, uid_scanner_show, NULL);
return single_open(file, uid_scanner_show, NULL);
}
static ssize_t uid_scanner_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
char cmd[16];
if (count >= sizeof(cmd))
return -EINVAL;
if (copy_from_user(cmd, buffer, count))
return -EFAULT;
cmd[count] = '\0';
// Remove newline if present
if (count > 0 && cmd[count-1] == '\n')
cmd[count-1] = '\0';
if (strcmp(cmd, "UPDATED") == 0) {
ksu_handle_userspace_update();
pr_info("received userspace update notification\n");
}
return count;
char cmd[16];
if (count >= sizeof(cmd))
return -EINVAL;
if (copy_from_user(cmd, buffer, count))
return -EFAULT;
cmd[count] = '\0';
// Remove newline if present
if (count > 0 && cmd[count-1] == '\n')
cmd[count-1] = '\0';
if (strcmp(cmd, "UPDATED") == 0) {
ksu_handle_userspace_update();
pr_info("received userspace update notification\n");
}
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,
.proc_write = uid_scanner_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
.proc_open = uid_scanner_open,
.proc_read = seq_read,
.proc_write = uid_scanner_write,
.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,
.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)
{
// Create workqueue
scanner_wq = alloc_workqueue("ksu_scanner", WQ_UNBOUND, 1);
if (!scanner_wq) {
pr_err("failed to create scanner workqueue\n");
return -ENOMEM;
}
INIT_WORK(&scan_work, rescan_work_fn);
// Create proc entry
proc_entry = proc_create(PROC_UID_SCANNER, 0600, NULL, &uid_scanner_proc_ops);
if (!proc_entry) {
pr_err("failed to create proc entry\n");
destroy_workqueue(scanner_wq);
return -ENOMEM;
}
pr_info("throne communication initialized\n");
return 0;
// Create workqueue
scanner_wq = alloc_workqueue("ksu_scanner", WQ_UNBOUND, 1);
if (!scanner_wq) {
pr_err("failed to create scanner workqueue\n");
return -ENOMEM;
}
INIT_WORK(&scan_work, rescan_work_fn);
// Create proc entry
proc_entry = proc_create(PROC_UID_SCANNER, 0600, NULL, &uid_scanner_proc_ops);
if (!proc_entry) {
pr_err("failed to create proc entry\n");
destroy_workqueue(scanner_wq);
return -ENOMEM;
}
pr_info("throne communication initialized\n");
return 0;
}
void ksu_throne_comm_exit(void)
{
if (proc_entry) {
proc_remove(proc_entry);
proc_entry = NULL;
}
if (scanner_wq) {
destroy_workqueue(scanner_wq);
scanner_wq = NULL;
}
pr_info("throne communication cleaned up\n");
if (proc_entry) {
proc_remove(proc_entry);
proc_entry = NULL;
}
if (scanner_wq) {
destroy_workqueue(scanner_wq);
scanner_wq = NULL;
}
pr_info("throne communication cleaned up\n");
}
int ksu_uid_init(void)
{
INIT_WORK(&ksu_state_save_work, do_save_throne_state);
INIT_WORK(&ksu_state_load_work, do_load_throne_state);
return 0;
INIT_WORK(&ksu_state_save_work, do_save_throne_state);
INIT_WORK(&ksu_state_load_work, do_load_throne_state);
return 0;
}
void ksu_uid_exit(void)
{
do_save_throne_state(NULL);
do_save_throne_state(NULL);
}