diff --git a/kernel/Makefile b/kernel/Makefile index 701a9e02..7622754c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -11,7 +11,7 @@ kernelsu-objs += ksud.o kernelsu-objs += embed_ksud.o kernelsu-objs += kernel_compat.o kernelsu-objs += throne_tracker.o -kernelsu-objs += file_wrapper.o +kernelsu-objs += file_proxy.o kernelsu-objs += throne_comm.o kernelsu-objs += sulog.o diff --git a/kernel/file_proxy.c b/kernel/file_proxy.c new file mode 100644 index 00000000..85f61fee --- /dev/null +++ b/kernel/file_proxy.c @@ -0,0 +1,373 @@ +#include "linux/export.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(5, 0, 0) +#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 +#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; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) +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; +} +#else +static int ksu_wrapper_clone_file_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, u64 len) { + // TODO: determine which file to use + struct ksu_file_wrapper* data = file_in->private_data; + struct file* orig = data->orig; + if (orig->f_op->clone_file_range) { + return orig->f_op->clone_file_range(orig, pos_in, file_out, pos_out, len); + } + return -EINVAL; +} + +static ssize_t ksu_wrapper_dedupe_file_range(struct file *src_file, u64 loff, + u64 len, struct file *dst_file, u64 dst_loff) { + // TODO: determine which file to use + struct ksu_file_wrapper* data = src_file->private_data; + struct file* orig = data->orig; + if (orig->f_op->dedupe_file_range) { + return orig->f_op->dedupe_file_range(orig, loff, len, dst_file, dst_loff); + } + return -EINVAL; +} +#endif + +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; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) + p->ops.iopoll = fp->f_op->iopoll ? ksu_file_proxy_iopoll : NULL; +#endif +#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; +#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 ? 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; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) + 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; +#else + p->ops.clone_file_range = fp->f_op->clone_file_range ? ksu_wrapper_clone_file_range : NULL; + p->ops.dedupe_file_range = fp->f_op->dedupe_file_range ? ksu_wrapper_dedupe_file_range : NULL; +#endif + +#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); +} + diff --git a/kernel/file_wrapper.h b/kernel/file_proxy.h similarity index 54% rename from kernel/file_wrapper.h rename to kernel/file_proxy.h index 7a97226d..0e719193 100644 --- a/kernel/file_wrapper.h +++ b/kernel/file_proxy.h @@ -5,10 +5,10 @@ typedef unsigned int __poll_t; #endif -struct ksu_file_wrapper { +struct ksu_file_proxy { 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); +struct ksu_file_proxy* ksu_create_file_proxy(struct file* fp); +void ksu_delete_file_proxy(struct ksu_file_proxy* data); diff --git a/kernel/file_wrapper.c b/kernel/file_wrapper.c deleted file mode 100644 index da224587..00000000 --- a/kernel/file_wrapper.c +++ /dev/null @@ -1,380 +0,0 @@ -#include "linux/export.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 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); -} - -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); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) -#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); -} -#else -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 -#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 - -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); -} - -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; -} -#else -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; -} -#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; -} - -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); - } -} - -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; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 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; -} - -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; -} -#else -static int mksu_wrapper_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = file_in->private_data; - struct file* orig = data->orig; - if (orig->f_op->clone_file_range) { - return orig->f_op->clone_file_range(orig, pos_in, file_out, pos_out, len); - } - return -EINVAL; -} - -static ssize_t mksu_wrapper_dedupe_file_range(struct file *src_file, u64 loff, - u64 len, struct file *dst_file, u64 dst_loff) { - // TODO: determine which file to use - struct ksu_file_wrapper* data = src_file->private_data; - struct file* orig = data->orig; - if (orig->f_op->dedupe_file_range) { - return orig->f_op->dedupe_file_range(orig, loff, len, dst_file, dst_loff); - } - 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; - 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; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 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 - p->ops.iterate_shared = fp->f_op->iterate_shared ? mksu_wrapper_iterate_shared : NULL; - 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; - p->ops.copy_file_range = fp->f_op->copy_file_range ? mksu_wrapper_copy_file_range : NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) - p->ops.remap_file_range = fp->f_op->remap_file_range ? mksu_wrapper_remap_file_range : NULL; - p->ops.fadvise = fp->f_op->fadvise ? mksu_wrapper_fadvise : NULL; -#else - p->ops.clone_file_range = fp->f_op->clone_file_range ? mksu_wrapper_clone_file_range : NULL; - p->ops.dedupe_file_range = fp->f_op->dedupe_file_range ? mksu_wrapper_dedupe_file_range : 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); -} - diff --git a/kernel/ksu.h b/kernel/ksu.h index 96567a93..f589cbe9 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -25,7 +25,7 @@ extern bool ksu_uid_scanner_enabled; #define CMD_IS_SU_ENABLED 14 #define CMD_ENABLE_SU 15 #define CMD_GET_MANAGER_UID 16 -#define CMD_GET_WRAPPER_FD 10000 +#define CMD_GET_FILE_PROXY_FD 10000 #define EVENT_POST_FS_DATA 1 #define EVENT_BOOT_COMPLETED 2 diff --git a/kernel/supercalls.c b/kernel/supercalls.c index 91762be2..d933b8a6 100644 --- a/kernel/supercalls.c +++ b/kernel/supercalls.c @@ -19,7 +19,7 @@ #include "selinux/selinux.h" #include "core_hook.h" #include "objsec.h" -#include "file_wrapper.h" +#include "file_proxy.h" #include "kernel_compat.h" #include "throne_comm.h" #include "dynamic_manager.h" @@ -357,16 +357,16 @@ static int do_set_feature(void __user *arg) return 0; } -static int do_get_wrapper_fd(void __user *arg) { +static int do_proxy_file(void __user *arg) { if (!ksu_file_sid) { - return -1; + return -EBUSY; } - struct ksu_get_wrapper_fd_cmd cmd; + struct ksu_proxy_file_cmd cmd; int ret; if (copy_from_user(&cmd, arg, sizeof(cmd))) { - pr_err("get_wrapper_fd: copy_from_user failed\n"); + pr_err("do_proxy_file: copy_from_user failed\n"); return -EFAULT; } @@ -375,40 +375,40 @@ static int do_get_wrapper_fd(void __user *arg) { return -EBADF; } - struct ksu_file_wrapper *data = mksu_create_file_wrapper(f); + struct ksu_file_proxy *data = ksu_create_file_proxy(f); if (data == NULL) { ret = -ENOMEM; goto put_orig_file; } - struct file* pf = anon_inode_getfile("[mksu_fdwrapper]", &data->ops, data, f->f_flags); + struct file* pf = anon_inode_getfile("[ksu_file_proxy]", &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; + pr_err("do_proxy_file: anon_inode_getfile failed: %ld\n", PTR_ERR(pf)); + goto put_proxy_data; } - struct inode* wrapper_inode = file_inode(pf); - struct inode_security_struct *sec = selinux_inode(wrapper_inode); + struct inode* proxy_inode = file_inode(pf); + struct inode_security_struct *sec = selinux_inode(proxy_inode); 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_err("do_proxy_file: get unused fd failed: %d\n", ret); + goto put_proxy_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); + // 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; - -put_wrapper_file: + +put_proxy_file: fput(pf); -put_wrapper_data: - mksu_delete_file_wrapper(data); +put_proxy_data: + ksu_delete_file_proxy(data); put_orig_file: fput(f); @@ -632,7 +632,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_PROXY_FILE, .name = "PROXY_FILE", .handler = do_proxy_file, .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}, diff --git a/kernel/supercalls.h b/kernel/supercalls.h index 5e1bbeaf..66ab3bcb 100644 --- a/kernel/supercalls.h +++ b/kernel/supercalls.h @@ -77,7 +77,7 @@ struct ksu_set_feature_cmd { __u64 value; // Input: feature value/state to set }; -struct ksu_get_wrapper_fd_cmd { +struct ksu_proxy_file_cmd { __u32 fd; __u32 flags; // CLOEXEC }; @@ -133,7 +133,7 @@ struct ksu_manual_su_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) +#define KSU_IOCTL_PROXY_FILE _IOC(_IOC_NONE, 'K', 15, 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)