Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 62 additions & 44 deletions kernel/core_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ static void nuke_ext4_sysfs() {
path_put(&path);
}

struct mount_entry {
char *umountable;
struct list_head list;
};
LIST_HEAD(mount_list);

int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
Expand Down Expand Up @@ -277,6 +283,45 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
#endif

if (arg2 == CMD_ADD_TRY_UMOUNT) {
struct mount_entry *new_entry, *entry;
char buf[384];
memzero_explicit(buf, 384); // overkill, init as empty is ok

if (copy_from_user(buf, (const char __user *)arg3, sizeof(buf) - 1)) {
pr_err("cmd_add_try_umount: failed to copy user string\n");
return 0;
}
buf[384 - 1] = '\0';

new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry)
return 0;

new_entry->umountable = kstrdup(buf, GFP_KERNEL);
if (!new_entry->umountable) {
kfree(new_entry);
return 0;
}

// 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);
return 0;
}
}

pr_info("cmd_add_try_umount: %s added!\n", buf); // guard me with KSU_DEBUG!
list_add(&new_entry->list, &mount_list);

if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}

if (arg2 == CMD_BECOME_MANAGER) {
if (from_manager) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
Expand Down Expand Up @@ -516,58 +561,39 @@ static bool is_appuid(kuid_t uid)
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
}

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;
}

static void ksu_umount_mnt(struct path *path, int flags)
static void ksu_path_umount(const char *mnt, struct path *path, int flags)
{
int err = path_umount(path, flags);
if (err) {
pr_info("umount %s failed: %d\n", path->dentry->d_iname, err);
}
#ifdef CONFIG_KSU_DEBUG
pr_info("%s: path: %s code: %d\n", __func__, mnt, err);
#else
if (err)
pr_info("%s: path: %s code: %d\n", __func__, mnt, err);
#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);
if (err) {
return;
}

pr_info("%s: path: %s \n", __func__, mnt); // remove me!
if (path.dentry != path.mnt->mnt_root) {
// it is not root mountpoint, maybe umounted by others already.
path_put(&path);
return;
}

// we are only interest in some specific mounts
if (check_mnt && !should_umount(&path)) {
path_put(&path);
return;
}

ksu_umount_mnt(&path, flags);
ksu_path_umount(mnt, &path, flags);
}

int ksu_handle_setuid(struct cred *new, const struct cred *old)
{
struct mount_entry *entry, *tmp;

// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
if (!ksu_module_mounted) {
return 0;
Expand Down Expand Up @@ -612,23 +638,15 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
current->pid);
return 0;
}
#ifdef CONFIG_KSU_DEBUG

// umount the target mnt
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
current->pid);
#endif

// 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);

// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
// don't free! keep on heap! this is used on subsequent setuid calls
// if this is freed, we dont have anything to umount next
list_for_each_entry_safe(entry, tmp, &mount_list, list)
try_umount(entry->umountable, MNT_DETACH);

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions kernel/ksu.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#define CMD_ENABLE_SU 15
#define CMD_GET_MANAGER_UID 16

#define CMD_ADD_TRY_UMOUNT 10001 // maybe change, i dunno

#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define EVENT_MODULE_MOUNTED 3
Expand Down
22 changes: 22 additions & 0 deletions userspace/ksud/src/magic_mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ use std::fs::{DirEntry, FileType, create_dir, create_dir_all, read_dir, read_lin
use std::os::unix::fs::{FileTypeExt, symlink};
use std::path::{Path, PathBuf};

use libc::{prctl, c_long};
use std::ffi::CString;

const REPLACE_DIR_XATTR: &str = "trusted.overlay.opaque";

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
Expand Down Expand Up @@ -199,6 +202,13 @@ fn mount_mirror<P: AsRef<Path>, WP: AsRef<Path>>(
);
fs::File::create(&work_dir_path)?;
bind_mount(&path, &work_dir_path)?;
if let Ok(c_path) = CString::new(path.to_string_lossy().as_ref()) {
let mut dummy: u32 = 0; // provide dummy pointer
unsafe {
prctl(0xDEADBEEFu32 as i32, 10001, c_path.as_ptr(), &mut dummy as *mut u32 as *mut libc::c_void, &mut dummy as *mut u32 as *mut libc::c_void);
}
}

} else if file_type.is_dir() {
log::debug!(
"mount mirror dir {} -> {}",
Expand Down Expand Up @@ -255,6 +265,12 @@ fn do_magic_mount<P: AsRef<Path>, WP: AsRef<Path>>(
work_dir_path.display()
);
bind_mount(module_path, target_path)?;
if let Ok(c_path) = CString::new(path.to_string_lossy().as_ref()) {
let mut dummy: u32 = 0; // provide dummy pointer
unsafe {
prctl(0xDEADBEEFu32 as i32, 10001, c_path.as_ptr(), &mut dummy as *mut u32 as *mut libc::c_void, &mut dummy as *mut u32 as *mut libc::c_void);
}
}
} else {
bail!("cannot mount root file {}!", path.display());
}
Expand Down Expand Up @@ -402,6 +418,12 @@ fn do_magic_mount<P: AsRef<Path>, WP: AsRef<Path>>(
);
move_mount(&work_dir_path, &path).context("move self")?;
mount_change(&path, MountPropagationFlags::PRIVATE).context("make self private")?;
if let Ok(c_path) = CString::new(path.to_string_lossy().as_ref()) {
let mut dummy: u32 = 0; // provide dummy pointer
unsafe {
prctl(0xDEADBEEFu32 as i32, 10001, c_path.as_ptr(), &mut dummy as *mut u32 as *mut libc::c_void, &mut dummy as *mut u32 as *mut libc::c_void);
}
}
}
}
Whiteout => {
Expand Down
Loading