Compare commits

...
Author SHA1 Message Date
Nicholas Andrew
543775015a sm6375: enable KernelSU-Next SUSFS in common Lineage config 2026-09-19 19:42:15 -04:00
Nicholas Andrew
b95186ce17 milanf: drop redundant KPROBE_EVENTS override 2026-09-19 17:59:03 -04:00
Nicholas Andrew
676d5d17df susfs: fix try_umount path reference lifetime 2026-09-19 00:45:44 -04:00
Nicholas Andrew
d622d068b8 susfs: preserve pathname for metadata-only maps spoofing 2026-09-19 00:22:31 -04:00
Nicholas Andrew
14cfb1b990 fs: add KernelSU umount compatibility helpers 2026-09-18 19:56:56 -04:00
Nicholas Andrew
c3c71b8ff6 milanf: add KernelSU-Next SUSFS support
KernelSU-Next commit: 9635f39b43792a448fc58f97d6d63b89b083a7e0
2026-09-18 19:55:23 -04:00
Nicholas Andrew
662196de01 milanf: integrate KernelSU-Next with manual hooks 2026-09-18 19:45:36 -04:00
22 changed files with 2191 additions and 3 deletions

View file

@ -48,3 +48,20 @@ CONFIG_QCA_CLD_WLAN=m
# ZRAM
CONFIG_ZRAM_WRITEBACK=y
# KernelSU-Next
CONFIG_KSU=y
CONFIG_KSU_MANUAL_HOOK=y
# KernelSU-Next SUSFS
CONFIG_KSU_SUSFS=y
CONFIG_KSU_SUSFS_SUS_PATH=y
CONFIG_KSU_SUSFS_SUS_MOUNT=y
# CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER is not set
CONFIG_KSU_SUSFS_SUS_KSTAT=y
CONFIG_KSU_SUSFS_SUS_MAPS=y
# CONFIG_KSU_SUSFS_SUS_PROC_FD_LINK is not set
# CONFIG_KSU_SUSFS_SUS_MEMFD is not set
CONFIG_KSU_SUSFS_TRY_UMOUNT=y
CONFIG_KSU_SUSFS_SPOOF_UNAME=y
CONFIG_KSU_SUSFS_ENABLE_LOG=y

View file

@ -244,4 +244,5 @@ source "drivers/mmi_relay/Kconfig"
source "drivers/sensors/Kconfig"
source "drivers/kernelsu/Kconfig"
endmenu

View file

@ -194,3 +194,5 @@ obj-$(CONFIG_MMI_ANNOTATE) += mmi_annotate/
obj-$(CONFIG_MMI_INFO) += mmi_info/
obj-$(CONFIG_MMI_RELAY) += mmi_relay/
obj-$(CONFIG_SENSORS_CLASS) += sensors/
obj-$(CONFIG_KSU) += kernelsu/

View file

@ -375,10 +375,21 @@ static int input_get_disposition(struct input_dev *dev,
return disposition;
}
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_input_handle_event(unsigned int *type,
unsigned int *code,
int *value);
#endif
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = input_get_disposition(dev, type, code, &value);
int disposition;
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_input_handle_event(&type, &code, &value);
#endif
disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);

1
drivers/kernelsu Symbolic link
View file

@ -0,0 +1 @@
../KernelSU-Next/kernel

View file

@ -14,8 +14,11 @@ obj-y := open.o read_write.o file_table.o super.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o splice.o sync.o utimes.o d_path.o \
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
fs_types.o fs_context.o fs_parser.o fsopen.o
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
obj-$(CONFIG_KSU_SUSFS) += susfs.o
obj-y += fs_types.o fs_context.o fs_parser.o fsopen.o
ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o

View file

@ -1904,11 +1904,19 @@ out_ret:
return retval;
}
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags);
#endif
static int do_execveat_common(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
#endif
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
}

View file

@ -90,6 +90,11 @@ extern int __mnt_want_write_file(struct file *);
extern void __mnt_drop_write_file(struct file *);
extern void dissolve_on_fput(struct vfsmount *);
#ifdef CONFIG_KSU_SUSFS
int path_umount(struct path *path, int flags);
#endif
/*
* fs_struct.c
*/

