From 0ce7bc2627d8c5552c2e7856a1996eed3b1e95db Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Thu, 6 Nov 2025 02:52:14 +0800 Subject: [PATCH] kernel: Migrate manual_su to ioctl --- kernel/Makefile | 1 - kernel/core_hook.c | 6 -- kernel/ksu_netlink.c | 203 ----------------------------------------- kernel/ksu_netlink.h | 49 ---------- kernel/selinux/rules.c | 4 - kernel/supercalls.c | 48 +++++++++- kernel/supercalls.h | 12 +++ 7 files changed, 59 insertions(+), 264 deletions(-) delete mode 100644 kernel/ksu_netlink.c delete mode 100644 kernel/ksu_netlink.h diff --git a/kernel/Makefile b/kernel/Makefile index b6a023fd..9bfe133e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -13,7 +13,6 @@ kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o -kernelsu-objs += ksu_netlink.o ifeq ($(CONFIG_KSU_MANUAL_SU), y) ccflags-y += -DCONFIG_KSU_MANUAL_SU diff --git a/kernel/core_hook.c b/kernel/core_hook.c index 0f0f2ab7..c11bdc8b 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -790,9 +790,6 @@ void __init ksu_core_init(void) if (ksu_register_feature_handler(&kernel_umount_handler)) { pr_err("Failed to register umount feature handler\n"); } -#ifdef CONFIG_KSU_MANUAL_SU - ksu_netlink_init(); -#endif } void ksu_core_exit(void) @@ -807,7 +804,4 @@ void ksu_core_exit(void) ksu_kprobe_exit(); #endif ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT); -#ifdef CONFIG_KSU_MANUAL_SU - ksu_netlink_exit(); -#endif } diff --git a/kernel/ksu_netlink.c b/kernel/ksu_netlink.c deleted file mode 100644 index 45085a9e..00000000 --- a/kernel/ksu_netlink.c +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include "kernel_compat.h" -#include "ksu_netlink.h" -#include "manual_su.h" -#include "ksu.h" - -static struct sock *ksu_nl_sock = NULL; - -static bool manager_only(uid_t uid) -{ - return is_manager(); -} - -static bool manager_or_allowed(uid_t uid) -{ - return is_manager() || ksu_is_allow_uid(uid); -} - -static bool always_allow(uid_t uid) -{ - return true; -} - -static bool system_uid(uid_t uid) -{ - return uid <= 2000; -} - -#ifdef CONFIG_KSU_MANUAL_SU -// Manual SU -static int handle_manual_su(struct sk_buff *skb, struct nlmsghdr *nlh, void *msg_data) -{ - struct netlink_manual_su *msg = (struct netlink_manual_su *)msg_data; - struct manual_su_request request; - int res; - - pr_info("ksu_netlink: manual_su request, option=%d, uid=%d, pid=%d\n", - msg->option, msg->target_uid, msg->target_pid); - - memset(&request, 0, sizeof(request)); - request.target_uid = msg->target_uid; - request.target_pid = msg->target_pid; - - if (msg->option == MANUAL_SU_OP_GENERATE_TOKEN || - msg->option == MANUAL_SU_OP_ESCALATE) { - memcpy(request.token_buffer, msg->token_buffer, sizeof(request.token_buffer)); - } - - res = ksu_handle_manual_su_request(msg->option, &request); - - msg->hdr.result = res; - if (msg->option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) { - memcpy(msg->token_buffer, request.token_buffer, sizeof(msg->token_buffer)); - } - - return 0; -} -#endif - -// Command handlers mapping table -static const struct ksu_netlink_cmd_handler ksu_netlink_handlers[] = { -#ifdef CONFIG_KSU_MANUAL_SU - { - .cmd = KSU_NETLINK_CMD_MANUAL_SU, - .msg_size = sizeof(struct netlink_manual_su), - .name = "MANUAL_SU", - .handler = handle_manual_su, - .perm_check = system_uid - }, -#endif - { .cmd = 0, .msg_size = NULL, .name = NULL, .handler = NULL, .perm_check = NULL } -}; - -static void ksu_netlink_recv_msg(struct sk_buff *skb) -{ - struct nlmsghdr *nlh; - struct ksu_netlink_hdr *hdr; - struct sk_buff *skb_out; - const struct ksu_netlink_cmd_handler *handler_entry = NULL; - void *msg_data; - int res; - u32 pid; - uid_t sender_uid; - int i; - - if (!skb) { - pr_err("ksu_netlink: received NULL skb\n"); - return; - } - - nlh = (struct nlmsghdr *)skb->data; - pid = nlh->nlmsg_pid; - sender_uid = NETLINK_CB(skb).creds.uid.val; - - if (!nlh || nlh->nlmsg_len < NLMSG_HDRLEN + sizeof(struct ksu_netlink_hdr)) { - pr_err("ksu_netlink: invalid message size\n"); - return; - } - - hdr = (struct ksu_netlink_hdr *)nlmsg_data(nlh); - - // Find command handler - for (i = 0; ksu_netlink_handlers[i].handler; i++) { - if (hdr->cmd == ksu_netlink_handlers[i].cmd) { - handler_entry = &ksu_netlink_handlers[i]; - break; - } - } - - if (!handler_entry) { - pr_warn("ksu_netlink: unknown command %d\n", hdr->cmd); - return; - } - - // Validate message size - if (nlh->nlmsg_len < NLMSG_HDRLEN + handler_entry->msg_size) { - pr_err("ksu_netlink: invalid message size for cmd %s\n", handler_entry->name); - return; - } - - // Permission check - if (handler_entry->perm_check && !handler_entry->perm_check(sender_uid)) { - pr_warn("ksu_netlink: permission denied for cmd %s from uid %d\n", - handler_entry->name, sender_uid); - hdr->result = -EPERM; - goto send_reply; - } - - // Allocate response buffer (reuse input data for response) - msg_data = kmalloc(handler_entry->msg_size, GFP_KERNEL); - if (!msg_data) { - pr_err("ksu_netlink: failed to allocate message buffer\n"); - return; - } - memcpy(msg_data, hdr, handler_entry->msg_size); - - // Execute handler - res = handler_entry->handler(skb, nlh, msg_data); - if (res < 0) { - pr_err("ksu_netlink: handler for cmd %s failed: %d\n", handler_entry->name, res); - kfree(msg_data); - return; - } - -send_reply: - // Send reply - skb_out = nlmsg_new(handler_entry->msg_size, GFP_KERNEL); - if (!skb_out) { - pr_err("ksu_netlink: failed to allocate reply skb\n"); - if (msg_data) - kfree(msg_data); - return; - } - - nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, handler_entry->msg_size, 0); - if (!nlh) { - pr_err("ksu_netlink: nlmsg_put failed\n"); - kfree_skb(skb_out); - if (msg_data) - kfree(msg_data); - return; - } - - NETLINK_CB(skb_out).dst_group = 0; - memcpy(nlmsg_data(nlh), msg_data ? msg_data : hdr, handler_entry->msg_size); - - if (msg_data) - kfree(msg_data); - - res = nlmsg_unicast(ksu_nl_sock, skb_out, pid); - if (res < 0) { - pr_err("ksu_netlink: failed to send reply: %d\n", res); - } else { - pr_info("ksu_netlink: reply sent for cmd %s\n", handler_entry->name); - } -} - -int ksu_netlink_init(void) -{ - struct netlink_kernel_cfg cfg = { - .input = ksu_netlink_recv_msg, - }; - - ksu_nl_sock = netlink_kernel_create(&init_net, KSU_NETLINK_PROTOCOL, &cfg); - if (!ksu_nl_sock) { - pr_err("ksu_netlink: failed to create netlink socket\n"); - return -ENOMEM; - } - - pr_info("ksu_netlink: initialized with protocol %d\n", KSU_NETLINK_PROTOCOL); - return 0; -} - -void ksu_netlink_exit(void) -{ - if (ksu_nl_sock) { - netlink_kernel_release(ksu_nl_sock); - ksu_nl_sock = NULL; - pr_info("ksu_netlink: released\n"); - } -} diff --git a/kernel/ksu_netlink.h b/kernel/ksu_netlink.h deleted file mode 100644 index 1286a387..00000000 --- a/kernel/ksu_netlink.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __KSU_NETLINK_H -#define __KSU_NETLINK_H - -#include -#include -#include -#include - -#define KSU_NETLINK_PROTOCOL 11 - -#define KSU_NETLINK_CMD_MANUAL_SU 100 - -struct ksu_netlink_hdr { - int cmd; // Command ID - int result; // Result code (output) -}; - -#ifdef CONFIG_KSU_MANUAL_SU -struct netlink_manual_su { - struct ksu_netlink_hdr hdr; - int option; - uid_t target_uid; - pid_t target_pid; - char token_buffer[33]; -}; -#endif - -union ksu_netlink_msg { - struct ksu_netlink_hdr hdr; -#ifdef CONFIG_KSU_MANUAL_SU - struct netlink_manual_su manual_su; -#endif -}; - -typedef int (*ksu_netlink_handler_t)(struct sk_buff *skb, struct nlmsghdr *nlh, void *msg_data); -typedef bool (*ksu_netlink_perm_check_t)(uid_t uid); - -struct ksu_netlink_cmd_handler { - int cmd; - size_t msg_size; - const char *name; - ksu_netlink_handler_t handler; - ksu_netlink_perm_check_t perm_check; -}; - -int ksu_netlink_init(void); -void ksu_netlink_exit(void); - -#endif diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index ff5adec0..c8db9fc3 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -127,10 +127,6 @@ void apply_kernelsu_rules() ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid"); ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill"); -#ifdef CONFIG_KSU_MANUAL_SU - ksu_allow(db, "shell", "shell", "netlink_connector_socket", ALL); -#endif - // https://android-review.googlesource.com/c/platform/system/logging/+/3725346 ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr"); diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 89c5c4ac..9adab23e 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -481,7 +481,7 @@ static int do_enable_uid_scanner(void __user *arg) bool enabled = cmd.enabled; if (enabled == ksu_uid_scanner_enabled) { - pr_info("enable_uid_scanner: no need to change, already %s\n", + pr_info("enable_uid_scanner: no need to change, already %s\n", enabled ? "enabled" : "disabled"); break; } @@ -520,6 +520,49 @@ static int do_enable_uid_scanner(void __user *arg) return 0; } +#ifdef CONFIG_KSU_MANUAL_SU +static bool system_uid_check(void) +{ + return current_uid().val <= 2000; +} + +static int do_manual_su(void __user *arg) +{ + struct ksu_manual_su_cmd cmd; + struct manual_su_request request; + int res; + + if (copy_from_user(&cmd, arg, sizeof(cmd))) { + pr_err("manual_su: copy_from_user failed\n"); + return -EFAULT; + } + + pr_info("manual_su request, option=%d, uid=%d, pid=%d\n", + cmd.option, cmd.target_uid, cmd.target_pid); + + memset(&request, 0, sizeof(request)); + request.target_uid = cmd.target_uid; + request.target_pid = cmd.target_pid; + + if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN || + cmd.option == MANUAL_SU_OP_ESCALATE) { + memcpy(request.token_buffer, cmd.token_buffer, sizeof(request.token_buffer)); + } + + res = ksu_handle_manual_su_request(cmd.option, &request); + + if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) { + memcpy(cmd.token_buffer, request.token_buffer, sizeof(cmd.token_buffer)); + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + pr_err("manual_su: copy_to_user failed\n"); + return -EFAULT; + } + } + + return res; +} +#endif + // IOCTL handlers mapping table static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = { { .cmd = KSU_IOCTL_GRANT_ROOT, .name = "GRANT_ROOT", .handler = do_grant_root, .perm_check = allowed_for_su }, @@ -542,6 +585,9 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = { { .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .name = "SET_DYNAMIC_MANAGER", .handler = do_dynamic_manager, .perm_check = manager_or_root}, { .cmd = KSU_IOCTL_GET_MANAGERS, .name = "GET_MANAGERS", .handler = do_get_managers, .perm_check = manager_or_root}, { .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .name = "SET_ENABLE_UID_SCANNER", .handler = do_enable_uid_scanner, .perm_check = manager_or_root}, +#ifdef CONFIG_KSU_MANUAL_SU + { .cmd = KSU_IOCTL_MANUAL_SU, .name = "MANUAL_SU", .handler = do_manual_su, .perm_check = system_uid_check}, +#endif #ifdef CONFIG_KPM { .cmd = KSU_IOCTL_KPM, .name = "KPM_OPERATION", .handler = do_kpm, .perm_check = manager_or_root}, #endif diff --git a/kernel/supercalls.h b/kernel/supercalls.h index 8fbbfd5e..6e2e887f 100644 --- a/kernel/supercalls.h +++ b/kernel/supercalls.h @@ -104,6 +104,15 @@ struct ksu_enable_uid_scanner_cmd { void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS) }; +#ifdef CONFIG_KSU_MANUAL_SU +struct ksu_manual_su_cmd { + __u32 option; // Input: operation type (MANUAL_SU_OP_GENERATE_TOKEN, MANUAL_SU_OP_ESCALATE, MANUAL_SU_OP_ADD_PENDING) + __u32 target_uid; // Input: target UID + __u32 target_pid; // Input: target PID + char token_buffer[33]; // Input/Output: token buffer +}; +#endif + // IOCTL command definitions #define KSU_IOCTL_GRANT_ROOT _IOC(_IOC_NONE, 'K', 1, 0) #define KSU_IOCTL_GET_INFO _IOC(_IOC_READ, 'K', 2, 0) @@ -126,6 +135,9 @@ struct ksu_enable_uid_scanner_cmd { #define KSU_IOCTL_DYNAMIC_MANAGER _IOC(_IOC_READ|_IOC_WRITE, 'K', 103, 0) #define KSU_IOCTL_GET_MANAGERS _IOC(_IOC_READ|_IOC_WRITE, 'K', 104, 0) #define KSU_IOCTL_ENABLE_UID_SCANNER _IOC(_IOC_READ|_IOC_WRITE, 'K', 105, 0) +#ifdef CONFIG_KSU_MANUAL_SU +#define KSU_IOCTL_MANUAL_SU _IOC(_IOC_READ|_IOC_WRITE, 'K', 106, 0) +#endif // IOCTL handler types typedef int (*ksu_ioctl_handler_t)(void __user *arg);