kernel: Add the ability to manually elevate privileges for programs using prctl by specifying UID or PID.

This commit is contained in:
ShirkNeko
2025-09-28 19:33:08 +08:00
parent 3f0f34e5b1
commit 7c4334e03a
5 changed files with 172 additions and 0 deletions

View File

@@ -21,6 +21,7 @@
#include <linux/version.h>
#include <linux/mount.h>
#include <linux/binfmts.h>
#include <linux/tty.h>
#include <linux/fs.h>
#include <linux/namei.h>
@@ -52,6 +53,7 @@
#include "throne_comm.h"
#include "kernel_compat.h"
#include "dynamic_manager.h"
#include "manual_su.h"
#ifdef CONFIG_KPM
#include "kpm/kpm.h"
@@ -283,6 +285,86 @@ void escape_to_root(void)
setup_selinux(profile->selinux_domain);
}
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
{
struct cred *newcreds;
struct task_struct *target_task;
pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid);
// Find target task by PID
rcu_read_lock();
target_task = pid_task(find_vpid(target_pid), PIDTYPE_PID);
if (!target_task) {
rcu_read_unlock();
pr_err("cmd_su: target task not found for PID: %d\n", target_pid);
return;
}
get_task_struct(target_task);
rcu_read_unlock();
if (task_uid(target_task).val == 0) {
pr_warn("cmd_su: target task is already root, PID: %d\n", target_pid);
put_task_struct(target_task);
return;
}
newcreds = prepare_kernel_cred(target_task);
if (newcreds == NULL) {
pr_err("cmd_su: failed to allocate new cred for PID: %d\n", target_pid);
put_task_struct(target_task);
return;
}
struct root_profile *profile = ksu_get_root_profile(target_uid);
newcreds->uid.val = profile->uid;
newcreds->suid.val = profile->uid;
newcreds->euid.val = profile->uid;
newcreds->fsuid.val = profile->uid;
newcreds->gid.val = profile->gid;
newcreds->fsgid.val = profile->gid;
newcreds->sgid.val = profile->gid;
newcreds->egid.val = profile->gid;
newcreds->securebits = 0;
u64 cap_for_cmd_su = profile->capabilities.effective | CAP_DAC_READ_SEARCH | CAP_SETUID | CAP_SETGID;
memcpy(&newcreds->cap_effective, &cap_for_cmd_su, sizeof(newcreds->cap_effective));
memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, sizeof(newcreds->cap_permitted));
memcpy(&newcreds->cap_bset, &profile->capabilities.effective, sizeof(newcreds->cap_bset));
setup_groups(profile, newcreds);
task_lock(target_task);
const struct cred *old_creds = get_task_cred(target_task);
rcu_assign_pointer(target_task->real_cred, newcreds);
rcu_assign_pointer(target_task->cred, get_cred(newcreds));
task_unlock(target_task);
if (target_task->sighand) {
spin_lock_irq(&target_task->sighand->siglock);
disable_seccomp(target_task);
spin_unlock_irq(&target_task->sighand->siglock);
}
setup_selinux(profile->selinux_domain);
put_cred(old_creds);
wake_up_process(target_task);
if (target_task->signal->tty) {
struct inode *inode = target_task->signal->tty->driver_data;
if (inode && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) {
__ksu_handle_devpts(inode);
}
}
put_task_struct(target_task);
pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid);
}
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
{
if (!current->mm) {
@@ -363,6 +445,11 @@ static bool is_system_bin_su()
return (current->mm->exe_file && !strcmp(current->mm->exe_file->f_path.dentry->d_name.name, "su"));
}
int handle_cmd_su_escalation(uid_t uid, pid_t pid, const char __user *pwd)
{
return ksu_manual_su_escalate(uid, pid, pwd);
}
static void init_uid_scanner(void)
{
ksu_uid_init();
@@ -398,6 +485,21 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
bool from_root = 0 == current_uid().val;
bool from_manager = is_manager();
if (arg2 == CMD_SU_ESCALATION_REQUEST) {
uid_t target_uid = (uid_t)arg3;
pid_t target_pid = (pid_t)arg4;
const char __user *user_password = (const char __user *)arg5;
int ret = handle_cmd_su_escalation(target_uid, target_pid, user_password);
if (ret == 0) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("cmd_su_escalation: prctl reply error\n");
}
}
return 0;
}
if (!from_root && !from_manager
&& !(is_allow_su() && is_system_bin_su())) {
// only root or manager can access this interface