View file

@ -46,6 +46,10 @@
#define CREATE_TRACE_POINTS
#include <trace/events/namei.h>
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
/* [Feb-1997 T. Schoebel-Theuer]
* Fundamental changes in the pathname lookup mechanisms (namei)
* were necessary because of omirr. The reason is that omirr needs
@ -3709,6 +3713,13 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
int flags = op->lookup_flags;
struct file *filp;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
int error;
if (susfs_sus_path_by_filename(pathname, &error, SYSCALL_FAMILY_ALL_ENOENT)) {
return ERR_PTR(error);
}
#endif
set_nameidata(&nd, dfd, pathname);
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
if (unlikely(filp == ERR_PTR(-ECHILD)))
@ -3897,6 +3908,19 @@ long do_mknodat(int dfd, const char __user *filename, umode_t mode,
int error;
unsigned int lookup_flags = 0;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(filename);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_MKNOD);
putname_safe(fname);
if (status) {
return error;
}
#endif
error = may_mknod(mode);
if (error)
return error;
@ -3976,6 +4000,19 @@ long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
int error;
unsigned int lookup_flags = LOOKUP_DIRECTORY;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(pathname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_MKDIRAT);
putname_safe(fname);
if (status) {
return error;
}
#endif
retry:
dentry = user_path_create(dfd, pathname, &path, lookup_flags);
if (IS_ERR(dentry))
@ -4051,6 +4088,21 @@ long do_rmdir(int dfd, const char __user *pathname)
struct qstr last;
int type;
unsigned int lookup_flags = 0;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(pathname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_RMDIR);
putname_safe(fname);
if (status) {
return error;
}
error = 0;
#endif
retry:
name = filename_parentat(dfd, getname(pathname), lookup_flags,
&path, &last, &type);
@ -4182,6 +4234,17 @@ long do_unlinkat(int dfd, struct filename *name)
struct inode *inode = NULL;
struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
int status;
status = susfs_sus_path_by_filename(name, &error, SYSCALL_FAMILY_UNLINKAT);
if (status) {
return error;
}
#endif
retry:
name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
if (IS_ERR(name))
@ -4289,6 +4352,19 @@ long do_symlinkat(const char __user *oldname, int newdfd,
struct path path;
unsigned int lookup_flags = 0;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(newname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_SYMLINKAT_NEWNAME);
putname_safe(fname);
if (status) {
return error;
}
#endif
from = getname(oldname);
if (IS_ERR(from))
return PTR_ERR(from);
@ -4420,6 +4496,27 @@ int do_linkat(int olddfd, const char __user *oldname, int newdfd,
int how = 0;
int error;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(oldname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_LINKAT_OLDNAME);
putname_safe(fname);
if (status) {
return error;
}
fname = getname_safe(newname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_LINKAT_NEWNAME);
putname_safe(fname);
if (status) {
return error;
}
#endif
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;
/*
@ -4702,6 +4799,27 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
bool should_retry = false;
int error;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(oldname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_RENAMEAT2_OLDNAME);
putname_safe(fname);
if (status) {
return error;
}
fname = getname_safe(newname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_RENAMEAT2_NEWNAME);
putname_safe(fname);
if (status) {
return error;
}
#endif
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;

View file

@ -1756,6 +1756,43 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
#endif
static int can_umount(const struct path *path, int flags)
{
struct mount *mnt = real_mount(path->mnt);
if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
return -EINVAL;
if (!may_mount())
return -EPERM;
if (path->dentry != path->mnt->mnt_root)
return -EINVAL;
if (!check_mnt(mnt))
return -EINVAL;
if (mnt->mnt.mnt_flags & MNT_LOCKED)
return -EINVAL;
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
int path_umount(struct path *path, int flags)
{
struct mount *mnt = real_mount(path->mnt);
int ret;
ret = can_umount(path, flags);
if (!ret)
ret = do_umount(mnt, flags);
dput(path->dentry);
mntput_no_expire(mnt);
return ret;
}
static bool is_mnt_ns_file(struct dentry *dentry)
{
/* Is this a proxy for a mount namespace? */

