Compare commits
10 Commits
c93cf58f48
...
4301d1dc5d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4301d1dc5d | ||
|
|
36d803a92a | ||
|
|
3a12bdead1 | ||
|
|
57e3c095be | ||
|
|
3510203fa6 | ||
|
|
2aa0034695 | ||
|
|
7782c00275 | ||
|
|
dc3de58aa6 | ||
|
|
83db28b262 | ||
|
|
6e44090e57 |
@@ -145,7 +145,14 @@ endif
|
||||
ifeq ($(shell grep -q "task_security_struct\s\+\*selinux_cred" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_SELINUX_CRED
|
||||
endif
|
||||
|
||||
# seccomp_types.h were added on 6.7
|
||||
ifeq ($(shell grep -q "atomic_t\s\+filter_count" $(srctree)/include/linux/seccomp.h $(srctree)/include/linux/seccomp_types.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_SECCOMP_FILTER_CNT
|
||||
endif
|
||||
# some old kernel backport this, let's check if put_seccomp_filter still exist
|
||||
ifneq ($(shell grep -wq "put_seccomp_filter" $(srctree)/kernel/seccomp.c $(srctree)/include/linux/seccomp.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_SECCOMP_FILTER_RELEASE
|
||||
endif
|
||||
ifeq ($(shell grep -q "anon_inode_getfd_secure" $(srctree)/fs/anon_inodes.c; echo $$?),0)
|
||||
ccflags-y += -DKSU_HAS_GETFD_SECURE
|
||||
endif
|
||||
|
||||
@@ -436,7 +436,7 @@ void persistent_allow_list(void)
|
||||
goto put_task;
|
||||
}
|
||||
cb->func = do_persistent_allow_list;
|
||||
ksu_task_work_add(tsk, cb, TWA_RESUME);
|
||||
task_work_add(tsk, cb, TWA_RESUME);
|
||||
|
||||
put_task:
|
||||
put_task_struct(tsk);
|
||||
|
||||
@@ -81,6 +81,7 @@ static long ksu_sys_setns(int fd, int flags)
|
||||
PT_REGS_PARM1(®s) = fd;
|
||||
PT_REGS_PARM2(®s) = flags;
|
||||
|
||||
// TODO: arm support
|
||||
#if (defined(__aarch64__) || defined(__x86_64__))
|
||||
return SYS_SETNS_SYMBOL(®s);
|
||||
#else
|
||||
@@ -180,13 +181,7 @@ static void setup_mount_namespace(int32_t ns_mode)
|
||||
if (ret) {
|
||||
pr_warn("sys_setns failed: %ld\n", ret);
|
||||
}
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
close_fd(fd);
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
|
||||
ksys_close(fd);
|
||||
#else
|
||||
sys_close(fd);
|
||||
#endif
|
||||
do_close_fd(fd);
|
||||
}
|
||||
|
||||
if (ns_mode == 2) {
|
||||
@@ -227,16 +222,25 @@ void disable_seccomp(struct task_struct *tsk)
|
||||
#ifdef CONFIG_SECCOMP
|
||||
tsk->seccomp.mode = 0;
|
||||
if (tsk->seccomp.filter) {
|
||||
// 5.9+ have filter_count and use seccomp_filter_release
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
|
||||
seccomp_filter_release(tsk);
|
||||
// 5.9+ have filter_count, but optional.
|
||||
#ifdef KSU_OPTIONAL_SECCOMP_FILTER_CNT
|
||||
atomic_set(&tsk->seccomp.filter_count, 0);
|
||||
#endif
|
||||
// some old kernel backport seccomp_filter_release..
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) && \
|
||||
defined(KSU_OPTIONAL_SECCOMP_FILTER_RELEASE)
|
||||
seccomp_filter_release(tsk);
|
||||
#else
|
||||
// never, ever call seccomp_filter_release on 6.10+ (no effect)
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) && \
|
||||
LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0))
|
||||
seccomp_filter_release(tsk);
|
||||
#else
|
||||
// for 6.11+ kernel support?
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
|
||||
put_seccomp_filter(tsk);
|
||||
#endif
|
||||
tsk->seccomp.filter = NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -123,3 +123,27 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
return copy_from_user_nofault(dst, src, size);
|
||||
#else
|
||||
// https://elixir.bootlin.com/linux/v5.8/source/mm/maccess.c#L205
|
||||
long ret = -EFAULT;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
set_fs(USER_DS);
|
||||
// tweaked to use ksu_access_ok
|
||||
if (ksu_access_ok(src, size)) {
|
||||
pagefault_disable();
|
||||
ret = __copy_from_user_inatomic(dst, src, size);
|
||||
pagefault_enable();
|
||||
}
|
||||
set_fs(old_fs);
|
||||
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/task_work.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include "ss/policydb.h"
|
||||
#include "linux/key.h"
|
||||
|
||||
@@ -69,16 +70,21 @@ extern struct key *init_session_keyring;
|
||||
|
||||
// Linux >= 5.7
|
||||
// task_work_add (struct, struct, enum)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
|
||||
#define ksu_task_work_add(tsk, cb, notify) task_work_add(tsk, cb, notify)
|
||||
#else
|
||||
// Linux pre-5.7
|
||||
// task_work_add (struct, struct, bool)
|
||||
#define ksu_task_work_add(tsk, cb, notify) task_work_add(tsk, cb, notify)
|
||||
// Decoy, so it wouldn't complain.
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)
|
||||
#ifndef TWA_RESUME
|
||||
#define TWA_RESUME true
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline int do_close_fd(unsigned int fd)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
return close_fd(fd);
|
||||
#else
|
||||
return __close_fd(current->files, fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,28 +44,11 @@ static const struct ksu_feature_handler kernel_umount_handler = {
|
||||
.set_handler = kernel_umount_feature_set,
|
||||
};
|
||||
|
||||
static bool should_umount(struct path *path)
|
||||
{
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
|
||||
pr_info("ignore global mnt namespace process: %d\n",
|
||||
current_uid().val);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
|
||||
const char *fstype = path->mnt->mnt_sb->s_type->name;
|
||||
return strcmp(fstype, "overlay") == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_HAS_PATH_UMOUNT)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || \
|
||||
defined(KSU_HAS_PATH_UMOUNT)
|
||||
extern int path_umount(struct path *path, int flags);
|
||||
static void ksu_umount_mnt(const char *__never_use_mnt, struct path *path, int flags)
|
||||
static void ksu_umount_mnt(const char *__never_use_mnt, struct path *path,
|
||||
int flags)
|
||||
{
|
||||
int err = path_umount(path, flags);
|
||||
if (err) {
|
||||
@@ -91,12 +74,12 @@ static void ksu_sys_umount(const char *mnt, int flags)
|
||||
#define ksu_umount_mnt(mnt, __unused, flags) \
|
||||
({ \
|
||||
path_put(__unused); \
|
||||
ksu_sys_umount(mnt, flags); \
|
||||
ksu_sys_umount(mnt, flags); \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
static void try_umount(const char *mnt, int flags)
|
||||
{
|
||||
struct path path;
|
||||
int err = kern_path(mnt, 0, &path);
|
||||
@@ -110,25 +93,17 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
// we are only interest in some specific mounts
|
||||
if (check_mnt && !should_umount(&path)) {
|
||||
path_put(&path);
|
||||
return;
|
||||
}
|
||||
|
||||
ksu_umount_mnt(mnt, &path, flags);
|
||||
}
|
||||
|
||||
static inline void do_ksu_umount_lists(void)
|
||||
static inline void do_umount_work(void)
|
||||
{
|
||||
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
|
||||
// filter the mountpoint whose target is `/data/adb`
|
||||
try_umount("/odm", true, 0);
|
||||
try_umount("/system", true, 0);
|
||||
try_umount("/vendor", true, 0);
|
||||
try_umount("/product", true, 0);
|
||||
try_umount("/system_ext", true, 0);
|
||||
try_umount("/data/adb/modules", false, MNT_DETACH);
|
||||
struct mount_entry *entry;
|
||||
list_for_each_entry (entry, &mount_list, list) {
|
||||
pr_info("%s: unmounting: %s flags 0x%x\n", __func__,
|
||||
entry->umountable, entry->flags);
|
||||
try_umount(entry->umountable, entry->flags);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KSU_SHOULD_USE_NEW_TP
|
||||
@@ -145,7 +120,9 @@ static void umount_tw_func(struct callback_head *cb)
|
||||
saved = override_creds(tw->old_cred);
|
||||
}
|
||||
|
||||
do_ksu_umount_lists();
|
||||
down_read(&mount_list_lock);
|
||||
do_umount_work();
|
||||
up_read(&mount_list_lock);
|
||||
|
||||
if (saved)
|
||||
revert_creds(saved);
|
||||
@@ -198,7 +175,7 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid)
|
||||
tw->old_cred = get_current_cred();
|
||||
tw->cb.func = umount_tw_func;
|
||||
|
||||
int err = ksu_task_work_add(current, &tw->cb, TWA_RESUME);
|
||||
int err = task_work_add(current, &tw->cb, TWA_RESUME);
|
||||
if (err) {
|
||||
if (tw->old_cred) {
|
||||
put_cred(tw->old_cred);
|
||||
@@ -208,7 +185,9 @@ int ksu_handle_umount(uid_t old_uid, uid_t new_uid)
|
||||
}
|
||||
#else
|
||||
// Using task work for non-kp context is expansive?
|
||||
do_ksu_umount_lists();
|
||||
down_read(&mount_list_lock);
|
||||
do_umount_work();
|
||||
up_read(&mount_list_lock);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define __KSU_H_KERNEL_UMOUNT
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
void ksu_kernel_umount_init(void);
|
||||
void ksu_kernel_umount_exit(void);
|
||||
@@ -9,4 +11,13 @@ void ksu_kernel_umount_exit(void);
|
||||
// Handler function to be called from setresuid hook
|
||||
int ksu_handle_umount(uid_t old_uid, uid_t new_uid);
|
||||
|
||||
// for the umount list
|
||||
struct mount_entry {
|
||||
char *umountable;
|
||||
unsigned int flags;
|
||||
struct list_head list;
|
||||
};
|
||||
extern struct list_head mount_list;
|
||||
extern struct rw_semaphore mount_list_lock;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -105,13 +105,13 @@ void on_post_fs_data(void)
|
||||
}
|
||||
|
||||
extern void ext4_unregister_sysfs(struct super_block *sb);
|
||||
static void nuke_ext4_sysfs(void)
|
||||
int nuke_ext4_sysfs(const char* mnt)
|
||||
{
|
||||
struct path path;
|
||||
int err = kern_path("/data/adb/modules", 0, &path);
|
||||
int err = kern_path(mnt, 0, &path);
|
||||
if (err) {
|
||||
pr_err("nuke path err: %d\n", err);
|
||||
return;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct super_block *sb = path.dentry->d_inode->i_sb;
|
||||
@@ -119,18 +119,18 @@ static void nuke_ext4_sysfs(void)
|
||||
if (strcmp(name, "ext4") != 0) {
|
||||
pr_info("nuke but module aren't mounted\n");
|
||||
path_put(&path);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ext4_unregister_sysfs(sb);
|
||||
path_put(&path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_module_mounted(void)
|
||||
{
|
||||
pr_info("on_module_mounted!\n");
|
||||
ksu_module_mounted = true;
|
||||
nuke_ext4_sysfs();
|
||||
}
|
||||
|
||||
void on_boot_completed(void)
|
||||
@@ -254,7 +254,7 @@ first_app_process:
|
||||
rcu_read_lock();
|
||||
init_task = rcu_dereference(current->real_parent);
|
||||
if (init_task) {
|
||||
ksu_task_work_add(init_task, &on_post_fs_data_cb,
|
||||
task_work_add(init_task, &on_post_fs_data_cb,
|
||||
TWA_RESUME);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -14,6 +14,8 @@ void on_boot_completed(void);
|
||||
|
||||
bool ksu_is_safe_mode(void);
|
||||
|
||||
int nuke_ext4_sysfs(const char* mnt);
|
||||
|
||||
extern u32 ksu_file_sid;
|
||||
extern bool ksu_module_mounted;
|
||||
extern bool ksu_boot_completed;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksud.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "setuid_hook.h"
|
||||
|
||||
@@ -102,7 +103,7 @@ static const struct lsm_id ksu_lsmid = {
|
||||
};
|
||||
#endif
|
||||
|
||||
void ksu_lsm_hook_init(void)
|
||||
void __init ksu_lsm_hook_init(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
|
||||
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), &ksu_lsmid);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
|
||||
#include "objsec.h"
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "supercalls.h"
|
||||
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/cred.h>
|
||||
@@ -14,11 +12,14 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "supercalls.h"
|
||||
#include "arch.h"
|
||||
#include "allowlist.h"
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksud.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "kernel_umount.h"
|
||||
#include "manager.h"
|
||||
#include "selinux/selinux.h"
|
||||
#include "objsec.h"
|
||||
@@ -371,10 +372,15 @@ static int do_get_wrapper_fd(void __user *arg) {
|
||||
goto put_orig_file;
|
||||
}
|
||||
|
||||
// kcompat for older kernel
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
#define getfd_secure anon_inode_create_getfd
|
||||
#else
|
||||
#elif defined(KSU_HAS_GETFD_SECURE)
|
||||
#define getfd_secure anon_inode_getfd_secure
|
||||
#else
|
||||
// technically not a secure inode, but, this is the only way so.
|
||||
#define getfd_secure(name, ops, data, flags, __unused) \
|
||||
anon_inode_getfd(name, ops, data, flags)
|
||||
#endif
|
||||
ret = getfd_secure("[ksu_fdwrapper]", &data->ops, data, f->f_flags, NULL);
|
||||
if (ret < 0) {
|
||||
@@ -386,7 +392,11 @@ static int do_get_wrapper_fd(void __user *arg) {
|
||||
struct inode* wrapper_inode = file_inode(pf);
|
||||
// copy original inode mode
|
||||
wrapper_inode->i_mode = file_inode(f)->i_mode;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || defined(KSU_OPTIONAL_SELINUX_INODE)
|
||||
struct inode_security_struct *sec = selinux_inode(wrapper_inode);
|
||||
#else
|
||||
struct inode_security_struct *sec = (struct inode_security_struct *)wrapper_inode->i_security;
|
||||
#endif
|
||||
if (sec) {
|
||||
sec->sid = ksu_file_sid;
|
||||
}
|
||||
@@ -466,6 +476,146 @@ static int do_manage_mark(void __user *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct list_head mount_list = LIST_HEAD_INIT(mount_list);
|
||||
DECLARE_RWSEM(mount_list_lock);
|
||||
|
||||
static int add_try_umount(void __user *arg)
|
||||
{
|
||||
struct mount_entry *new_entry, *entry, *tmp;
|
||||
struct ksu_add_try_umount_cmd cmd;
|
||||
char buf[256] = { 0 };
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof cmd))
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd.mode) {
|
||||
case KSU_UMOUNT_WIPE: {
|
||||
struct mount_entry *entry, *tmp;
|
||||
down_write(&mount_list_lock);
|
||||
list_for_each_entry_safe (entry, tmp, &mount_list, list) {
|
||||
pr_info("wipe_umount_list: removing entry: %s\n",
|
||||
entry->umountable);
|
||||
list_del(&entry->list);
|
||||
kfree(entry->umountable);
|
||||
kfree(entry);
|
||||
}
|
||||
up_write(&mount_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case KSU_UMOUNT_ADD: {
|
||||
long len = strncpy_from_user(buf, (const char __user *)cmd.arg,
|
||||
256);
|
||||
if (len <= 0)
|
||||
return -EFAULT;
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
|
||||
if (!new_entry)
|
||||
return -ENOMEM;
|
||||
|
||||
new_entry->umountable = kstrdup(buf, GFP_KERNEL);
|
||||
if (!new_entry->umountable) {
|
||||
kfree(new_entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
down_write(&mount_list_lock);
|
||||
|
||||
// disallow dupes
|
||||
// if this gets too many, we can consider moving this whole task to a kthread
|
||||
list_for_each_entry (entry, &mount_list, list) {
|
||||
if (!strcmp(entry->umountable, buf)) {
|
||||
pr_info("cmd_add_try_umount: %s is already here!\n",
|
||||
buf);
|
||||
up_write(&mount_list_lock);
|
||||
kfree(new_entry->umountable);
|
||||
kfree(new_entry);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// now check flags and add
|
||||
// this also serves as a null check
|
||||
if (cmd.flags)
|
||||
new_entry->flags = cmd.flags;
|
||||
else
|
||||
new_entry->flags = 0;
|
||||
|
||||
// debug
|
||||
list_add(&new_entry->list, &mount_list);
|
||||
up_write(&mount_list_lock);
|
||||
pr_info("cmd_add_try_umount: %s added!\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this is just strcmp'd wipe anyway
|
||||
case KSU_UMOUNT_DEL: {
|
||||
long len = strncpy_from_user(buf, (const char __user *)cmd.arg,
|
||||
sizeof(buf) - 1);
|
||||
if (len <= 0)
|
||||
return -EFAULT;
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
down_write(&mount_list_lock);
|
||||
list_for_each_entry_safe (entry, tmp, &mount_list, list) {
|
||||
if (!strcmp(entry->umountable, buf)) {
|
||||
pr_info("cmd_add_try_umount: entry removed: %s\n",
|
||||
entry->umountable);
|
||||
list_del(&entry->list);
|
||||
kfree(entry->umountable);
|
||||
kfree(entry);
|
||||
}
|
||||
}
|
||||
up_write(&mount_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default: {
|
||||
pr_err("cmd_add_try_umount: invalid operation %u\n", cmd.mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
} // switch(cmd.mode)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_nuke_ext4_sysfs(void __user *arg)
|
||||
{
|
||||
struct ksu_nuke_ext4_sysfs_cmd cmd;
|
||||
char mnt[256];
|
||||
long ret;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!cmd.arg)
|
||||
return -EINVAL;
|
||||
|
||||
memset(mnt, 0, sizeof(mnt));
|
||||
|
||||
ret = strncpy_from_user(mnt, cmd.arg, sizeof(mnt));
|
||||
if (ret < 0) {
|
||||
pr_err("nuke ext4 copy mnt failed: %ld\\n", ret);
|
||||
return -EFAULT; // 或者 return ret;
|
||||
}
|
||||
|
||||
if (ret == sizeof(mnt)) {
|
||||
pr_err("nuke ext4 mnt path too long\\n");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
pr_info("do_nuke_ext4_sysfs: %s\n", mnt);
|
||||
|
||||
return nuke_ext4_sysfs(mnt);
|
||||
}
|
||||
|
||||
// 100. GET_FULL_VERSION - Get full version string
|
||||
static int do_get_full_version(void __user *arg)
|
||||
{
|
||||
@@ -642,6 +792,8 @@ static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
|
||||
{ .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_MANAGE_MARK, .name = "MANAGE_MARK", .handler = do_manage_mark, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_NUKE_EXT4_SYSFS, .name = "NUKE_EXT4_SYSFS", .handler = do_nuke_ext4_sysfs, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_ADD_TRY_UMOUNT, .name = "ADD_TRY_UMOUNT", .handler = add_try_umount, .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},
|
||||
@@ -669,11 +821,7 @@ static void ksu_install_fd_tw_func(struct callback_head *cb)
|
||||
|
||||
if (copy_to_user(tw->outp, &fd, sizeof(fd))) {
|
||||
pr_err("install ksu fd reply err\n");
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
close_fd(fd);
|
||||
#else
|
||||
ksys_close(fd);
|
||||
#endif
|
||||
do_close_fd(fd);
|
||||
}
|
||||
|
||||
kfree(tw);
|
||||
@@ -699,7 +847,7 @@ static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
tw->outp = (int __user *)arg4;
|
||||
tw->cb.func = ksu_install_fd_tw_func;
|
||||
|
||||
if (ksu_task_work_add(current, &tw->cb, TWA_RESUME)) {
|
||||
if (task_work_add(current, &tw->cb, TWA_RESUME)) {
|
||||
kfree(tw);
|
||||
pr_warn("install fd add task_work failed\n");
|
||||
}
|
||||
@@ -730,13 +878,7 @@ int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd,
|
||||
// downstream: dereference all arg usage!
|
||||
if (copy_to_user((void __user *)*arg, &fd, sizeof(fd))) {
|
||||
pr_err("install ksu fd reply err\n");
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
close_fd(fd);
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
|
||||
ksys_close(fd);
|
||||
#else
|
||||
sys_close(fd);
|
||||
#endif
|
||||
do_close_fd(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -842,8 +984,10 @@ int ksu_install_fd(void)
|
||||
// Install fd
|
||||
fd_install(fd, filp);
|
||||
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_info("ksu fd[%d] installed for %s/%d\n", fd, current->comm,
|
||||
current->pid);
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifdef CONFIG_KPM
|
||||
#include "kpm/kpm.h"
|
||||
#endif
|
||||
#include "ksu.h"
|
||||
|
||||
// Magic numbers for reboot hook to install fd
|
||||
#define KSU_INSTALL_MAGIC1 0xDEADBEEF
|
||||
@@ -77,6 +78,10 @@ struct ksu_set_feature_cmd {
|
||||
__u64 value; // Input: feature value/state to set
|
||||
};
|
||||
|
||||
struct ksu_nuke_ext4_sysfs_cmd {
|
||||
__aligned_u64 arg; // Input: mnt pointer
|
||||
};
|
||||
|
||||
// Other command structures
|
||||
struct ksu_get_full_version_cmd {
|
||||
char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string
|
||||
@@ -120,6 +125,16 @@ struct ksu_manage_mark_cmd {
|
||||
#define KSU_MARK_UNMARK 3
|
||||
#define KSU_MARK_REFRESH 4
|
||||
|
||||
struct ksu_add_try_umount_cmd {
|
||||
__aligned_u64 arg; // char ptr, this is the mountpoint
|
||||
__u32 flags; // this is the flag we use for it
|
||||
__u8 mode; // denotes what to do with it 0:wipe_list 1:add_to_list 2:delete_entry
|
||||
};
|
||||
|
||||
#define KSU_UMOUNT_WIPE 0 // ignore everything and wipe list
|
||||
#define KSU_UMOUNT_ADD 1 // add entry (path + flags)
|
||||
#define KSU_UMOUNT_DEL 2 // delete entry, strcmp
|
||||
|
||||
// IOCTL command definitions
|
||||
#define KSU_IOCTL_GRANT_ROOT _IOC(_IOC_NONE, 'K', 1, 0)
|
||||
#define KSU_IOCTL_GET_INFO _IOC(_IOC_READ, 'K', 2, 0)
|
||||
@@ -137,6 +152,8 @@ struct ksu_manage_mark_cmd {
|
||||
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||
#define KSU_IOCTL_GET_WRAPPER_FD _IOC(_IOC_WRITE, 'K', 15, 0)
|
||||
#define KSU_IOCTL_MANAGE_MARK _IOC(_IOC_READ | _IOC_WRITE, 'K', 16, 0)
|
||||
#define KSU_IOCTL_NUKE_EXT4_SYSFS _IOC(_IOC_WRITE, 'K', 17, 0)
|
||||
#define KSU_IOCTL_ADD_TRY_UMOUNT _IOC(_IOC_WRITE, 'K', 18, 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)
|
||||
|
||||
@@ -212,7 +212,7 @@ struct apk_path_hash {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static struct list_head apk_path_hash_list = LIST_HEAD_INIT(apk_path_hash_list);
|
||||
static struct list_head apk_path_hash_list;
|
||||
|
||||
struct my_dir_context {
|
||||
struct dir_context ctx;
|
||||
@@ -279,8 +279,9 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
|
||||
data->depth = my_ctx->depth - 1;
|
||||
list_add_tail(&data->list, my_ctx->data_path_list);
|
||||
} else {
|
||||
if ((namelen == 8) && (strncmp(name, "base.apk", namelen) == 0)) {
|
||||
struct apk_path_hash *pos, *n;
|
||||
if ((namelen == 8) &&
|
||||
(strncmp(name, "base.apk", namelen) == 0)) {
|
||||
struct apk_path_hash *pos;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
|
||||
unsigned int hash = full_name_hash(dirpath, strlen(dirpath));
|
||||
#else
|
||||
@@ -307,32 +308,18 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
|
||||
crown_manager(dirpath, my_ctx->private_data, 0);
|
||||
*my_ctx->stop = 1;
|
||||
}
|
||||
|
||||
struct apk_path_hash *apk_data = kzalloc(sizeof(*apk_data), GFP_ATOMIC);
|
||||
if (apk_data) {
|
||||
apk_data->hash = hash;
|
||||
apk_data->exists = true;
|
||||
list_add_tail(&apk_data->list, &apk_path_hash_list);
|
||||
}
|
||||
|
||||
if (is_manager_apk(dirpath)) {
|
||||
// Manager found, clear APK cache list
|
||||
list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) {
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
void search_manager(const char *path, int depth, struct list_head *uid_data)
|
||||
static void search_manager(const char *path, int depth, struct list_head *uid_data)
|
||||
{
|
||||
int i, stop = 0;
|
||||
struct list_head data_path_list;
|
||||
INIT_LIST_HEAD(&data_path_list);
|
||||
INIT_LIST_HEAD(&apk_path_hash_list);
|
||||
unsigned long data_app_magic = 0;
|
||||
|
||||
// Initialize APK cache list
|
||||
@@ -397,12 +384,11 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove stale cached APK entries
|
||||
// clear apk_path_hash_list unconditionally
|
||||
pr_info("search manager: cleanup!\n");
|
||||
list_for_each_entry_safe (pos, n, &apk_path_hash_list, list) {
|
||||
if (!pos->exists) {
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
}
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user