Kernel: Enable processes with corresponding UIDs to utilise netlink, and optimise netlink functionality
This commit is contained in:
@@ -1,26 +1,90 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/slab.h>
|
||||
#include "kernel_compat.h"
|
||||
#include "ksu_netlink.h"
|
||||
#include "manual_su.h"
|
||||
#include "ksu.h"
|
||||
|
||||
static struct sock *ksu_nl_sock = NULL;
|
||||
|
||||
extern int ksu_handle_manual_su_request(int option, struct manual_su_request *request);
|
||||
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)
|
||||
{
|
||||
if (!current->mm || current->in_execve) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uid_t caller_uid = current_uid().val;
|
||||
return caller_uid <= 2000;
|
||||
}
|
||||
|
||||
// Manual SU
|
||||
static int handle_manual_su(struct sk_buff *skb, struct nlmsghdr *nlh, void *msg_data)
|
||||
{
|
||||
struct ksu_netlink_manual_su *msg = (struct ksu_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;
|
||||
}
|
||||
|
||||
// Command handlers mapping table
|
||||
static const struct ksu_netlink_cmd_handler ksu_netlink_handlers[] = {
|
||||
{
|
||||
.cmd = KSU_NETLINK_CMD_MANUAL_SU,
|
||||
.msg_size = sizeof(struct ksu_netlink_manual_su),
|
||||
.name = "MANUAL_SU",
|
||||
.handler = handle_manual_su,
|
||||
.perm_check = system_uid
|
||||
},
|
||||
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL }
|
||||
};
|
||||
|
||||
static void ksu_netlink_recv_msg(struct sk_buff *skb)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct ksu_netlink_msg *msg;
|
||||
struct ksu_netlink_msg reply;
|
||||
struct ksu_netlink_hdr *hdr;
|
||||
struct sk_buff *skb_out;
|
||||
int msg_size;
|
||||
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");
|
||||
@@ -29,67 +93,88 @@ static void ksu_netlink_recv_msg(struct sk_buff *skb)
|
||||
|
||||
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_msg)) {
|
||||
if (!nlh || nlh->nlmsg_len < NLMSG_HDRLEN + sizeof(struct ksu_netlink_hdr)) {
|
||||
pr_err("ksu_netlink: invalid message size\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msg = (struct ksu_netlink_msg *)nlmsg_data(nlh);
|
||||
hdr = (struct ksu_netlink_hdr *)nlmsg_data(nlh);
|
||||
|
||||
if (msg->cmd != KSU_NETLINK_CMD_MANUAL_SU) {
|
||||
pr_warn("ksu_netlink: unknown command %d\n", msg->cmd);
|
||||
// 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;
|
||||
}
|
||||
|
||||
pr_info("ksu_netlink: received manual_su request, option=%d, uid=%d, pid=%d\n",
|
||||
msg->option, msg->target_uid, msg->target_pid);
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.cmd = msg->cmd;
|
||||
reply.option = msg->option;
|
||||
reply.target_uid = msg->target_uid;
|
||||
reply.target_pid = msg->target_pid;
|
||||
|
||||
struct manual_su_request request = {
|
||||
.target_uid = msg->target_uid,
|
||||
.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, KSU_TOKEN_LENGTH + 1);
|
||||
// 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;
|
||||
}
|
||||
|
||||
res = ksu_handle_manual_su_request(msg->option, &request);
|
||||
|
||||
reply.result = res;
|
||||
if (msg->option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) {
|
||||
memcpy(reply.token_buffer, request.token_buffer, KSU_TOKEN_LENGTH + 1);
|
||||
// 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;
|
||||
}
|
||||
|
||||
msg_size = sizeof(struct ksu_netlink_msg);
|
||||
skb_out = nlmsg_new(msg_size, GFP_KERNEL);
|
||||
// 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, msg_size, 0);
|
||||
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), &reply, sizeof(reply));
|
||||
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 successfully\n");
|
||||
pr_info("ksu_netlink: reply sent for cmd %s\n", handler_entry->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,39 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#define KSU_NETLINK_PROTOCOL 2
|
||||
#define KSU_NETLINK_CMD_MANUAL_SU 50
|
||||
#define KSU_NETLINK_PROTOCOL 11
|
||||
|
||||
struct ksu_netlink_msg {
|
||||
int cmd;
|
||||
#define KSU_NETLINK_CMD_MANUAL_SU 100
|
||||
|
||||
struct ksu_netlink_hdr {
|
||||
int cmd; // Command ID
|
||||
int result; // Result code (output)
|
||||
};
|
||||
|
||||
struct ksu_netlink_manual_su {
|
||||
struct ksu_netlink_hdr hdr;
|
||||
int option;
|
||||
uid_t target_uid;
|
||||
pid_t target_pid;
|
||||
char token_buffer[33];
|
||||
int result;
|
||||
};
|
||||
|
||||
union ksu_netlink_msg {
|
||||
struct ksu_netlink_hdr hdr;
|
||||
struct ksu_netlink_manual_su manual_su;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@@ -127,6 +127,8 @@ void apply_kernelsu_rules()
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||
|
||||
ksu_allow(db, "shell", "shell", "netlink_connector_socket", ALL);
|
||||
|
||||
// https://android-review.googlesource.com/c/platform/system/logging/+/3725346
|
||||
ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user