View file

@ -35,6 +35,10 @@
#include "internal.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
struct file *filp)
{
@ -123,6 +127,18 @@ long do_sys_truncate(const char __user *pathname, loff_t length)
unsigned int lookup_flags = LOOKUP_FOLLOW;
struct path path;
int error;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(pathname);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_ALL_ENOENT);
putname_safe(fname);
if (status) {
return error;
}
#endif
if (length < 0) /* sorry, but loff_t says... */
return -EINVAL;
@ -345,6 +361,12 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
* We do this by temporarily clearing all FS-related capabilities and
* switching the fsuid/fsgid around to the real ones.
*/
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_faccessat(int *dfd,
const char __user **filename_user,
int *mode, int *flags);
#endif
long do_faccessat(int dfd, const char __user *filename, int mode)
{
const struct cred *old_cred;
@ -354,6 +376,26 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename *fname;
int status;
int error;
#endif
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
fname = getname_safe(filename);
status = susfs_sus_path_by_filename(fname, &error,
SYSCALL_FAMILY_ALL_ENOENT);
putname_safe(fname);
if (status)
return error;
#endif
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
@ -455,6 +497,20 @@ int ksys_chdir(const char __user *filename)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
struct filename* fname;
int status;
fname = getname_safe(filename);
status = susfs_sus_path_by_filename(fname, &error, SYSCALL_FAMILY_ALL_ENOENT);
putname_safe(fname);
if (status) {
return error;
}
#endif
retry:
error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
if (error)

View file

@ -103,6 +103,10 @@
#include "../../lib/kstrtox.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
/* NOTE:
* Implementing inode permission operations in /proc is almost
* certainly an error. Permission checks need to happen during
@ -1793,6 +1797,15 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen)
char *pathname;
int len;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
struct mm_struct *mm;
struct vm_area_struct *vma;
struct file *vma_file;
struct dentry *vma_dentry;
struct inode *vma_inode;
unsigned long ino;
#endif
if (!tmp)
return -ENOMEM;
@ -1804,6 +1817,39 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen)
if (len > buflen)
len = buflen;
#ifdef CONFIG_KSU_SUSFS_SUS_PROC_FD_LINK
if (!susfs_is_sus_proc_fd_link_list_empty()) {
if (susfs_sus_proc_fd_link(pathname, len))
goto orig_flow;
}
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
if (!susfs_is_sus_maps_list_empty()) {
mm = current->mm;
down_read(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
if (vma->vm_file) {
vma_file = vma->vm_file;
vma_dentry = vma_file->f_path.dentry;
if (vma_dentry == path->dentry) {
vma_inode = file_inode(vma_file);
ino = vma_inode->i_ino;
susfs_sus_map_files_readlink(ino, pathname);
break;
}
}
}
up_read(&mm->mmap_sem);
}
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_PROC_FD_LINK
orig_flow:
#endif
if (copy_to_user(buffer, pathname, len))
len = -EFAULT;
out:
@ -2208,6 +2254,9 @@ struct map_files_info {
unsigned long start;
unsigned long end;
fmode_t mode;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
int susfs_action;
#endif
};
/*
@ -2268,6 +2317,10 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
struct dentry *result;
struct mm_struct *mm;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
int ret = 0;
#endif
result = ERR_PTR(-ENOENT);
task = get_proc_task(dir);
if (!task)
@ -2294,6 +2347,23 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
if (!vma)
goto out_no_vma;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
if (vma->vm_file) {
ret = susfs_sus_map_files_instantiate(vma);
if (ret == 1) {
if (vma->vm_file->f_mode & FMODE_WRITE) {
vma->vm_file->f_mode &= ~FMODE_WRITE;
}
goto orig_flow;
}
if (ret == 2) {
result = ERR_PTR(-ENOENT);
goto out_no_vma;
}
}
orig_flow:
#endif
if (vma->vm_file)
result = proc_map_files_instantiate(dentry, task,
(void *)(unsigned long)vma->vm_file->f_mode);
@ -2379,6 +2449,10 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
p->start = vma->vm_start;
p->end = VMA_PAD_START(vma);
p->mode = vma->vm_file->f_mode;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
p->susfs_action = susfs_sus_map_files_instantiate(vma);
#endif
}
up_read(&mm->mmap_sem);
mmput(mm);
@ -2389,12 +2463,28 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
p = genradix_ptr(&fa, i);
len = snprintf(buf, sizeof(buf), "%lx-%lx", p->start, p->end);
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
if (p->susfs_action == SUSFS_MAP_FILES_ACTION_REMOVE_WRITE_PERM) {
if (p->mode & FMODE_WRITE) {
p->mode &= ~FMODE_WRITE;
}
} else if (p->susfs_action == SUSFS_MAP_FILES_ACTION_HIDE_DENTRY) {
goto skip_proc_fill_cache;
}
#endif
if (!proc_fill_cache(file, ctx,
buf, len,
proc_map_files_instantiate,
task,
(void *)(unsigned long)p->mode))
break;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
skip_proc_fill_cache:
#endif
ctx->pos++;
}

View file

@ -28,6 +28,10 @@
#include <asm/tlbflush.h>
#include "internal.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
#define SEQ_PUT_DEC(str, val) \
seq_put_decimal_ull_width(m, str, (val) << (PAGE_SHIFT-10), 8)
void task_mem(struct seq_file *m, struct mm_struct *mm)
@ -360,6 +364,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
unsigned long start, end;
dev_t dev = 0;
const char *name = NULL;
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
char *out_name = NULL;
int ret = 0;
#endif
if (file) {
struct inode *inode = file_inode(vma->vm_file);
@ -370,8 +378,32 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
start = vma->vm_start;
end = VMA_PAD_START(vma);
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
out_name = kmalloc(SUSFS_MAX_LEN_PATHNAME, GFP_KERNEL);
if (!out_name)
goto orig_flow;
ret = susfs_sus_maps(ino, vma->vm_end - vma->vm_start,
&ino, &dev, &flags, &pgoff, vma, out_name);
orig_flow:
#endif
show_vma_header_prefix(m, start, end, flags, pgoff, dev, ino);
#ifdef CONFIG_KSU_SUSFS_SUS_MAPS
if (ret == 2) {
seq_pad(m, ' ');
seq_puts(m, out_name);
seq_putc(m, '\n');
kfree(out_name);
return;
}
kfree(out_name);
#endif
/*
* Print the dentry name for named mappings, and a
* special [heap] marker for the heap:

View file

@ -18,6 +18,10 @@
#include "pnode.h"
#include "internal.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
static __poll_t mounts_poll(struct file *file, poll_table *wait)
{
struct seq_file *m = file->private_data;
@ -102,6 +106,11 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
struct super_block *sb = mnt_path.dentry->d_sb;
int err;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
if (susfs_sus_mount(mnt, &p->root))
return 0;
#endif
if (sb->s_op->show_devname) {
err = sb->s_op->show_devname(m, mnt_path.dentry);
if (err)
@ -138,8 +147,31 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
int err;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
int out_mnt_id = 0, out_parent_mnt_id = 0;
int status = 1;
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
if (susfs_sus_mount(mnt, &p->root))
return 0;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
if (!uid_matches_proc_need_to_reorder_mnt_id())
goto orig_flow;
status = susfs_get_fake_mnt_id(r->mnt_id, &out_mnt_id, &out_parent_mnt_id);
if (status)
goto orig_flow;
seq_printf(m, "%i %i %u:%u ", out_mnt_id, out_parent_mnt_id,
MAJOR(sb->s_dev), MINOR(sb->s_dev));
goto bypass_orig_flow;
orig_flow:
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
MAJOR(sb->s_dev), MINOR(sb->s_dev));
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
bypass_orig_flow:
#endif
if (sb->s_op->show_path) {
err = sb->s_op->show_path(m, mnt->mnt_root);
if (err)
@ -202,6 +234,11 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
struct super_block *sb = mnt_path.dentry->d_sb;
int err;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
if (susfs_sus_mount(mnt, &p->root))
return 0;
#endif
/* device */
if (sb->s_op->show_devname) {
seq_puts(m, "device ");
@ -285,6 +322,12 @@ static int mounts_open_common(struct inode *inode, struct file *file,
p->show = show;
p->cached_event = ~0ULL;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
if (uid_matches_proc_need_to_reorder_mnt_id()) {
susfs_add_mnt_id_recorder(p->ns);
}
#endif
return 0;
err_put_path:
@ -299,6 +342,13 @@ static int mounts_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
struct proc_mounts *p = m->private;
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT_MNT_ID_REORDER
if (uid_matches_proc_need_to_reorder_mnt_id()) {
susfs_remove_mnt_id_recorder();
}
#endif
path_put(&p->root);
put_mnt_ns(p->ns);
return seq_release_private(inode, file);

View file

@ -443,10 +443,20 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
}
EXPORT_SYMBOL_NS(kernel_read, ANDROID_GKI_VFS_EXPORT_ONLY);
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_vfs_read(struct file **file_ptr,
char __user **buf_ptr,
size_t *count_ptr, loff_t **pos);
#endif
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_vfs_read(&file, &buf, &count, &pos);
#endif
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))

