Reworking fdwrapper
Co-authored-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com> Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Co-authored-by: Ylarod <me@ylarod.cn>
This commit is contained in:
@@ -12,7 +12,7 @@ kernelsu-objs += feature.o
|
|||||||
kernelsu-objs += ksud.o
|
kernelsu-objs += ksud.o
|
||||||
kernelsu-objs += embed_ksud.o
|
kernelsu-objs += embed_ksud.o
|
||||||
kernelsu-objs += kernel_compat.o
|
kernelsu-objs += kernel_compat.o
|
||||||
kernelsu-objs += file_proxy.o
|
kernelsu-objs += file_wrapper.o
|
||||||
kernelsu-objs += throne_comm.o
|
kernelsu-objs += throne_comm.o
|
||||||
kernelsu-objs += sulog.o
|
kernelsu-objs += sulog.o
|
||||||
|
|
||||||
|
|||||||
@@ -1,341 +0,0 @@
|
|||||||
#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/seq_file.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
#include "file_proxy.h"
|
|
||||||
|
|
||||||
static loff_t ksu_file_proxy_llseek(struct file *fp, loff_t off, int flags) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->llseek(data->orig, off, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_file_proxy_read(struct file *fp, char __user *ptr, size_t sz, loff_t *off) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->read(orig, ptr, sz, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_file_proxy_write(struct file *fp, const char __user *ptr, size_t sz, loff_t *off) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->write(orig, ptr, sz, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_file_proxy_read_iter(struct kiocb *iocb, struct iov_iter *iovi) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_write_iter (struct kiocb *iocb, struct iov_iter *iovi) {
|
|
||||||
struct ksu_file_proxy* data = iocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
iocb->ki_filp = orig;
|
|
||||||
return orig->f_op->write_iter(iocb, iovi);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
|
||||||
static int ksu_file_proxy_iopoll(struct kiocb *kiocb, struct io_comp_batch* icb, unsigned int v) {
|
|
||||||
struct ksu_file_proxy* data = kiocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
kiocb->ki_filp = orig;
|
|
||||||
return orig->f_op->iopoll(kiocb, icb, v);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int ksu_file_proxy_iopoll(struct kiocb *kiocb, bool spin) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_iterate (struct file *fp, struct dir_context *dc) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->iterate(orig, dc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ksu_file_proxy_iterate_shared (struct file *fp, struct dir_context *dc) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->iterate_shared(orig, dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __poll_t ksu_file_proxy_poll (struct file *fp, struct poll_table_struct *pts) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->poll(orig, pts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long ksu_file_proxy_unlocked_ioctl (struct file *fp, unsigned int cmd, unsigned long arg) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->unlocked_ioctl(orig, cmd, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long ksu_file_proxy_compat_ioctl (struct file *fp, unsigned int cmd, unsigned long arg) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->compat_ioctl(orig, cmd, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_mmap (struct file *fp, struct vm_area_struct * vma) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->mmap(orig, vma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static unsigned long mmap_supported_flags {}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_open(struct inode *ino, struct file *fp) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_flush (struct file *fp, fl_owner_t id) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->flush(orig, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ksu_file_proxy_fsync(struct file *fp, loff_t off1, loff_t off2, int datasync) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->fsync(orig, off1, off2, datasync);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_fasync(int arg, struct file *fp, int arg2) {
|
|
||||||
struct ksu_file_proxy* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->fasync(arg, orig, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_lock(struct file *fp, int arg1, struct file_lock *fl) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_sendpage (struct file *fp, struct page *pg, int arg1, size_t sz, loff_t *off, int arg2) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_get_unmapped_area(struct file *fp, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_check_flags(int arg) {}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_flock(struct file *fp, int arg1, struct file_lock *fl) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_splice_write(struct pipe_inode_info * pii, struct file *fp, loff_t *off, size_t sz, unsigned int arg1) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_splice_read(struct file *fp, loff_t *off, struct pipe_inode_info *pii, size_t sz, unsigned int arg1) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_splice_eof(struct file *fp) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_setlease(struct file *fp, int arg1, struct file_lease **fl, void **p) {
|
|
||||||
struct ksu_file_proxy* 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 ksu_file_proxy_setlease(struct file *fp, int arg1, struct file_lock **fl, void **p) {
|
|
||||||
struct ksu_file_proxy* 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
|
|
||||||
static int ksu_file_proxy_setlease(struct file *fp, long arg1, struct file_lock **fl, void **p) {
|
|
||||||
struct ksu_file_proxy* 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;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static long ksu_file_proxy_fallocate(struct file *fp, int mode, loff_t offset, loff_t len) {
|
|
||||||
struct ksu_file_proxy* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ksu_file_proxy_show_fdinfo(struct seq_file *m, struct file *f) {
|
|
||||||
struct ksu_file_proxy* data = m->file->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->show_fdinfo) {
|
|
||||||
orig->f_op->show_fdinfo(m, orig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_file_proxy_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_proxy* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static loff_t ksu_file_proxy_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_proxy* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_fadvise(struct file *fp, loff_t off1, loff_t off2, int flags) {
|
|
||||||
struct ksu_file_proxy* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_file_proxy_release(struct inode *inode, struct file *filp) {
|
|
||||||
ksu_delete_file_proxy(filp->private_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ksu_file_proxy* ksu_create_file_proxy(struct file* fp) {
|
|
||||||
struct ksu_file_proxy* p = kcalloc(sizeof(struct ksu_file_proxy), 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 ? ksu_file_proxy_llseek : NULL;
|
|
||||||
p->ops.read = fp->f_op->read ? ksu_file_proxy_read : NULL;
|
|
||||||
p->ops.write = fp->f_op->write ? ksu_file_proxy_write : NULL;
|
|
||||||
p->ops.read_iter = fp->f_op->read_iter ? ksu_file_proxy_read_iter : NULL;
|
|
||||||
p->ops.write_iter = fp->f_op->write_iter ? ksu_file_proxy_write_iter : NULL;
|
|
||||||
p->ops.iopoll = fp->f_op->iopoll ? ksu_file_proxy_iopoll : NULL;
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.iterate = fp->f_op->iterate ? ksu_file_proxy_iterate : NULL;
|
|
||||||
#endif
|
|
||||||
p->ops.iterate_shared = fp->f_op->iterate_shared ? ksu_file_proxy_iterate_shared : NULL;
|
|
||||||
p->ops.poll = fp->f_op->poll ? ksu_file_proxy_poll : NULL;
|
|
||||||
p->ops.unlocked_ioctl = fp->f_op->unlocked_ioctl ? ksu_file_proxy_unlocked_ioctl : NULL;
|
|
||||||
p->ops.compat_ioctl = fp->f_op->compat_ioctl ? ksu_file_proxy_compat_ioctl : NULL;
|
|
||||||
p->ops.mmap = fp->f_op->mmap ? ksu_file_proxy_mmap : NULL;
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
|
||||||
p->ops.fop_flags = fp->f_op->fop_flags;
|
|
||||||
#else
|
|
||||||
p->ops.mmap_supported_flags = fp->f_op->mmap_supported_flags;
|
|
||||||
#endif
|
|
||||||
p->ops.open = fp->f_op->open ? ksu_file_proxy_open : NULL;
|
|
||||||
p->ops.flush = fp->f_op->flush ? ksu_file_proxy_flush : NULL;
|
|
||||||
p->ops.release = ksu_file_proxy_release;
|
|
||||||
p->ops.fsync = fp->f_op->fsync ? ksu_file_proxy_fsync : NULL;
|
|
||||||
p->ops.fasync = fp->f_op->fasync ? ksu_file_proxy_fasync : NULL;
|
|
||||||
p->ops.lock = fp->f_op->lock ? ksu_file_proxy_lock : NULL;
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.sendpage = fp->f_op->sendpage ? ksu_file_proxy_sendpage : NULL;
|
|
||||||
#endif
|
|
||||||
p->ops.get_unmapped_area = fp->f_op->get_unmapped_area ? ksu_file_proxy_get_unmapped_area : NULL;
|
|
||||||
p->ops.check_flags = fp->f_op->check_flags;
|
|
||||||
p->ops.flock = fp->f_op->flock ? ksu_file_proxy_flock : NULL;
|
|
||||||
p->ops.splice_write = fp->f_op->splice_write ? ksu_file_proxy_splice_write : NULL;
|
|
||||||
p->ops.splice_read = fp->f_op->splice_read ? ksu_file_proxy_splice_read : NULL;
|
|
||||||
p->ops.setlease = fp->f_op->setlease ? ksu_file_proxy_setlease : NULL;
|
|
||||||
p->ops.fallocate = fp->f_op->fallocate ? ksu_file_proxy_fallocate : NULL;
|
|
||||||
p->ops.show_fdinfo = fp->f_op->show_fdinfo ? ksu_file_proxy_show_fdinfo : NULL;
|
|
||||||
p->ops.copy_file_range = fp->f_op->copy_file_range ? ksu_file_proxy_copy_file_range : NULL;
|
|
||||||
p->ops.remap_file_range = fp->f_op->remap_file_range ? ksu_file_proxy_remap_file_range : NULL;
|
|
||||||
p->ops.fadvise = fp->f_op->fadvise ? ksu_file_proxy_fadvise : NULL;
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.splice_eof = fp->f_op->splice_eof ? ksu_file_proxy_splice_eof : NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_delete_file_proxy(struct ksu_file_proxy* data) {
|
|
||||||
fput((struct file*) data->orig);
|
|
||||||
kfree(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef KSU_FILE_PROXY_H
|
|
||||||
#define KSU_FILE_PROXY_H
|
|
||||||
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
|
|
||||||
struct ksu_file_proxy {
|
|
||||||
struct file* orig;
|
|
||||||
struct file_operations ops;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_file_proxy* ksu_create_file_proxy(struct file* fp);
|
|
||||||
void ksu_delete_file_proxy(struct ksu_file_proxy* data);
|
|
||||||
|
|
||||||
#endif // KSU_FILE_PROXY_H
|
|
||||||
347
kernel/file_wrapper.c
Normal file
347
kernel/file_wrapper.c
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
#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/seq_file.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"
|
||||||
|
|
||||||
|
static loff_t ksu_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 ksu_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 ksu_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ksu_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 ksu_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||||
|
static int ksu_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);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int ksu_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 ksu_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
|
||||||
|
|
||||||
|
static int ksu_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __poll_t ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_wrapper_check_flags(int arg) {}
|
||||||
|
|
||||||
|
static int ksu_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 ksu_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 ksu_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 ksu_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 ksu_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 ksu_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;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int ksu_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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static long ksu_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ksu_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ksu_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static loff_t ksu_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_wrapper_release(struct inode *inode, struct file *filp) {
|
||||||
|
ksu_delete_file_wrapper(filp->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ksu_file_wrapper* ksu_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 ? ksu_wrapper_llseek : NULL;
|
||||||
|
p->ops.read = fp->f_op->read ? ksu_wrapper_read : NULL;
|
||||||
|
p->ops.write = fp->f_op->write ? ksu_wrapper_write : NULL;
|
||||||
|
p->ops.read_iter = fp->f_op->read_iter ? ksu_wrapper_read_iter : NULL;
|
||||||
|
p->ops.write_iter = fp->f_op->write_iter ? ksu_wrapper_write_iter : NULL;
|
||||||
|
p->ops.iopoll = fp->f_op->iopoll ? ksu_wrapper_iopoll : NULL;
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||||
|
p->ops.iterate = fp->f_op->iterate ? ksu_wrapper_iterate : NULL;
|
||||||
|
#endif
|
||||||
|
p->ops.iterate_shared = fp->f_op->iterate_shared ? ksu_wrapper_iterate_shared : NULL;
|
||||||
|
p->ops.poll = fp->f_op->poll ? ksu_wrapper_poll : NULL;
|
||||||
|
p->ops.unlocked_ioctl = fp->f_op->unlocked_ioctl ? ksu_wrapper_unlocked_ioctl : NULL;
|
||||||
|
p->ops.compat_ioctl = fp->f_op->compat_ioctl ? ksu_wrapper_compat_ioctl : NULL;
|
||||||
|
p->ops.mmap = fp->f_op->mmap ? ksu_wrapper_mmap : NULL;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||||
|
p->ops.fop_flags = fp->f_op->fop_flags;
|
||||||
|
#else
|
||||||
|
p->ops.mmap_supported_flags = fp->f_op->mmap_supported_flags;
|
||||||
|
#endif
|
||||||
|
p->ops.open = fp->f_op->open ? ksu_wrapper_open : NULL;
|
||||||
|
p->ops.flush = fp->f_op->flush ? ksu_wrapper_flush : NULL;
|
||||||
|
p->ops.release = ksu_wrapper_release;
|
||||||
|
p->ops.fsync = fp->f_op->fsync ? ksu_wrapper_fsync : NULL;
|
||||||
|
p->ops.fasync = fp->f_op->fasync ? ksu_wrapper_fasync : NULL;
|
||||||
|
p->ops.lock = fp->f_op->lock ? ksu_wrapper_lock : NULL;
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||||
|
p->ops.sendpage = fp->f_op->sendpage ? ksu_wrapper_sendpage : NULL;
|
||||||
|
#endif
|
||||||
|
p->ops.get_unmapped_area = fp->f_op->get_unmapped_area ? ksu_wrapper_get_unmapped_area : NULL;
|
||||||
|
p->ops.check_flags = fp->f_op->check_flags;
|
||||||
|
p->ops.flock = fp->f_op->flock ? ksu_wrapper_flock : NULL;
|
||||||
|
p->ops.splice_write = fp->f_op->splice_write ? ksu_wrapper_splice_write : NULL;
|
||||||
|
p->ops.splice_read = fp->f_op->splice_read ? ksu_wrapper_splice_read : NULL;
|
||||||
|
p->ops.setlease = fp->f_op->setlease ? ksu_wrapper_setlease : NULL;
|
||||||
|
p->ops.fallocate = fp->f_op->fallocate ? ksu_wrapper_fallocate : NULL;
|
||||||
|
p->ops.show_fdinfo = fp->f_op->show_fdinfo ? ksu_wrapper_show_fdinfo : NULL;
|
||||||
|
p->ops.copy_file_range = fp->f_op->copy_file_range ? ksu_wrapper_copy_file_range : NULL;
|
||||||
|
p->ops.remap_file_range = fp->f_op->remap_file_range ? ksu_wrapper_remap_file_range : NULL;
|
||||||
|
p->ops.fadvise = fp->f_op->fadvise ? ksu_wrapper_fadvise : NULL;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
||||||
|
p->ops.splice_eof = fp->f_op->splice_eof ? ksu_wrapper_splice_eof : NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_delete_file_wrapper(struct ksu_file_wrapper* data) {
|
||||||
|
fput((struct file*) data->orig);
|
||||||
|
kfree(data);
|
||||||
|
}
|
||||||
14
kernel/file_wrapper.h
Normal file
14
kernel/file_wrapper.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef KSU_FILE_WRAPPER_H
|
||||||
|
#define KSU_FILE_WRAPPER_H
|
||||||
|
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
struct ksu_file_wrapper {
|
||||||
|
struct file* orig;
|
||||||
|
struct file_operations ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp);
|
||||||
|
void ksu_delete_file_wrapper(struct ksu_file_wrapper* data);
|
||||||
|
#endif // KSU_FILE_WRAPPER_H
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
#include "core_hook.h"
|
#include "core_hook.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
#include "file_proxy.h"
|
#include "file_wrapper.h"
|
||||||
#include "kernel_compat.h"
|
#include "kernel_compat.h"
|
||||||
#include "throne_comm.h"
|
#include "throne_comm.h"
|
||||||
#include "dynamic_manager.h"
|
#include "dynamic_manager.h"
|
||||||
@@ -358,62 +358,56 @@ static int do_set_feature(void __user *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_proxy_file(void __user *arg) {
|
static int do_get_wrapper_fd(void __user *arg) {
|
||||||
if (!ksu_file_sid) {
|
if (!ksu_file_sid) {
|
||||||
return -EBUSY;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ksu_proxy_file_cmd cmd;
|
struct ksu_get_wrapper_fd_cmd cmd;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||||
pr_err("do_proxy_file: copy_from_user failed\n");
|
pr_err("get_wrapper_fd: copy_from_user failed\n");
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file* f = fget(cmd.fd);
|
struct file* f = fget(cmd.fd);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ksu_file_proxy *data = ksu_create_file_proxy(f);
|
struct ksu_file_wrapper *data = ksu_create_file_wrapper(f);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto put_orig_file;
|
goto put_orig_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file* pf = anon_inode_getfile("[ksu_file_proxy]", &data->ops, data, f->f_flags);
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||||
if (IS_ERR(pf)) {
|
#define getfd_secure anon_inode_create_getfd
|
||||||
ret = PTR_ERR(pf);
|
#else
|
||||||
pr_err("do_proxy_file: anon_inode_getfile failed: %ld\n", PTR_ERR(pf));
|
#define getfd_secure anon_inode_getfd_secure
|
||||||
goto put_proxy_data;
|
#endif
|
||||||
|
ret = getfd_secure("[ksu_fdwrapper]", &data->ops, data, f->f_flags, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("ksu_fdwrapper: getfd failed: %d\n", ret);
|
||||||
|
goto put_wrapper_data;
|
||||||
}
|
}
|
||||||
|
struct file* pf = fget(ret);
|
||||||
|
|
||||||
struct inode* proxy_inode = file_inode(pf);
|
struct inode* wrapper_inode = file_inode(pf);
|
||||||
struct inode_security_struct *sec = selinux_inode(proxy_inode);
|
struct inode_security_struct *sec = selinux_inode(wrapper_inode);
|
||||||
if (sec) {
|
if (sec) {
|
||||||
sec->sid = ksu_file_sid;
|
sec->sid = ksu_file_sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = get_unused_fd_flags(cmd.flags);
|
fput(pf);
|
||||||
if (ret < 0) {
|
|
||||||
pr_err("do_proxy_file: get unused fd failed: %d\n", ret);
|
|
||||||
goto put_proxy_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pr_info("do_proxy_file: installed proxy 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;
|
goto put_orig_file;
|
||||||
|
put_wrapper_data:
|
||||||
put_proxy_file:
|
ksu_delete_file_wrapper(data);
|
||||||
fput(pf);
|
|
||||||
put_proxy_data:
|
|
||||||
ksu_delete_file_proxy(data);
|
|
||||||
put_orig_file:
|
put_orig_file:
|
||||||
fput(f);
|
fput(f);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 100. GET_FULL_VERSION - Get full version string
|
// 100. GET_FULL_VERSION - Get full version string
|
||||||
@@ -662,7 +656,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_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_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_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root },
|
||||||
{ .cmd = KSU_IOCTL_PROXY_FILE, .name = "PROXY_FILE", .handler = do_proxy_file, .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_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_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},
|
{ .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root},
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ struct ksu_set_feature_cmd {
|
|||||||
__u64 value; // Input: feature value/state to set
|
__u64 value; // Input: feature value/state to set
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ksu_proxy_file_cmd {
|
struct ksu_get_wrapper_fd_cmd {
|
||||||
__u32 fd;
|
__u32 fd; // Input: userspace fd
|
||||||
__u32 flags; // CLOEXEC
|
__u32 flags; // Input: flags of userspace fd
|
||||||
};
|
};
|
||||||
|
|
||||||
// Other command structures
|
// Other command structures
|
||||||
@@ -133,7 +133,7 @@ struct ksu_manual_su_cmd {
|
|||||||
#define KSU_IOCTL_SET_APP_PROFILE _IOC(_IOC_WRITE, 'K', 12, 0)
|
#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_GET_FEATURE _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
||||||
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||||
#define KSU_IOCTL_PROXY_FILE _IOC(_IOC_NONE, 'K', 15, 0)
|
#define KSU_IOCTL_GET_WRAPPER_FD _IOC(_IOC_WRITE, 'K', 15, 0)
|
||||||
// Other IOCTL command definitions
|
// Other IOCTL command definitions
|
||||||
#define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0)
|
#define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0)
|
||||||
#define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)
|
#define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const KSU_IOCTL_SET_SEPOLICY: u32 = 0xc0004b04; // _IOC(_IOC_READ|_IOC_WRITE, 'K
|
|||||||
const KSU_IOCTL_CHECK_SAFEMODE: u32 = 0x80004b05; // _IOC(_IOC_READ, 'K', 5, 0)
|
const KSU_IOCTL_CHECK_SAFEMODE: u32 = 0x80004b05; // _IOC(_IOC_READ, 'K', 5, 0)
|
||||||
const KSU_IOCTL_GET_FEATURE: u32 = 0xc0004b0d; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
const KSU_IOCTL_GET_FEATURE: u32 = 0xc0004b0d; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
||||||
const KSU_IOCTL_SET_FEATURE: u32 = 0x40004b0e; // _IOC(_IOC_WRITE, 'K', 14, 0)
|
const KSU_IOCTL_SET_FEATURE: u32 = 0x40004b0e; // _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||||
const KSU_IOCTL_PROXY_FILE: u32 = 0x00004b0f; // _IOC(_IOC_NONE, 'K', 15, 0)
|
const KSU_IOCTL_GET_WRAPPER_FD: u32 = 0x40004b0f; // _IOC(_IOC_WRITE, 'K', 15, 0)
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const KSU_IOCTL_KPM: u32 = 0xc0004bc8; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0)
|
const KSU_IOCTL_KPM: u32 = 0xc0004bc8; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0)
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -63,7 +63,7 @@ struct SetFeatureCmd {
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
struct ProxyFileCmd {
|
struct GetWrapperFdCmd {
|
||||||
fd: i32,
|
fd: i32,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
}
|
}
|
||||||
@@ -233,9 +233,10 @@ pub fn set_feature(feature_id: u32, value: u64) -> std::io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proxy_file(fd: RawFd) -> std::io::Result<RawFd> {
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
let mut cmd = ProxyFileCmd { fd, flags: 0 };
|
pub fn get_wrapped_fd(fd: RawFd) -> std::io::Result<RawFd> {
|
||||||
let result = ksuctl(KSU_IOCTL_PROXY_FILE, &mut cmd as *mut _)?;
|
let mut cmd = GetWrapperFdCmd { fd, flags: 0 };
|
||||||
|
let result = ksuctl(KSU_IOCTL_GET_WRAPPER_FD, &mut cmd as *mut _)?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
defs,
|
defs,
|
||||||
ksucalls::proxy_file,
|
|
||||||
utils::{self, umask},
|
utils::{self, umask},
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Ok, Result, bail};
|
use anyhow::{Context, Ok, Result, bail};
|
||||||
@@ -11,6 +10,9 @@ use log::{error, warn};
|
|||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
use std::{env, ffi::CStr, path::PathBuf, process::Command};
|
use std::{env, ffi::CStr, path::PathBuf, process::Command};
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
use crate::ksucalls::get_wrapped_fd;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use rustix::{
|
use rustix::{
|
||||||
process::getuid,
|
process::getuid,
|
||||||
@@ -71,7 +73,7 @@ fn wrap_tty(fd: c_int) {
|
|||||||
warn!("not a tty: {fd}");
|
warn!("not a tty: {fd}");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let new_fd = proxy_file(fd).context("proxy_file")?;
|
let new_fd = get_wrapped_fd(fd).context("get_wrapped_fd")?;
|
||||||
if unsafe { libc::dup2(new_fd, fd) } == -1 {
|
if unsafe { libc::dup2(new_fd, fd) } == -1 {
|
||||||
bail!("dup {new_fd} -> {fd} errno: {}", unsafe {
|
bail!("dup {new_fd} -> {fd} errno: {}", unsafe {
|
||||||
*libc::__errno()
|
*libc::__errno()
|
||||||
@@ -147,6 +149,7 @@ pub fn root_shell() -> Result<()> {
|
|||||||
"Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified.",
|
"Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified.",
|
||||||
"GROUP",
|
"GROUP",
|
||||||
);
|
);
|
||||||
|
opts.optflag("W", "no-wrapper", "don't use ksu fd wrapper");
|
||||||
|
|
||||||
// Replace -cn with -z, -mm with -M for supporting getopt_long
|
// Replace -cn with -z, -mm with -M for supporting getopt_long
|
||||||
let args = args
|
let args = args
|
||||||
@@ -190,6 +193,7 @@ pub fn root_shell() -> Result<()> {
|
|||||||
let mut is_login = matches.opt_present("l");
|
let mut is_login = matches.opt_present("l");
|
||||||
let preserve_env = matches.opt_present("p");
|
let preserve_env = matches.opt_present("p");
|
||||||
let mount_master = matches.opt_present("M");
|
let mount_master = matches.opt_present("M");
|
||||||
|
let use_fd_wrapper = !matches.opt_present("W");
|
||||||
|
|
||||||
let groups = matches
|
let groups = matches
|
||||||
.opt_strs("G")
|
.opt_strs("G")
|
||||||
@@ -289,7 +293,7 @@ pub fn root_shell() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
if true {
|
if use_fd_wrapper {
|
||||||
wrap_tty(0);
|
wrap_tty(0);
|
||||||
wrap_tty(1);
|
wrap_tty(1);
|
||||||
wrap_tty(2);
|
wrap_tty(2);
|
||||||
|
|||||||
Reference in New Issue
Block a user