kernel, ksud: clean headers and add fd wrapper for devpts (#193)
* Now Official KernelSU devpts compat is questionable Squashed commits:4893fad235e7c3d4a6a64bb2dae3f5Signed-off-by: Faris <rissu.ntk@gmail.com> Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Co-authored-by: weishu <twsxtd@gmail.com> Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
@@ -12,13 +12,9 @@ kernelsu-objs += throne_tracker.o
|
||||
kernelsu-objs += ksud.o
|
||||
kernelsu-objs += embed_ksud.o
|
||||
kernelsu-objs += kernel_compat.o
|
||||
kernelsu-objs += file_wrapper.o
|
||||
kernelsu-objs += throne_comm.o
|
||||
|
||||
ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
|
||||
kernelsu-objs += ksu_trace.o
|
||||
endif
|
||||
|
||||
|
||||
kernelsu-objs += selinux/selinux.o
|
||||
kernelsu-objs += selinux/sepolicy.o
|
||||
kernelsu-objs += selinux/rules.o
|
||||
@@ -89,12 +85,13 @@ ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
||||
ccflags-y += -DKSU_VERSION_FULL=\"$(KSU_VERSION_FULL)\"
|
||||
|
||||
# Checks hooks state
|
||||
ifeq ($(CONFIG_KSU_KPROBES_HOOK), y)
|
||||
$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK)
|
||||
else ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
|
||||
$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK)
|
||||
else ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
|
||||
$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK)
|
||||
ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
|
||||
ccflags-y += -DKSU_MANUAL_HOOK
|
||||
$(info -- SukiSU: KSU_MANUAL_HOOK)
|
||||
else
|
||||
ccflags-y += -DKSU_HAVE_SYSCALL_TRACEPOINTS_HOOK
|
||||
ccflags-y += -DKSU_KPROBES_HOOK
|
||||
$(info -- SukiSU: KSU_TRACEPOINT_HOOK)
|
||||
endif
|
||||
|
||||
# SELinux drivers check
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
#error "Unsupported arch"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "kernel_compat.h"
|
||||
#include "supercalls.h"
|
||||
|
||||
bool ksu_module_mounted = false;
|
||||
bool ksu_module_mounted __read_mostly = false;
|
||||
|
||||
#ifndef DEVPTS_SUPER_MAGIC
|
||||
#define DEVPTS_SUPER_MAGIC 0x1cd1
|
||||
@@ -55,8 +55,6 @@ extern int __ksu_handle_devpts(struct inode *inode); // sucompat.c
|
||||
bool ksu_is_compat __read_mostly = false;
|
||||
#endif
|
||||
|
||||
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
|
||||
static bool ksu_kernel_umount_enabled = true;
|
||||
|
||||
static int kernel_umount_feature_get(u64 *value)
|
||||
@@ -360,7 +358,7 @@ static void ksu_do_umount_lists(void)
|
||||
try_umount("/sbin", false, MNT_DETACH);
|
||||
}
|
||||
|
||||
#if defined(MODULE) || defined(CONFIG_KSU_KPROBES_HOOK)
|
||||
#if defined(MODULE) || defined(KSU_KPROBES_HOOK)
|
||||
struct umount_tw {
|
||||
struct callback_head cb;
|
||||
const struct cred *old_cred;
|
||||
@@ -438,7 +436,8 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
if (ksu_get_manager_uid() == new_uid.val) {
|
||||
pr_info("install fd for ksu manager(uid=%d)\n", new_uid.val);
|
||||
pr_info("install fd for ksu manager(uid=%d)\n",
|
||||
new_uid.val);
|
||||
ksu_install_fd();
|
||||
}
|
||||
|
||||
@@ -477,7 +476,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
current->pid);
|
||||
#endif
|
||||
|
||||
#if defined(MODULE) || defined(CONFIG_KSU_KPROBES_HOOK)
|
||||
#if defined(MODULE) || defined(KSU_KPROBES_HOOK)
|
||||
struct umount_tw *tw;
|
||||
tw = kmalloc(sizeof(*tw), GFP_ATOMIC);
|
||||
if (!tw)
|
||||
@@ -568,9 +567,9 @@ int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd,
|
||||
}
|
||||
|
||||
// -- For old kernel compat?
|
||||
#if !defined(MODULE) && !defined(CONFIG_KSU_KPROBES_HOOK)
|
||||
static int ksu_task_fix_setuid(struct cred *new,
|
||||
const struct cred *old, int flags)
|
||||
#if !defined(MODULE) && !defined(KSU_KPROBE_HOOK)
|
||||
static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
|
||||
int flags)
|
||||
{
|
||||
return ksu_handle_setuid(new, old);
|
||||
}
|
||||
@@ -598,7 +597,7 @@ static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
|
||||
static struct security_hook_list ksu_hooks[] = {
|
||||
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
|
||||
LSM_HOOK_INIT(inode_permission, ksu_inode_permission),
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check),
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
||||
@@ -633,7 +632,7 @@ static void ksu_lsm_hook_init(void)
|
||||
#endif
|
||||
|
||||
// -- For KPROBE and LKM handler
|
||||
#if defined(MODULE) || defined(CONFIG_KSU_KPROBES_HOOK)
|
||||
#if defined(MODULE) || defined(KSU_KPROBES_HOOK)
|
||||
static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||
|
||||
@@ -7,4 +7,10 @@
|
||||
void __init ksu_core_init(void);
|
||||
void ksu_core_exit(void);
|
||||
|
||||
void escape_to_root(void);
|
||||
|
||||
void nuke_ext4_sysfs(void);
|
||||
|
||||
extern bool ksu_module_mounted;
|
||||
|
||||
#endif
|
||||
|
||||
473
kernel/file_wrapper.c
Normal file
473
kernel/file_wrapper.c
Normal file
@@ -0,0 +1,473 @@
|
||||
#include "linux/export.h"
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksu.h"
|
||||
#include "ksud.h"
|
||||
#include "manager.h"
|
||||
#include "selinux/selinux.h"
|
||||
#include "core_hook.h"
|
||||
#include "objsec.h"
|
||||
|
||||
#include "file_wrapper.h"
|
||||
|
||||
#ifndef __poll_t
|
||||
typedef unsigned __bitwise __poll_t;
|
||||
#endif
|
||||
|
||||
static loff_t mksu_wrapper_llseek(struct file *fp, loff_t off, int flags)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->llseek(data->orig, off, flags);
|
||||
}
|
||||
|
||||
static ssize_t mksu_wrapper_read(struct file *fp, char __user *ptr, size_t sz,
|
||||
loff_t *off)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->read(orig, ptr, sz, off);
|
||||
}
|
||||
|
||||
static ssize_t mksu_wrapper_write(struct file *fp, const char __user *ptr,
|
||||
size_t sz, loff_t *off)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->write(orig, ptr, sz, off);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
|
||||
static ssize_t mksu_wrapper_read_iter(struct kiocb *iocb, struct iov_iter *iovi)
|
||||
{
|
||||
struct ksu_file_wrapper *data = iocb->ki_filp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
iocb->ki_filp = orig;
|
||||
return orig->f_op->read_iter(iocb, iovi);
|
||||
}
|
||||
|
||||
static ssize_t mksu_wrapper_write_iter(struct kiocb *iocb,
|
||||
struct iov_iter *iovi)
|
||||
{
|
||||
struct ksu_file_wrapper *data = iocb->ki_filp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
iocb->ki_filp = orig;
|
||||
return orig->f_op->write_iter(iocb, iovi);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
static int mksu_wrapper_iopoll(struct kiocb *kiocb, struct io_comp_batch *icb,
|
||||
unsigned int v)
|
||||
{
|
||||
struct ksu_file_wrapper *data = kiocb->ki_filp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
kiocb->ki_filp = orig;
|
||||
return orig->f_op->iopoll(kiocb, icb, v);
|
||||
}
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
|
||||
static int mksu_wrapper_iopoll(struct kiocb *kiocb, bool spin)
|
||||
{
|
||||
struct ksu_file_wrapper *data = kiocb->ki_filp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
kiocb->ki_filp = orig;
|
||||
return orig->f_op->iopoll(kiocb, spin);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
static int mksu_wrapper_iterate(struct file *fp, struct dir_context *dc)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->iterate(orig, dc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||
static int mksu_wrapper_iterate_shared(struct file *fp, struct dir_context *dc)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->iterate_shared(orig, dc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __poll_t mksu_wrapper_poll(struct file *fp,
|
||||
struct poll_table_struct *pts)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->poll(orig, pts);
|
||||
}
|
||||
|
||||
static long mksu_wrapper_unlocked_ioctl(struct file *fp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->unlocked_ioctl(orig, cmd, arg);
|
||||
}
|
||||
|
||||
static long mksu_wrapper_compat_ioctl(struct file *fp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->compat_ioctl(orig, cmd, arg);
|
||||
}
|
||||
|
||||
static int mksu_wrapper_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->mmap(orig, vma);
|
||||
}
|
||||
|
||||
// static unsigned long mmap_supported_flags {}
|
||||
|
||||
static int mksu_wrapper_open(struct inode *ino, struct file *fp)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
struct inode *orig_ino = file_inode(orig);
|
||||
return orig->f_op->open(orig_ino, orig);
|
||||
}
|
||||
|
||||
static int mksu_wrapper_flush(struct file *fp, fl_owner_t id)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->flush(orig, id);
|
||||
}
|
||||
|
||||
static int mksu_wrapper_fsync(struct file *fp, loff_t off1, loff_t off2,
|
||||
int datasync)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->fsync(orig, off1, off2, datasync);
|
||||
}
|
||||
|
||||
static int mksu_wrapper_fasync(int arg, struct file *fp, int arg2)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->fasync(arg, orig, arg2);
|
||||
}
|
||||
|
||||
static int mksu_wrapper_lock(struct file *fp, int arg1, struct file_lock *fl)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
return orig->f_op->lock(orig, arg1, fl);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
static ssize_t mksu_wrapper_sendpage(struct file *fp, struct page *pg, int arg1,
|
||||
size_t sz, loff_t *off, int arg2)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->sendpage) {
|
||||
return orig->f_op->sendpage(orig, pg, arg1, sz, off, arg2);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long mksu_wrapper_get_unmapped_area(struct file *fp,
|
||||
unsigned long arg1,
|
||||
unsigned long arg2,
|
||||
unsigned long arg3,
|
||||
unsigned long arg4)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->get_unmapped_area) {
|
||||
return orig->f_op->get_unmapped_area(orig, arg1, arg2, arg3,
|
||||
arg4);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// static int mksu_wrapper_check_flags(int arg) {}
|
||||
|
||||
static int mksu_wrapper_flock(struct file *fp, int arg1, struct file_lock *fl)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->flock) {
|
||||
return orig->f_op->flock(orig, arg1, fl);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t mksu_wrapper_splice_write(struct pipe_inode_info *pii,
|
||||
struct file *fp, loff_t *off,
|
||||
size_t sz, unsigned int arg1)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->splice_write) {
|
||||
return orig->f_op->splice_write(pii, orig, off, sz, arg1);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t mksu_wrapper_splice_read(struct file *fp, loff_t *off,
|
||||
struct pipe_inode_info *pii, size_t sz,
|
||||
unsigned int arg1)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->splice_read) {
|
||||
return orig->f_op->splice_read(orig, off, pii, sz, arg1);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||
void mksu_wrapper_splice_eof(struct file *fp)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->splice_eof) {
|
||||
return orig->f_op->splice_eof(orig);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
static int mksu_wrapper_setlease(struct file *fp, int arg1,
|
||||
struct file_lease **fl, void **p)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->setlease) {
|
||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||
static int mksu_wrapper_setlease(struct file *fp, int arg1,
|
||||
struct file_lock **fl, void **p)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->setlease) {
|
||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#elif LINUX_VERSION_CODE >= \
|
||||
KERNEL_VERSION( \
|
||||
3, 18, \
|
||||
0) // int (*setlease)(struct file *, long, struct file_lock **, void **);
|
||||
static int mksu_wrapper_setlease(struct file *fp, long arg1,
|
||||
struct file_lock **fl, void **p)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->setlease) {
|
||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#else // int (*setlease)(struct file *, long, struct file_lock **);
|
||||
static int mksu_wrapper_setlease(struct file *fp, long arg1,
|
||||
struct file_lock **fl)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->setlease) {
|
||||
return orig->f_op->setlease(orig, arg1, fl);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long mksu_wrapper_fallocate(struct file *fp, int mode, loff_t offset,
|
||||
loff_t len)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->fallocate) {
|
||||
return orig->f_op->fallocate(orig, mode, offset, len);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
|
||||
static void mksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f)
|
||||
{
|
||||
struct ksu_file_wrapper *data = m->file->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->show_fdinfo) {
|
||||
orig->f_op->show_fdinfo(m, orig);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static int mksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f)
|
||||
{
|
||||
struct ksu_file_wrapper *data = m->file->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->show_fdinfo) {
|
||||
orig->f_op->show_fdinfo(m, orig);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||
static ssize_t mksu_wrapper_copy_file_range(struct file *f1, loff_t off1,
|
||||
struct file *f2, loff_t off2,
|
||||
size_t sz, unsigned int flags)
|
||||
{
|
||||
// TODO: determine which file to use
|
||||
struct ksu_file_wrapper *data = f1->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->copy_file_range) {
|
||||
return orig->f_op->copy_file_range(orig, off1, f2, off2, sz,
|
||||
flags);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
|
||||
static loff_t mksu_wrapper_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out,
|
||||
loff_t pos_out, loff_t len,
|
||||
unsigned int remap_flags)
|
||||
{
|
||||
// TODO: determine which file to use
|
||||
struct ksu_file_wrapper *data = file_in->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->remap_file_range) {
|
||||
return orig->f_op->remap_file_range(orig, pos_in, file_out,
|
||||
pos_out, len, remap_flags);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
|
||||
static int mksu_wrapper_fadvise(struct file *fp, loff_t off1, loff_t off2,
|
||||
int flags)
|
||||
{
|
||||
struct ksu_file_wrapper *data = fp->private_data;
|
||||
struct file *orig = data->orig;
|
||||
if (orig->f_op->fadvise) {
|
||||
return orig->f_op->fadvise(orig, off1, off2, flags);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mksu_wrapper_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
mksu_delete_file_wrapper(filp->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ksu_file_wrapper *mksu_create_file_wrapper(struct file *fp)
|
||||
{
|
||||
struct ksu_file_wrapper *p =
|
||||
kcalloc(sizeof(struct ksu_file_wrapper), 1, GFP_KERNEL);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
get_file(fp);
|
||||
|
||||
p->orig = fp;
|
||||
p->ops.owner = THIS_MODULE;
|
||||
p->ops.llseek = fp->f_op->llseek ? mksu_wrapper_llseek : NULL;
|
||||
p->ops.read = fp->f_op->read ? mksu_wrapper_read : NULL;
|
||||
p->ops.write = fp->f_op->write ? mksu_wrapper_write : NULL;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
|
||||
p->ops.read_iter = fp->f_op->read_iter ? mksu_wrapper_read_iter : NULL;
|
||||
p->ops.write_iter =
|
||||
fp->f_op->write_iter ? mksu_wrapper_write_iter : NULL;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
p->ops.iopoll = fp->f_op->iopoll ? mksu_wrapper_iopoll : NULL;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
p->ops.iterate = fp->f_op->iterate ? mksu_wrapper_iterate : NULL;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||
p->ops.iterate_shared =
|
||||
fp->f_op->iterate_shared ? mksu_wrapper_iterate_shared : NULL;
|
||||
#endif
|
||||
p->ops.poll = fp->f_op->poll ? mksu_wrapper_poll : NULL;
|
||||
p->ops.unlocked_ioctl =
|
||||
fp->f_op->unlocked_ioctl ? mksu_wrapper_unlocked_ioctl : NULL;
|
||||
p->ops.compat_ioctl =
|
||||
fp->f_op->compat_ioctl ? mksu_wrapper_compat_ioctl : NULL;
|
||||
p->ops.mmap = fp->f_op->mmap ? mksu_wrapper_mmap : NULL;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
p->ops.fop_flags = fp->f_op->fop_flags;
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
|
||||
p->ops.mmap_supported_flags = fp->f_op->mmap_supported_flags;
|
||||
#endif
|
||||
p->ops.open = fp->f_op->open ? mksu_wrapper_open : NULL;
|
||||
p->ops.flush = fp->f_op->flush ? mksu_wrapper_flush : NULL;
|
||||
p->ops.release = mksu_wrapper_release;
|
||||
p->ops.fsync = fp->f_op->fsync ? mksu_wrapper_fsync : NULL;
|
||||
p->ops.fasync = fp->f_op->fasync ? mksu_wrapper_fasync : NULL;
|
||||
p->ops.lock = fp->f_op->lock ? mksu_wrapper_lock : NULL;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
p->ops.sendpage = fp->f_op->sendpage ? mksu_wrapper_sendpage : NULL;
|
||||
#endif
|
||||
p->ops.get_unmapped_area = fp->f_op->get_unmapped_area ?
|
||||
mksu_wrapper_get_unmapped_area :
|
||||
NULL;
|
||||
p->ops.check_flags = fp->f_op->check_flags;
|
||||
p->ops.flock = fp->f_op->flock ? mksu_wrapper_flock : NULL;
|
||||
p->ops.splice_write =
|
||||
fp->f_op->splice_write ? mksu_wrapper_splice_write : NULL;
|
||||
p->ops.splice_read =
|
||||
fp->f_op->splice_read ? mksu_wrapper_splice_read : NULL;
|
||||
p->ops.setlease = fp->f_op->setlease ? mksu_wrapper_setlease : NULL;
|
||||
p->ops.fallocate = fp->f_op->fallocate ? mksu_wrapper_fallocate : NULL;
|
||||
p->ops.show_fdinfo =
|
||||
fp->f_op->show_fdinfo ? mksu_wrapper_show_fdinfo : NULL;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||
p->ops.copy_file_range =
|
||||
fp->f_op->copy_file_range ? mksu_wrapper_copy_file_range : NULL;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
|
||||
p->ops.remap_file_range = fp->f_op->remap_file_range ?
|
||||
mksu_wrapper_remap_file_range :
|
||||
NULL;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
|
||||
p->ops.fadvise = fp->f_op->fadvise ? mksu_wrapper_fadvise : NULL;
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||
p->ops.splice_eof =
|
||||
fp->f_op->splice_eof ? mksu_wrapper_splice_eof : NULL;
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void mksu_delete_file_wrapper(struct ksu_file_wrapper *data)
|
||||
{
|
||||
fput((struct file *)data->orig);
|
||||
kfree(data);
|
||||
}
|
||||
10
kernel/file_wrapper.h
Normal file
10
kernel/file_wrapper.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
struct ksu_file_wrapper {
|
||||
struct file *orig;
|
||||
struct file_operations ops;
|
||||
};
|
||||
|
||||
struct ksu_file_wrapper *mksu_create_file_wrapper(struct file *fp);
|
||||
void mksu_delete_file_wrapper(struct ksu_file_wrapper *data);
|
||||
30
kernel/ksu.c
30
kernel/ksu.c
@@ -14,6 +14,9 @@
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksu.h"
|
||||
#include "throne_tracker.h"
|
||||
#include "sucompat.h"
|
||||
#include "ksud.h"
|
||||
#include "supercalls.h"
|
||||
|
||||
static struct workqueue_struct *ksu_workqueue;
|
||||
|
||||
@@ -22,11 +25,6 @@ bool ksu_queue_work(struct work_struct *work)
|
||||
return queue_work(ksu_workqueue, work);
|
||||
}
|
||||
|
||||
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
void *argv, void *envp, int *flags);
|
||||
|
||||
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
void *argv, void *envp, int *flags);
|
||||
|
||||
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||
void *envp, int *flags)
|
||||
@@ -36,16 +34,6 @@ int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||
flags);
|
||||
}
|
||||
|
||||
extern void ksu_sucompat_init(void);
|
||||
extern void ksu_sucompat_exit(void);
|
||||
extern void ksu_ksud_init(void);
|
||||
extern void ksu_ksud_exit(void);
|
||||
extern void ksu_supercalls_init(void);
|
||||
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||
extern void ksu_trace_register();
|
||||
extern void ksu_trace_unregister();
|
||||
#endif
|
||||
|
||||
int __init kernelsu_init(void)
|
||||
{
|
||||
pr_info("Initialized on: %s (%s) with driver version: %u\n",
|
||||
@@ -75,14 +63,10 @@ int __init kernelsu_init(void)
|
||||
|
||||
ksu_sucompat_init();
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
ksu_ksud_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||
ksu_trace_register();
|
||||
#endif
|
||||
|
||||
#ifdef MODULE
|
||||
#ifndef CONFIG_KSU_DEBUG
|
||||
kobject_del(&THIS_MODULE->mkobj.kobj);
|
||||
@@ -101,14 +85,10 @@ void kernelsu_exit(void)
|
||||
|
||||
destroy_workqueue(ksu_workqueue);
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
ksu_ksud_exit();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||
ksu_trace_unregister();
|
||||
#endif
|
||||
|
||||
ksu_sucompat_exit();
|
||||
|
||||
ksu_core_exit();
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#include "ksu_trace.h"
|
||||
|
||||
// extern kernelsu functions
|
||||
extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr,
|
||||
void *argv, void *envp, int *flags);
|
||||
extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user,
|
||||
int *mode, int *flags);
|
||||
extern bool ksu_vfs_read_hook __read_mostly;
|
||||
extern int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr,
|
||||
size_t *count_ptr);
|
||||
extern int ksu_handle_stat(int *dfd, const char __user **filename_user,
|
||||
int *flags);
|
||||
extern bool ksu_input_hook __read_mostly;
|
||||
extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||
int *value);
|
||||
extern int ksu_handle_devpts(struct inode *);
|
||||
// end kernelsu functions
|
||||
|
||||
// tracepoint callback functions
|
||||
void ksu_trace_execveat_hook_callback(void *data, int *fd,
|
||||
struct filename **filename_ptr,
|
||||
void *argv, void *envp,
|
||||
int *flags)
|
||||
{
|
||||
ksu_handle_execveat(fd, filename_ptr, argv, envp,
|
||||
flags);
|
||||
}
|
||||
|
||||
void ksu_trace_faccessat_hook_callback(void *data, int *dfd,
|
||||
const char __user **filename_user,
|
||||
int *mode, int *flags)
|
||||
{
|
||||
ksu_handle_faccessat(dfd, filename_user, mode, flags);
|
||||
}
|
||||
|
||||
void ksu_trace_sys_read_hook_callback(void *data, unsigned int fd,
|
||||
char __user **buf_ptr, size_t *count_ptr)
|
||||
{
|
||||
if (unlikely(ksu_vfs_read_hook))
|
||||
ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
||||
}
|
||||
|
||||
void ksu_trace_stat_hook_callback(void *data, int *dfd,
|
||||
const char __user **filename_user, int *flags)
|
||||
{
|
||||
ksu_handle_stat(dfd, filename_user, flags);
|
||||
}
|
||||
|
||||
void ksu_trace_input_hook_callback(void *data, unsigned int *type,
|
||||
unsigned int *code, int *value)
|
||||
{
|
||||
if (unlikely(ksu_input_hook))
|
||||
ksu_handle_input_handle_event(type, code, value);
|
||||
}
|
||||
|
||||
// end tracepoint callback functions
|
||||
|
||||
// register tracepoint callback functions
|
||||
void ksu_trace_register(void)
|
||||
{
|
||||
register_trace_ksu_trace_execveat_hook(
|
||||
ksu_trace_execveat_hook_callback, NULL);
|
||||
register_trace_ksu_trace_faccessat_hook(
|
||||
ksu_trace_faccessat_hook_callback, NULL);
|
||||
register_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback,
|
||||
NULL);
|
||||
register_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL);
|
||||
register_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback,
|
||||
NULL);
|
||||
}
|
||||
|
||||
// unregister tracepoint callback functions
|
||||
void ksu_trace_unregister(void)
|
||||
{
|
||||
unregister_trace_ksu_trace_execveat_hook(
|
||||
ksu_trace_execveat_hook_callback, NULL);
|
||||
unregister_trace_ksu_trace_faccessat_hook(
|
||||
ksu_trace_faccessat_hook_callback, NULL);
|
||||
unregister_trace_ksu_trace_sys_read_hook(
|
||||
ksu_trace_sys_read_hook_callback, NULL);
|
||||
unregister_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback,
|
||||
NULL);
|
||||
unregister_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback,
|
||||
NULL);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ksu_trace
|
||||
|
||||
#if !defined(_KSU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _KSU_TRACE_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
DECLARE_TRACE(ksu_trace_execveat_hook,
|
||||
TP_PROTO(int *fd, struct filename **filename_ptr, void *argv,
|
||||
void *envp, int *flags),
|
||||
TP_ARGS(fd, filename_ptr, argv, envp, flags));
|
||||
|
||||
DECLARE_TRACE(ksu_trace_faccessat_hook,
|
||||
TP_PROTO(int *dfd, const char __user **filename_user, int *mode,
|
||||
int *flags),
|
||||
TP_ARGS(dfd, filename_user, mode, flags));
|
||||
|
||||
DECLARE_TRACE(ksu_trace_sys_read_hook,
|
||||
TP_PROTO(unsigned int fd, char __user **buf_ptr,
|
||||
size_t *count_ptr),
|
||||
TP_ARGS(fd, buf_ptr, count_ptr));
|
||||
|
||||
DECLARE_TRACE(ksu_trace_stat_hook,
|
||||
TP_PROTO(int *dfd, const char __user **filename_user, int *flags),
|
||||
TP_ARGS(dfd, filename_user, flags));
|
||||
|
||||
DECLARE_TRACE(ksu_trace_input_hook,
|
||||
TP_PROTO(unsigned int *type, unsigned int *code, int *value),
|
||||
TP_ARGS(type, code, value));
|
||||
|
||||
|
||||
#endif /* _KSU_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE ksu_trace
|
||||
|
||||
#include <trace/define_trace.h>
|
||||
@@ -1,8 +0,0 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "ksu_trace.h"
|
||||
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_hook);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_faccessat_hook);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_sys_read_hook);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_stat_hook);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_input_hook);
|
||||
@@ -54,7 +54,7 @@ static void stop_vfs_read_hook(void);
|
||||
static void stop_execve_hook(void);
|
||||
static void stop_input_hook(void);
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
static struct work_struct stop_vfs_read_work;
|
||||
static struct work_struct stop_execve_hook_work;
|
||||
static struct work_struct stop_input_hook_work;
|
||||
@@ -64,7 +64,7 @@ bool ksu_input_hook __read_mostly = true;
|
||||
#endif
|
||||
bool ksu_execveat_hook __read_mostly = true;
|
||||
|
||||
u32 ksu_devpts_sid;
|
||||
u32 ksu_file_sid;
|
||||
|
||||
// Detect whether it is on or not
|
||||
static bool is_boot_phase = true;
|
||||
@@ -83,11 +83,11 @@ void on_post_fs_data(void)
|
||||
// sanity check, this may influence the performance
|
||||
stop_input_hook();
|
||||
|
||||
ksu_devpts_sid = ksu_get_devpts_sid();
|
||||
pr_info("devpts sid: %d\n", ksu_devpts_sid);
|
||||
|
||||
// End of boot state
|
||||
// End of boot state
|
||||
is_boot_phase = false;
|
||||
|
||||
ksu_file_sid = ksu_get_ksu_file_sid();
|
||||
pr_info("devpts sid: %d\n", ksu_file_sid);
|
||||
}
|
||||
|
||||
struct user_arg_ptr {
|
||||
@@ -294,7 +294,7 @@ static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
|
||||
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||
size_t *count_ptr, loff_t **pos)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_vfs_read_hook) {
|
||||
return 0;
|
||||
}
|
||||
@@ -407,7 +407,7 @@ static bool is_volumedown_enough(unsigned int count)
|
||||
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||
int *value)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_input_hook) {
|
||||
return 0;
|
||||
}
|
||||
@@ -449,7 +449,7 @@ bool ksu_is_safe_mode(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
@@ -668,7 +668,7 @@ int __maybe_unused ksu_handle_compat_execve_ksud(
|
||||
|
||||
static void stop_vfs_read_hook(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
bool ret = schedule_work(&stop_vfs_read_work);
|
||||
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
||||
#else
|
||||
@@ -679,7 +679,7 @@ static void stop_vfs_read_hook(void)
|
||||
|
||||
static void stop_execve_hook(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
bool ret = schedule_work(&stop_execve_hook_work);
|
||||
pr_info("unregister execve kprobe: %d!\n", ret);
|
||||
#else
|
||||
@@ -690,7 +690,7 @@ static void stop_execve_hook(void)
|
||||
|
||||
static void stop_input_hook(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
static bool input_hook_stopped = false;
|
||||
if (input_hook_stopped) {
|
||||
return;
|
||||
@@ -710,7 +710,7 @@ static void stop_input_hook(void)
|
||||
// ksud: module support
|
||||
void ksu_ksud_init(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
int ret;
|
||||
|
||||
ret = register_kprobe(&execve_kp);
|
||||
@@ -730,7 +730,7 @@ void ksu_ksud_init(void)
|
||||
|
||||
void ksu_ksud_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
unregister_kprobe(&execve_kp);
|
||||
// this should be done before unregister vfs_read_kp
|
||||
// unregister_kprobe(&vfs_read_kp);
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
#define KSUD_PATH "/data/adb/ksud"
|
||||
|
||||
void ksu_ksud_init();
|
||||
void ksu_ksud_exit();
|
||||
|
||||
void on_post_fs_data(void);
|
||||
|
||||
bool ksu_is_safe_mode(void);
|
||||
|
||||
extern u32 ksu_devpts_sid;
|
||||
extern u32 ksu_file_sid;
|
||||
|
||||
extern bool ksu_execveat_hook __read_mostly;
|
||||
extern int ksu_handle_pre_ksud(const char *filename);
|
||||
|
||||
@@ -238,23 +238,26 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char perm_buf[MAX_SEPOL_LEN];
|
||||
|
||||
char *s, *t, *c, *p;
|
||||
if (get_object(src_buf, (void __user *)data.sepol1, sizeof(src_buf), &s) < 0) {
|
||||
if (get_object(src_buf, (void __user *)data.sepol1,
|
||||
sizeof(src_buf), &s) < 0) {
|
||||
pr_err("sepol: copy src failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (get_object(tgt_buf, (void __user *)data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||
if (get_object(tgt_buf, (void __user *)data.sepol2,
|
||||
sizeof(tgt_buf), &t) < 0) {
|
||||
pr_err("sepol: copy tgt failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (get_object(cls_buf, (void __user *)data.sepol3, sizeof(cls_buf), &c) < 0) {
|
||||
if (get_object(cls_buf, (void __user *)data.sepol3,
|
||||
sizeof(cls_buf), &c) < 0) {
|
||||
pr_err("sepol: copy cls failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (get_object(perm_buf, (void __user *)data.sepol4, sizeof(perm_buf), &p) <
|
||||
0) {
|
||||
if (get_object(perm_buf, (void __user *)data.sepol4,
|
||||
sizeof(perm_buf), &p) < 0) {
|
||||
pr_err("sepol: copy perm failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -285,15 +288,18 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char perm_set[MAX_SEPOL_LEN];
|
||||
|
||||
char *s, *t, *c;
|
||||
if (get_object(src_buf, (void __user *)data.sepol1, sizeof(src_buf), &s) < 0) {
|
||||
if (get_object(src_buf, (void __user *)data.sepol1,
|
||||
sizeof(src_buf), &s) < 0) {
|
||||
pr_err("sepol: copy src failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (get_object(tgt_buf, (void __user *)data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||
if (get_object(tgt_buf, (void __user *)data.sepol2,
|
||||
sizeof(tgt_buf), &t) < 0) {
|
||||
pr_err("sepol: copy tgt failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (get_object(cls_buf, (void __user *)data.sepol3, sizeof(cls_buf), &c) < 0) {
|
||||
if (get_object(cls_buf, (void __user *)data.sepol3,
|
||||
sizeof(cls_buf), &c) < 0) {
|
||||
pr_err("sepol: copy cls failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -302,8 +308,8 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
pr_err("sepol: copy operation failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(perm_set, (void __user *)data.sepol5, sizeof(perm_set)) <
|
||||
0) {
|
||||
if (strncpy_from_user(perm_set, (void __user *)data.sepol5,
|
||||
sizeof(perm_set)) < 0) {
|
||||
pr_err("sepol: copy perm_set failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -324,7 +330,8 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
case CMD_TYPE_STATE: {
|
||||
char src[MAX_SEPOL_LEN];
|
||||
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1, sizeof(src)) < 0) {
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||
sizeof(src)) < 0) {
|
||||
pr_err("sepol: copy src failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -346,11 +353,13 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char type[MAX_SEPOL_LEN];
|
||||
char attr[MAX_SEPOL_LEN];
|
||||
|
||||
if (strncpy_from_user(type, (void __user *)data.sepol1, sizeof(type)) < 0) {
|
||||
if (strncpy_from_user(type, (void __user *)data.sepol1,
|
||||
sizeof(type)) < 0) {
|
||||
pr_err("sepol: copy type failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(attr, (void __user *)data.sepol2, sizeof(attr)) < 0) {
|
||||
if (strncpy_from_user(attr, (void __user *)data.sepol2,
|
||||
sizeof(attr)) < 0) {
|
||||
pr_err("sepol: copy attr failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -371,7 +380,8 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
case CMD_ATTR: {
|
||||
char attr[MAX_SEPOL_LEN];
|
||||
|
||||
if (strncpy_from_user(attr, (void __user *)data.sepol1, sizeof(attr)) < 0) {
|
||||
if (strncpy_from_user(attr, (void __user *)data.sepol1,
|
||||
sizeof(attr)) < 0) {
|
||||
pr_err("sepol: copy attr failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -389,15 +399,18 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char default_type[MAX_SEPOL_LEN];
|
||||
char object[MAX_SEPOL_LEN];
|
||||
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1, sizeof(src)) < 0) {
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||
sizeof(src)) < 0) {
|
||||
pr_err("sepol: copy src failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2, sizeof(tgt)) < 0) {
|
||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
||||
sizeof(tgt)) < 0) {
|
||||
pr_err("sepol: copy tgt failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(cls, (void __user *)data.sepol3, sizeof(cls)) < 0) {
|
||||
if (strncpy_from_user(cls, (void __user *)data.sepol3,
|
||||
sizeof(cls)) < 0) {
|
||||
pr_err("sepol: copy cls failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -410,7 +423,8 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
if ((void __user *)data.sepol5 == NULL) {
|
||||
real_object = NULL;
|
||||
} else {
|
||||
if (strncpy_from_user(object, (void __user *)data.sepol5,
|
||||
if (strncpy_from_user(object,
|
||||
(void __user *)data.sepol5,
|
||||
sizeof(object)) < 0) {
|
||||
pr_err("sepol: copy object failed.\n");
|
||||
goto exit;
|
||||
@@ -430,15 +444,18 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char cls[MAX_SEPOL_LEN];
|
||||
char default_type[MAX_SEPOL_LEN];
|
||||
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1, sizeof(src)) < 0) {
|
||||
if (strncpy_from_user(src, (void __user *)data.sepol1,
|
||||
sizeof(src)) < 0) {
|
||||
pr_err("sepol: copy src failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2, sizeof(tgt)) < 0) {
|
||||
if (strncpy_from_user(tgt, (void __user *)data.sepol2,
|
||||
sizeof(tgt)) < 0) {
|
||||
pr_err("sepol: copy tgt failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(cls, (void __user *)data.sepol3, sizeof(cls)) < 0) {
|
||||
if (strncpy_from_user(cls, (void __user *)data.sepol3,
|
||||
sizeof(cls)) < 0) {
|
||||
pr_err("sepol: copy cls failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
@@ -465,16 +482,18 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char name[MAX_SEPOL_LEN];
|
||||
char path[MAX_SEPOL_LEN];
|
||||
char context[MAX_SEPOL_LEN];
|
||||
if (strncpy_from_user(name, (void __user *)data.sepol1, sizeof(name)) < 0) {
|
||||
if (strncpy_from_user(name, (void __user *)data.sepol1,
|
||||
sizeof(name)) < 0) {
|
||||
pr_err("sepol: copy name failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(path, (void __user *)data.sepol2, sizeof(path)) < 0) {
|
||||
if (strncpy_from_user(path, (void __user *)data.sepol2,
|
||||
sizeof(path)) < 0) {
|
||||
pr_err("sepol: copy path failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
if (strncpy_from_user(context, (void __user *)data.sepol3, sizeof(context)) <
|
||||
0) {
|
||||
if (strncpy_from_user(context, (void __user *)data.sepol3,
|
||||
sizeof(context)) < 0) {
|
||||
pr_err("sepol: copy context failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -155,16 +155,15 @@ bool is_zygote(void *sec)
|
||||
return result;
|
||||
}
|
||||
|
||||
#define DEVPTS_DOMAIN "u:object_r:ksu_file:s0"
|
||||
#define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0"
|
||||
|
||||
u32 ksu_get_devpts_sid(void)
|
||||
u32 ksu_get_ksu_file_sid(void)
|
||||
{
|
||||
u32 devpts_sid = 0;
|
||||
int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN),
|
||||
&devpts_sid);
|
||||
|
||||
if (err)
|
||||
pr_info("get devpts sid err %d\n", err);
|
||||
|
||||
return devpts_sid;
|
||||
u32 ksu_file_sid = 0;
|
||||
int err = security_secctx_to_secid(
|
||||
KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN), &ksu_file_sid);
|
||||
if (err) {
|
||||
pr_info("get ksufile sid err %d\n", err);
|
||||
}
|
||||
return ksu_file_sid;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ bool is_zygote(void *cred);
|
||||
|
||||
void apply_kernelsu_rules(void);
|
||||
|
||||
u32 ksu_get_devpts_sid(void);
|
||||
|
||||
u32 ksu_get_ksu_file_sid(void);
|
||||
|
||||
int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksud.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "sucompat.h"
|
||||
#include "core_hook.h"
|
||||
|
||||
#define SU_PATH "/system/bin/su"
|
||||
#define SH_PATH "/system/bin/sh"
|
||||
@@ -29,10 +31,6 @@
|
||||
static const char su[] = SU_PATH;
|
||||
static const char ksud_path[] = KSUD_PATH;
|
||||
|
||||
extern void escape_to_root(void);
|
||||
void ksu_sucompat_enable(void);
|
||||
void ksu_sucompat_disable(void);
|
||||
|
||||
static bool ksu_su_compat_enabled __read_mostly = true;
|
||||
|
||||
static int su_compat_feature_get(u64 *value)
|
||||
@@ -91,7 +89,7 @@ static inline char __user *ksud_user_path(void)
|
||||
|
||||
static inline bool __is_su_allowed(const void *ptr_to_check)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
if (!ksu_su_compat_enabled)
|
||||
return false;
|
||||
#endif
|
||||
@@ -180,15 +178,9 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// dummified
|
||||
int ksu_handle_devpts(struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ksu_handle_devpts(struct inode *inode)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_su_compat_enabled)
|
||||
return 0;
|
||||
#endif
|
||||
@@ -212,13 +204,12 @@ int __ksu_handle_devpts(struct inode *inode)
|
||||
struct inode_security_struct *sec = (struct inode_security_struct *)inode->i_security;
|
||||
#endif
|
||||
|
||||
if (ksu_devpts_sid && sec)
|
||||
sec->sid = ksu_devpts_sid;
|
||||
|
||||
if (ksu_file_sid && sec)
|
||||
sec->sid = ksu_file_sid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
|
||||
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
@@ -252,23 +243,10 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct inode *inode;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
|
||||
struct file *file = (struct file *)PT_REGS_PARM2(regs);
|
||||
inode = file->f_path.dentry->d_inode;
|
||||
#else
|
||||
inode = (struct inode *)PT_REGS_PARM2(regs);
|
||||
#endif
|
||||
|
||||
return ksu_handle_devpts(inode);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static struct kprobe *su_kps[6];
|
||||
static struct kprobe *su_kps[5];
|
||||
#else
|
||||
static struct kprobe *su_kps[4];
|
||||
static struct kprobe *su_kps[3];
|
||||
#endif
|
||||
|
||||
static struct kprobe *init_kprobe(const char *name,
|
||||
@@ -304,14 +282,13 @@ static void destroy_kprobe(struct kprobe **kp_ptr)
|
||||
|
||||
void ksu_sucompat_enable(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
|
||||
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
|
||||
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
|
||||
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
|
||||
#ifdef CONFIG_COMPAT
|
||||
su_kps[4] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre);
|
||||
su_kps[5] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre);
|
||||
su_kps[3] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre);
|
||||
su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre);
|
||||
#endif
|
||||
#else
|
||||
ksu_su_compat_enabled = true;
|
||||
@@ -321,7 +298,7 @@ void ksu_sucompat_enable(void)
|
||||
|
||||
void ksu_sucompat_disable(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
#ifdef KSU_KPROBES_HOOK
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(su_kps); i++) {
|
||||
destroy_kprobe(&su_kps[i]);
|
||||
|
||||
17
kernel/sucompat.h
Normal file
17
kernel/sucompat.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __KSU_H_SUCOMPAT
|
||||
#define __KSU_H_SUCOMPAT
|
||||
#include <linux/sched.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
void ksu_sucompat_init(void);
|
||||
void ksu_sucompat_exit(void);
|
||||
|
||||
void ksu_sucompat_enable(void);
|
||||
void ksu_sucompat_disable(void);
|
||||
|
||||
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
void *argv, void *envp, int *flags);
|
||||
|
||||
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
void *argv, void *envp, int *flags);
|
||||
#endif
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "manager.h"
|
||||
#include "sulog.h"
|
||||
#include "selinux/selinux.h"
|
||||
#include "core_hook.h"
|
||||
#include "objsec.h"
|
||||
#include "file_wrapper.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "throne_comm.h"
|
||||
#include "dynamic_manager.h"
|
||||
@@ -385,7 +388,7 @@ static int do_get_hook_type(void __user *arg)
|
||||
|
||||
#if defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
||||
type = "Tracepoint";
|
||||
#elif defined(CONFIG_KSU_MANUAL_HOOK)
|
||||
#elif defined(KSU_MANUAL_HOOK)
|
||||
type = "Manual";
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
@@ -516,6 +519,73 @@ static int do_enable_uid_scanner(void __user *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_wrapper_fd(void __user *arg)
|
||||
{
|
||||
if (!ksu_file_sid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ksu_get_wrapper_fd_cmd cmd;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("get_wrapper_fd: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
struct file *f = fget(cmd.fd);
|
||||
if (!f) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
struct ksu_file_wrapper *data = mksu_create_file_wrapper(f);
|
||||
if (data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto put_orig_file;
|
||||
}
|
||||
|
||||
struct file *pf = anon_inode_getfile("[mksu_fdwrapper]", &data->ops,
|
||||
data, f->f_flags);
|
||||
if (IS_ERR(pf)) {
|
||||
ret = PTR_ERR(pf);
|
||||
pr_err("mksu_fdwrapper: anon_inode_getfile failed: %ld\n",
|
||||
PTR_ERR(pf));
|
||||
goto put_wrapper_data;
|
||||
}
|
||||
|
||||
struct inode *wrapper_inode = file_inode(pf);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || \
|
||||
defined(KSU_OPTIONAL_SELINUX_INODE)
|
||||
struct inode_security_struct *sec = selinux_inode(wrapper_inode);
|
||||
#else
|
||||
struct inode_security_struct *sec =
|
||||
(struct inode_security_struct *)wrapper_inode->i_security;
|
||||
#endif
|
||||
if (sec) {
|
||||
sec->sid = ksu_file_sid;
|
||||
}
|
||||
|
||||
ret = get_unused_fd_flags(cmd.flags);
|
||||
if (ret < 0) {
|
||||
pr_err("mksu_fdwrapper: get unused fd failed: %d\n", ret);
|
||||
goto put_wrapper_file;
|
||||
}
|
||||
|
||||
// pr_info("mksu_fdwrapper: installed wrapper fd for %p %d (flags=%d, mode=%d) to %p %d (flags=%d, mode=%d)", f, cmd.fd, f->f_flags, f->f_mode, pf, ret, pf->f_flags, pf->f_mode);
|
||||
// pf->f_mode |= FMODE_READ | FMODE_CAN_READ | FMODE_WRITE | FMODE_CAN_WRITE;
|
||||
fd_install(ret, pf);
|
||||
goto put_orig_file;
|
||||
|
||||
put_wrapper_file:
|
||||
fput(pf);
|
||||
put_wrapper_data:
|
||||
mksu_delete_file_wrapper(data);
|
||||
put_orig_file:
|
||||
fput(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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 },
|
||||
@@ -532,6 +602,7 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
|
||||
{ .cmd = KSU_IOCTL_SET_APP_PROFILE, .name = "SET_APP_PROFILE", .handler = do_set_app_profile, .perm_check = only_manager },
|
||||
{ .cmd = KSU_IOCTL_GET_FEATURE, .name = "GET_FEATURE", .handler = do_get_feature, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_WRAPPER_FD, .name = "GET_WRAPPER_FD", .handler = do_get_wrapper_fd, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow},
|
||||
{ .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root},
|
||||
{ .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root},
|
||||
@@ -542,7 +613,7 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
|
||||
{ .cmd = KSU_IOCTL_KPM, .name = "KPM_OPERATION", .handler = do_kpm, .perm_check = manager_or_root},
|
||||
#endif
|
||||
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine
|
||||
};
|
||||
}
|
||||
|
||||
void ksu_supercalls_init(void)
|
||||
{
|
||||
|
||||
@@ -104,6 +104,11 @@ struct ksu_enable_uid_scanner_cmd {
|
||||
void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS)
|
||||
};
|
||||
|
||||
struct ksu_get_wrapper_fd_cmd {
|
||||
__u32 fd;
|
||||
__u32 flags; // CLOEXEC
|
||||
};
|
||||
|
||||
// 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)
|
||||
@@ -119,6 +124,7 @@ struct ksu_enable_uid_scanner_cmd {
|
||||
#define KSU_IOCTL_SET_APP_PROFILE _IOC(_IOC_WRITE, 'K', 12, 0)
|
||||
#define KSU_IOCTL_GET_FEATURE _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
||||
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||
#define KSU_IOCTL_GET_WRAPPER_FD _IOC(_IOC_NONE, 'K', 10000, 0)
|
||||
// Other IOCTL command definitions
|
||||
#define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0)
|
||||
#define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)
|
||||
@@ -142,4 +148,6 @@ struct ksu_ioctl_cmd_map {
|
||||
// Install KSU fd to current process
|
||||
int ksu_install_fd(void);
|
||||
|
||||
#endif // __KSU_H_SUPERCALLS
|
||||
void ksu_supercalls_init();
|
||||
|
||||
#endif // __KSU_H_SUPERCALLS
|
||||
|
||||
Reference in New Issue
Block a user