View file

@ -22,6 +22,10 @@
#include <linux/compat.h>
#include <linux/uaccess.h>
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
#include <asm/unaligned.h>
/*
@ -328,6 +332,11 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
prev_reclen = buf->prev_reclen;
if (prev_reclen && signal_pending(current))
return -EINTR;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
if (susfs_sus_ino_for_filldir64(ino)) {
return 0;
}
#endif
dirent = buf->current_dir;
prev = (void __user *)dirent - prev_reclen;
if (!user_access_begin(prev, reclen + prev_reclen))

View file

@ -21,6 +21,10 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
/**
* generic_fillattr - Fill in the basic attributes from the inode struct
* @inode: Inode to use as the source
@ -112,6 +116,12 @@ int vfs_getattr(const struct path *path, struct kstat *stat,
{
int retval;
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
if (susfs_sus_path_by_path(path, &retval, SYSCALL_FAMILY_ALL_ENOENT)) {
return retval;
}
#endif
retval = security_inode_getattr(path);
if (retval)
return retval;
@ -165,6 +175,18 @@ EXPORT_SYMBOL(vfs_statx_fd);
*
* 0 will be returned on success, and a -ve error code if unsuccessful.
*/
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_stat(int *dfd,
const char __user **filename_user,
int *flags);
extern void ksu_handle_newfstat_ret(unsigned int *fd,
struct stat __user **statbuf_ptr);
#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64)
extern void ksu_handle_fstat64_ret(unsigned long *fd,
struct stat64 __user **statbuf_ptr);
#endif
#endif
int vfs_statx(int dfd, const char __user *filename, int flags,
struct kstat *stat, u32 request_mask)
{
@ -172,6 +194,10 @@ int vfs_statx(int dfd, const char __user *filename, int flags,
int error = -EINVAL;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_stat(&dfd, &filename, &flags);
#endif
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
return -EINVAL;
@ -330,6 +356,9 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
#endif
tmp.st_blocks = stat->blocks;
tmp.st_blksize = stat->blksize;
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
susfs_sus_kstat(tmp.st_ino, &tmp);
#endif
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
@ -379,6 +408,11 @@ SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
if (!error)
error = cp_new_stat(&stat, statbuf);
#ifdef CONFIG_KSU_MANUAL_HOOK
if (!error)
ksu_handle_newfstat_ret(&fd, &statbuf);
#endif
return error;
}
#endif
@ -506,6 +540,11 @@ SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf)
if (!error)
error = cp_new_stat64(&stat, statbuf);
#ifdef CONFIG_KSU_MANUAL_HOOK
if (!error)
ksu_handle_fstat64_ret(&fd, &statbuf);
#endif
return error;
}

