kernel: Use task work to install fd

There are many fd related functions that can sleep, so we have no choice
but move operations to task work. Also close fd when copy_to_user fails.

Co-authored-by: Wang Han <416810799@qq.com>
This commit is contained in:
ShirkNeko
2025-11-11 01:10:36 +08:00
parent fd3a22360a
commit 8f49898155

View File

@@ -4,12 +4,15 @@
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/fdtable.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kprobes.h>
#include <linux/syscalls.h>
#include <linux/task_work.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/kprobes.h>
#include "arch.h" #include "arch.h"
#include "allowlist.h" #include "allowlist.h"
@@ -739,9 +742,35 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine { .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine
}; };
#ifdef KSU_KPROBES_HOOK
struct ksu_install_fd_tw {
struct callback_head cb;
int __user *outp;
};
static void ksu_install_fd_tw_func(struct callback_head *cb)
{
struct ksu_install_fd_tw *tw = container_of(cb, struct ksu_install_fd_tw, cb);
int fd = ksu_install_fd();
pr_info("[%d] install ksu fd: %d\n", current->pid, fd);
if (copy_to_user(tw->outp, &fd, sizeof(fd))) {
pr_err("install ksu fd reply err\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
close_fd(fd);
#else
ksys_close(fd);
#endif
}
kfree(tw);
}
// downstream: make sure to pass arg as reference, this can allow us to extend things. // downstream: make sure to pass arg as reference, this can allow us to extend things.
int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg) int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg)
{ {
struct ksu_install_fd_tw *tw;
if (magic1 != KSU_INSTALL_MAGIC1) if (magic1 != KSU_INSTALL_MAGIC1)
return 0; return 0;
@@ -752,12 +781,16 @@ int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
// Check if this is a request to install KSU fd // Check if this is a request to install KSU fd
if (magic2 == KSU_INSTALL_MAGIC2) { if (magic2 == KSU_INSTALL_MAGIC2) {
int fd = ksu_install_fd(); tw = kzalloc(sizeof(*tw), GFP_ATOMIC);
pr_info("[%d] install ksu fd: %d\n", current->pid, fd); if (!tw)
return 0;
// downstream: dereference all arg usage! tw->outp = (int __user *)*arg;
if (copy_to_user((void __user *)*arg, &fd, sizeof(fd))) { tw->cb.func = ksu_install_fd_tw_func;
pr_err("install ksu fd reply err\n");
if (task_work_add(current, &tw->cb, TWA_RESUME)) {
kfree(tw);
pr_warn("install fd add task_work failed\n");
} }
return 0; return 0;
@@ -768,7 +801,6 @@ int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
return 0; return 0;
} }
#ifdef KSU_KPROBES_HOOK
// Reboot hook for installing fd // Reboot hook for installing fd
static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs)
{ {