1446
fs/susfs.c Normal file

File diff suppressed because it is too large Load diff

216
include/linux/susfs.h Normal file
View file

@ -0,0 +1,216 @@
#ifndef KSU_SUSFS_H
#define KSU_SUSFS_H
#include <linux/version.h>
#include <linux/types.h>
#include <linux/utsname.h>
#include <linux/mount.h>
/* shared with userspace ksu_susfs tool */
#define CMD_SUSFS_ADD_SUS_PATH 0x55555
#define CMD_SUSFS_ADD_SUS_MOUNT 0x55556
#define CMD_SUSFS_ADD_SUS_KSTAT 0x55558
#define CMD_SUSFS_UPDATE_SUS_KSTAT 0x55559
#define CMD_SUSFS_ADD_TRY_UMOUNT 0x5555a
#define CMD_SUSFS_SET_UNAME 0x5555b
#define CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY 0x5555c
#define CMD_SUSFS_ENABLE_LOG 0x5555d
#define CMD_SUSFS_ADD_SUS_MAPS_STATICALLY 0x5555e
#define CMD_SUSFS_ADD_SUS_PROC_FD_LINK 0x5555f
#define CMD_SUSFS_ADD_SUS_MAPS 0x55560
#define CMD_SUSFS_UPDATE_SUS_MAPS 0x55561
#define CMD_SUSFS_ADD_SUS_MEMFD 0x55562
#define SUSFS_MAX_LEN_PATHNAME 256 // 256 should address many paths already unless you are doing some strange experimental stuff, then set your own desired length
#define SUSFS_MAX_LEN_MFD_NAME 248
#define SUSFS_MAX_SUS_MNTS 300 // I think 300 is now enough? This includes the mount entries for each process and sus mounts added by user
#define SUSFS_MAX_SUS_MAPS 200 // I think 200 is now enough? Tell me why if you have over 200 entries
#define SUSFS_MAP_FILES_ACTION_REMOVE_WRITE_PERM 1
#define SUSFS_MAP_FILES_ACTION_HIDE_DENTRY 2
/* non shared to userspace ksu_susfs tool */
#define SYSCALL_FAMILY_ALL_ENOENT 0
#define SYSCALL_FAMILY_OPENAT 1
#define SYSCALL_FAMILY_MKNOD 2
#define SYSCALL_FAMILY_MKDIRAT 3
#define SYSCALL_FAMILY_RMDIR 4
#define SYSCALL_FAMILY_UNLINKAT 5
#define SYSCALL_FAMILY_SYMLINKAT_NEWNAME 6
#define SYSCALL_FAMILY_LINKAT_OLDNAME 7
#define SYSCALL_FAMILY_LINKAT_NEWNAME 8
#define SYSCALL_FAMILY_RENAMEAT2_OLDNAME 9
#define SYSCALL_FAMILY_RENAMEAT2_NEWNAME 10
#define SYSCALL_FAMILY_TRUNCATE 11
#define SYSCALL_FAMILY_FACCESSAT 12
#define SYSCALL_FAMILY_CHDIR 13
#define getname_safe(name) (name == NULL ? ERR_PTR(-EINVAL) : getname(name))
#define putname_safe(name) (IS_ERR(name) ? NULL : putname(name))
#define uid_matches_suspicious_path() (current_uid().val >= 2000)
#define uid_matches_suspicious_kstat() (current_uid().val >= 2000)
#define uid_matches_proc_need_to_reorder_mnt_id() (current_uid().val >= 10000)
struct st_susfs_sus_path {
char target_pathname[SUSFS_MAX_LEN_PATHNAME];
unsigned long target_ino;
};
struct st_susfs_sus_mount {
char target_pathname[SUSFS_MAX_LEN_PATHNAME];
};
struct st_susfs_sus_kstat {
unsigned long target_ino; // the ino after bind mounted or overlayed
char target_pathname[SUSFS_MAX_LEN_PATHNAME];
char spoofed_pathname[SUSFS_MAX_LEN_PATHNAME];
unsigned long spoofed_ino;
unsigned long spoofed_dev;
unsigned int spoofed_nlink;
long spoofed_atime_tv_sec;
long spoofed_mtime_tv_sec;
long spoofed_ctime_tv_sec;
long spoofed_atime_tv_nsec;
long spoofed_mtime_tv_nsec;
long spoofed_ctime_tv_nsec;
};
struct st_susfs_sus_maps {
bool is_statically;
int compare_mode;
bool is_isolated_entry;
bool is_file;
unsigned long prev_target_ino;
unsigned long next_target_ino;
char target_pathname[SUSFS_MAX_LEN_PATHNAME];
unsigned long target_ino;
unsigned long target_dev;
unsigned long long target_pgoff;
unsigned long target_prot;
unsigned long target_addr_size;
char spoofed_pathname[SUSFS_MAX_LEN_PATHNAME];
unsigned long spoofed_ino;
unsigned long spoofed_dev;
unsigned long long spoofed_pgoff;
unsigned long spoofed_prot;
bool need_to_spoof_pathname;
bool need_to_spoof_ino;
bool need_to_spoof_dev;
bool need_to_spoof_pgoff;
bool need_to_spoof_prot;
};
struct st_susfs_try_umount {
char target_pathname[SUSFS_MAX_LEN_PATHNAME];
int mnt_mode;
};
struct st_susfs_sus_proc_fd_link {
char target_link_name[SUSFS_MAX_LEN_PATHNAME];
char spoofed_link_name[SUSFS_MAX_LEN_PATHNAME];
};
struct st_susfs_sus_memfd {
char target_pathname[SUSFS_MAX_LEN_MFD_NAME];
};
struct st_susfs_mnt_id_recorder {
int target_mnt_id[SUSFS_MAX_SUS_MNTS];
int spoofed_mnt_id[SUSFS_MAX_SUS_MNTS];
int spoofed_parent_mnt_id[SUSFS_MAX_SUS_MNTS];
int count;
};
struct st_susfs_sus_path_list {
struct list_head list;
struct st_susfs_sus_path info;
};
struct st_susfs_sus_mount_list {
struct list_head list;
struct st_susfs_sus_mount info;
};
struct st_susfs_sus_kstat_list {
struct list_head list;
struct st_susfs_sus_kstat info;
};
struct st_susfs_sus_maps_list {
struct list_head list;
struct st_susfs_sus_maps info;
};
struct st_susfs_try_umount_list {
struct list_head list;
struct st_susfs_try_umount info;
};
struct st_susfs_sus_proc_fd_link_list {
struct list_head list;
struct st_susfs_sus_proc_fd_link info;
};
struct st_susfs_sus_memfd_list {
struct list_head list;
struct st_susfs_sus_memfd info;
};
struct st_susfs_mnt_id_recorder_list {
struct list_head list;
int pid;
int opened_count;
struct st_susfs_mnt_id_recorder info;
};
struct st_susfs_uname {
char sysname[__NEW_UTS_LEN+1];
char nodename[__NEW_UTS_LEN+1];
char release[__NEW_UTS_LEN+1];
char version[__NEW_UTS_LEN+1];
char machine[__NEW_UTS_LEN+1];
};
int susfs_add_sus_path(struct st_susfs_sus_path* __user user_info);
int susfs_add_sus_mount(struct st_susfs_sus_mount* __user user_info);
int susfs_add_sus_kstat(struct st_susfs_sus_kstat* __user user_info);
int susfs_update_sus_kstat(struct st_susfs_sus_kstat* __user user_info);
int susfs_add_sus_maps(struct st_susfs_sus_maps* __user user_info);
int susfs_update_sus_maps(struct st_susfs_sus_maps* __user user_info);
int susfs_add_sus_proc_fd_link(struct st_susfs_sus_proc_fd_link* __user user_info);
int susfs_add_sus_memfd(struct st_susfs_sus_memfd* __user user_info);
int susfs_add_try_umount(struct st_susfs_try_umount* __user user_info);
int susfs_set_uname(struct st_susfs_uname* __user user_info);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
int susfs_sus_path_by_path(struct path* file, int* errno_to_be_changed, int syscall_family);
#else
int susfs_sus_path_by_path(const struct path* file, int* errno_to_be_changed, int syscall_family);
#endif
int susfs_sus_path_by_filename(struct filename* name, int* errno_to_be_changed, int syscall_family);
int susfs_sus_mount(struct vfsmount* mnt, struct path* root);
int susfs_sus_ino_for_filldir64(unsigned long ino);
void susfs_sus_kstat(unsigned long ino, struct stat* out_stat);
int susfs_sus_maps(unsigned long target_ino, unsigned long target_addr_size,
unsigned long* orig_ino, dev_t* orig_dev, vm_flags_t* flags,
unsigned long long* pgoff, struct vm_area_struct* vma, char* out_name);
void susfs_sus_map_files_readlink(unsigned long target_ino, char* pathname);
int susfs_sus_map_files_instantiate(struct vm_area_struct* vma);
int susfs_is_sus_maps_list_empty(void);
int susfs_sus_proc_fd_link(char *pathname, int len);
int susfs_is_sus_proc_fd_link_list_empty(void);
int susfs_sus_memfd(char *memfd_name);
void susfs_try_umount(uid_t target_uid);
void susfs_spoof_uname(struct new_utsname* tmp);
void susfs_add_mnt_id_recorder(struct mnt_namespace *ns);
int susfs_get_fake_mnt_id(int mnt_id, int *out_mnt_id, int *out_parent_mnt_id);
void susfs_remove_mnt_id_recorder(void);
void susfs_set_log(bool enabled);
void susfs_change_error_no_by_pathname(char* pathname, int* errno_to_be_changed, int syscall_family);
void __init susfs_init(void);
#endif

View file

@ -310,6 +310,11 @@ DEFINE_MUTEX(system_transition_mutex);
*
* reboot doesn't sync: do that yourself before calling this.
*/
#ifdef CONFIG_KSU_MANUAL_HOOK
extern int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd,
void __user **arg);
#endif
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
@ -317,6 +322,10 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
char buffer[256];
int ret = 0;
#ifdef CONFIG_KSU_MANUAL_HOOK
ksu_handle_sys_reboot(magic1, magic2, cmd, &arg);
#endif
/* We only trust the superuser with rebooting the system. */
if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
return -EPERM;

View file

@ -75,6 +75,14 @@
#include "uid16.h"
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
extern long ksu_handle_susfs_prctl(int option, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5);
#endif
#include <trace/hooks/sys.h>
#ifndef SET_UNALIGN_CTL
@ -1247,6 +1255,9 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
down_read(&uts_sem);
memcpy(&tmp, utsname(), sizeof(tmp));
up_read(&uts_sem);
#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
susfs_spoof_uname(&tmp);
#endif
if (copy_to_user(name, &tmp, sizeof(tmp)))
return -EFAULT;
@ -2430,6 +2441,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned char comm[sizeof(me->comm)];
long error;
#ifdef CONFIG_KSU_SUSFS
error = ksu_handle_susfs_prctl(option, arg2, arg3, arg4, arg5);
if (error != -ENOSYS)
return error;
#endif
error = security_task_prctl(option, arg2, arg3, arg4, arg5);
if (error != -ENOSYS)
return error;

View file

@ -20,6 +20,10 @@
#include <linux/memfd.h>
#include <uapi/linux/memfd.h>
#ifdef CONFIG_KSU_SUSFS
#include <linux/susfs.h>
#endif
/*
* We need a tag: a new tag would expand every xa_node by 8 bytes,
* so reuse a tag which we firmly believe is never set or cleared on tmpfs
@ -306,6 +310,13 @@ SYSCALL_DEFINE2(memfd_create,
goto err_name;
}
#ifdef CONFIG_KSU_SUSFS_SUS_MEMFD
if (susfs_sus_memfd(name)) {
error = -EFAULT;
goto err_name;
}
#endif
fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0);
if (fd < 0) {
error = fd;