From db600d5ea0ab881f1ad908acbac278ad04471ab2 Mon Sep 17 00:00:00 2001 From: Ylarod Date: Thu, 26 Jan 2023 11:29:02 +0800 Subject: [PATCH] kernel: precise trigger timing of post-fs-data (#118) * kernel: add report_event cmd * ksud: report event * kernel: trigger on_post_fs_data * ksud: comment unused code * [skip ci] run clang-format Signed-off-by: Ylarod * ci: use custom key to sign official bootimgs * format ksud * reject non root * remove Signed-off-by: Ylarod --- kernel/allowlist.c | 9 +++-- kernel/core_hook.c | 32 +++++++++++++++++- kernel/ksu.c | 4 +-- kernel/ksu.h | 5 ++- kernel/ksud.c | 17 ++++++++-- kernel/ksud.h | 6 ++++ kernel/manager.c | 2 +- kernel/selinux/rules.c | 2 +- kernel/selinux/selinux.c | 2 +- kernel/uid_observer.c | 2 +- userspace/ksud/Cargo.lock | 1 + userspace/ksud/Cargo.toml | 1 + userspace/ksud/src/cli.rs | 29 +++++++++------- userspace/ksud/src/defs.rs | 2 +- userspace/ksud/src/event.rs | 2 ++ userspace/ksud/src/ksu.rs | 58 ++++++++++++++++++++++++++++++++ userspace/ksud/src/main.rs | 15 +++++---- userspace/ksud/src/module.rs | 16 +++++++-- userspace/ksud/src/restorecon.rs | 2 +- 19 files changed, 170 insertions(+), 37 deletions(-) create mode 100644 kernel/ksud.h create mode 100644 userspace/ksud/src/ksu.rs diff --git a/kernel/allowlist.c b/kernel/allowlist.c index df1202fe..23a041ce 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -5,8 +5,9 @@ #include "linux/printk.h" #include "linux/slab.h" -#include "selinux/selinux.h" #include "klog.h" // IWYU pragma: keep +#include "selinux/selinux.h" + #define FILE_MAGIC 0x7f4b5355 // ' KSU', u32 #define FILE_FORMAT_VERSION 1 // u32 @@ -27,7 +28,8 @@ static struct work_struct ksu_load_work; bool persistent_allow_list(void); -void ksu_show_allow_list(void){ +void ksu_show_allow_list(void) +{ struct perm_data *p = NULL; struct list_head *pos = NULL; pr_info("ksu_show_allow_list"); @@ -179,7 +181,8 @@ void do_load_allow_list(struct work_struct *work) #ifdef CONFIG_KSU_DEBUG int errno = PTR_ERR(fp); if (errno == -ENOENT) { - ksu_allow_uid(2000, true, true); // allow adb shell by default + ksu_allow_uid(2000, true, + true); // allow adb shell by default } else { pr_err("load_allow_list open file failed: %d\n", PTR_ERR(fp)); diff --git a/kernel/core_hook.c b/kernel/core_hook.c index e1dd50ba..2ba85f8b 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -4,6 +4,7 @@ #include "linux/kernel.h" #include "linux/kprobes.h" #include "linux/lsm_hooks.h" +#include "linux/printk.h" #include "linux/uaccess.h" #include "linux/uidgid.h" #include "linux/version.h" @@ -15,11 +16,12 @@ #include "allowlist.h" #include "arch.h" #include "core_hook.h" +#include "klog.h" // IWYU pragma: keep #include "ksu.h" +#include "ksud.h" #include "manager.h" #include "selinux/selinux.h" #include "uid_observer.h" -#include "klog.h" // IWYU pragma: keep static inline bool is_allow_su() { @@ -200,6 +202,34 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3, } } + if (arg2 == CMD_REPORT_EVENT) { + if (0 != current_uid().val) { + return 0; + } + switch (arg3) { + case EVENT_POST_FS_DATA: { + static bool post_fs_data_lock = false; + if (!post_fs_data_lock) { + post_fs_data_lock = true; + pr_info("post-fs-data triggered"); + on_post_fs_data(); + } + break; + } + case EVENT_BOOT_COMPLETED: { + static bool boot_complete_lock = false; + if (!boot_complete_lock) { + boot_complete_lock = true; + pr_info("boot_complete triggered"); + } + break; + } + default: + break; + } + return 0; + } + // all other cmds are for 'root manager' if (!is_manager()) { pr_info("Only manager can do cmd: %d\n", arg2); diff --git a/kernel/ksu.c b/kernel/ksu.c index 5016d37f..26997edb 100644 --- a/kernel/ksu.c +++ b/kernel/ksu.c @@ -1,13 +1,13 @@ +#include "linux/fs.h" #include "linux/module.h" #include "linux/workqueue.h" -#include "linux/fs.h" #include "allowlist.h" #include "arch.h" #include "core_hook.h" +#include "klog.h" // IWYU pragma: keep #include "ksu.h" #include "uid_observer.h" -#include "klog.h" // IWYU pragma: keep static struct workqueue_struct *ksu_workqueue; diff --git a/kernel/ksu.h b/kernel/ksu.h index 650f7509..161e05be 100644 --- a/kernel/ksu.h +++ b/kernel/ksu.h @@ -8,13 +8,16 @@ #define KERNEL_SU_OPTION 0xDEADBEEF #define CMD_GRANT_ROOT 0 - #define CMD_BECOME_MANAGER 1 #define CMD_GET_VERSION 2 #define CMD_ALLOW_SU 3 #define CMD_DENY_SU 4 #define CMD_GET_ALLOW_LIST 5 #define CMD_GET_DENY_LIST 6 +#define CMD_REPORT_EVENT 7 + +#define EVENT_POST_FS_DATA 1 +#define EVENT_BOOT_COMPLETED 2 bool ksu_queue_work(struct work_struct *work); diff --git a/kernel/ksud.c b/kernel/ksud.c index 92f8f6b7..9a3a2258 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -4,6 +4,7 @@ #include "linux/err.h" #include "linux/fs.h" #include "linux/kprobes.h" +#include "linux/printk.h" #include "linux/types.h" #include "linux/uaccess.h" #include "linux/version.h" @@ -11,8 +12,8 @@ #include "allowlist.h" #include "arch.h" -#include "selinux/selinux.h" #include "klog.h" // IWYU pragma: keep +#include "selinux/selinux.h" static const char KERNEL_SU_RC[] = "\n" @@ -47,6 +48,18 @@ static bool vfs_read_hook = true; static bool execveat_hook = true; #endif +void on_post_fs_data(void) +{ + static bool done = false; + if (done) { + pr_info("on_post_fs_data already done"); + return; + } + done = true; + pr_info("ksu_load_allow_list"); + ksu_load_allow_list(); +} + int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags) { @@ -85,7 +98,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, !memcmp(filename->name, app_process, sizeof(app_process) - 1)) { first_app_process = false; pr_info("exec app_process, /data prepared!\n"); - ksu_load_allow_list(); + on_post_fs_data(); // we keep this for old ksud stop_execve_hook(); } diff --git a/kernel/ksud.h b/kernel/ksud.h new file mode 100644 index 00000000..99423c58 --- /dev/null +++ b/kernel/ksud.h @@ -0,0 +1,6 @@ +#ifndef __KSU_H_KSUD +#define __KSU_H_KSUD + +void on_post_fs_data(void); + +#endif \ No newline at end of file diff --git a/kernel/manager.c b/kernel/manager.c index 93978328..19528083 100644 --- a/kernel/manager.c +++ b/kernel/manager.c @@ -9,9 +9,9 @@ #include "linux/rcupdate.h" #include "apk_sign.h" +#include "klog.h" // IWYU pragma: keep #include "ksu.h" #include "manager.h" -#include "klog.h" // IWYU pragma: keep uid_t ksu_manager_uid = INVALID_UID; diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index e43af38d..190661d2 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -1,9 +1,9 @@ #include "linux/version.h" +#include "../klog.h" // IWYU pragma: keep #include "selinux.h" #include "sepolicy.h" #include "ss/services.h" -#include "../klog.h" // IWYU pragma: keep #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) #define SELINUX_POLICY_INSTEAD_SELINUX_SS diff --git a/kernel/selinux/selinux.c b/kernel/selinux/selinux.c index 586eb3a5..292c29f1 100644 --- a/kernel/selinux/selinux.c +++ b/kernel/selinux/selinux.c @@ -1,5 +1,5 @@ -#include "objsec.h" #include "selinux.h" +#include "objsec.h" #include "../klog.h" // IWYU pragma: keep diff --git a/kernel/uid_observer.c b/kernel/uid_observer.c index 4f909e70..20c93c25 100644 --- a/kernel/uid_observer.c +++ b/kernel/uid_observer.c @@ -8,10 +8,10 @@ #include "linux/workqueue.h" #include "allowlist.h" +#include "klog.h" // IWYU pragma: keep #include "ksu.h" #include "manager.h" #include "uid_observer.h" -#include "klog.h" // IWYU pragma: keep #define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list" static struct work_struct ksu_update_uid_work; diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock index d05454bf..19c6f910 100644 --- a/userspace/ksud/Cargo.lock +++ b/userspace/ksud/Cargo.lock @@ -445,6 +445,7 @@ dependencies = [ "env_logger", "humansize", "java-properties", + "libc", "log", "regex", "retry", diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml index 6e908e3d..8b087c08 100644 --- a/userspace/ksud/Cargo.toml +++ b/userspace/ksud/Cargo.toml @@ -22,6 +22,7 @@ regex = "1.5.4" encoding = "0.2.33" retry = "2.0.0" humansize = "2.0.0" +libc = "0.2" [profile.release] strip = true diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index a35a09ae..2e26861d 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -1,7 +1,7 @@ -use anyhow::Result; +use anyhow::{Ok, Result}; use clap::Parser; -use crate::{event, module, debug, apk_sign}; +use crate::{apk_sign, debug, event, module}; /// KernelSU userspace cli #[derive(Parser, Debug)] @@ -58,6 +58,9 @@ enum Debug { apk: String, }, + /// Get kernel version + Version, + /// For testing Test, } @@ -115,17 +118,19 @@ pub fn run() -> Result<()> { Commands::Sepolicy => todo!(), Commands::Services => event::on_services(), - Commands::Debug { command } => { - match command { - Debug::SetManager { apk } => debug::set_manager(&apk), - Debug::GetSign { apk } => { - let sign = apk_sign::get_apk_signature(&apk)?; - println!("size: {:#x}, hash: {:#x}", sign.0, sign.1); - Ok(()) - }, - Debug::Test => todo!(), + Commands::Debug { command } => match command { + Debug::SetManager { apk } => debug::set_manager(&apk), + Debug::GetSign { apk } => { + let sign = apk_sign::get_apk_signature(&apk)?; + println!("size: {:#x}, hash: {:#x}", sign.0, sign.1); + Ok(()) } - } + Debug::Version => { + println!("Kernel Version: {}", crate::ksu::get_version()); + Ok(()) + } + Debug::Test => todo!(), + }, }; if let Err(e) = &result { diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs index bbdc0856..37b9f883 100644 --- a/userspace/ksud/src/defs.rs +++ b/userspace/ksud/src/defs.rs @@ -14,4 +14,4 @@ pub const MODULE_UPDATE_TMP_DIR: &str = concatcp!(WORKING_DIR, "modules_update/" pub const DISABLE_FILE_NAME: &str = "disable"; pub const UPDATE_FILE_NAME: &str = "update"; -pub const REMOVE_FILE_NAME: &str = "remove"; \ No newline at end of file +pub const REMOVE_FILE_NAME: &str = "remove"; diff --git a/userspace/ksud/src/event.rs b/userspace/ksud/src/event.rs index 555603f7..d82fb78e 100644 --- a/userspace/ksud/src/event.rs +++ b/userspace/ksud/src/event.rs @@ -89,6 +89,7 @@ pub fn do_systemless_mount(module_dir: &str) -> Result<()> { } pub fn on_post_data_fs() -> Result<()> { + crate::ksu::report_post_fs_data(); let module_update_img = defs::MODULE_UPDATE_IMG; let module_img = defs::MODULE_IMG; let module_dir = defs::MODULE_DIR; @@ -151,6 +152,7 @@ pub fn on_services() -> Result<()> { } pub fn on_boot_completed() -> Result<()> { + crate::ksu::report_boot_complete(); let module_update_img = Path::new(defs::MODULE_UPDATE_IMG); let module_img = Path::new(defs::MODULE_IMG); if module_update_img.exists() { diff --git a/userspace/ksud/src/ksu.rs b/userspace/ksud/src/ksu.rs new file mode 100644 index 00000000..80f4d129 --- /dev/null +++ b/userspace/ksud/src/ksu.rs @@ -0,0 +1,58 @@ +const KERNEL_SU_OPTION: u32 = 0xDEADBEEF; + +// const CMD_GRANT_ROOT: u64 = 0; +// const CMD_BECOME_MANAGER: u64 = 1; +const CMD_GET_VERSION: u64 = 2; +// const CMD_ALLOW_SU: u64 = 3; +// const CMD_DENY_SU: u64 = 4; +// const CMD_GET_ALLOW_LIST: u64 = 5; +// const CMD_GET_DENY_LIST: u64 = 6; +const CMD_REPORT_EVENT: u64 = 7; + +const EVENT_POST_FS_DATA: u64 = 1; +const EVENT_BOOT_COMPLETED: u64 = 2; + + +// pub fn grant_root() -> bool { +// let mut result: i32 = 0; +// unsafe { +// libc::prctl( +// KERNEL_SU_OPTION as i32, +// CMD_GRANT_ROOT, +// 0, +// 0, +// &mut result as *mut _ as *mut libc::c_void, +// ); +// } +// return result as u32 == KERNEL_SU_OPTION; +// } + +pub fn get_version() -> i32 { + let mut result: i32 = 0; + unsafe { + libc::prctl( + KERNEL_SU_OPTION as i32, + CMD_GET_VERSION, + &mut result as *mut _ as *mut libc::c_void, + ); + } + return result; +} + +fn report_event(event: u64){ + unsafe { + libc::prctl( + KERNEL_SU_OPTION as i32, + CMD_REPORT_EVENT, + event, + ); + } +} + +pub fn report_post_fs_data(){ + report_event(EVENT_POST_FS_DATA); +} + +pub fn report_boot_complete(){ + report_event(EVENT_BOOT_COMPLETED); +} \ No newline at end of file diff --git a/userspace/ksud/src/main.rs b/userspace/ksud/src/main.rs index df3cd039..14d8e91d 100644 --- a/userspace/ksud/src/main.rs +++ b/userspace/ksud/src/main.rs @@ -1,11 +1,12 @@ -mod cli; -mod event; -mod module; -mod defs; -mod utils; -mod restorecon; -mod debug; mod apk_sign; +mod cli; +mod debug; +mod defs; +mod event; +mod ksu; +mod module; +mod restorecon; +mod utils; fn main() -> anyhow::Result<()> { cli::run() diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index d9434565..1e3c76ec 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -109,7 +109,11 @@ fn check_image(img: &str) -> Result<()> { // 0: no error // 1: file system errors corrected // https://man7.org/linux/man-pages/man8/e2fsck.8.html - ensure!(code == Some(0) || code == Some(1), "check image e2fsck exec failed: {}", code.unwrap_or(-1)); + ensure!( + code == Some(0) || code == Some(1), + "check image e2fsck exec failed: {}", + code.unwrap_or(-1) + ); Ok(()) } @@ -120,7 +124,10 @@ fn grow_image_size(img: &str, extra_size: u64) -> Result<()> { // check image check_image(img)?; - println!("- Target image size: {}", humansize::format_size(target_size, humansize::DECIMAL)); + println!( + "- Target image size: {}", + humansize::format_size(target_size, humansize::DECIMAL) + ); let target_size = target_size / 1024 + 1; let result = Exec::shell(format!("resize2fs {} {}K", img, target_size)) @@ -331,7 +338,10 @@ pub fn install_module(zip: String) -> Result<()> { let grow_size_per_m = grow_size / 1024 / 1024 + 1; println!("- Preparing image"); - println!("- Module size: {}", humansize::format_size(zip_uncompressed_size, humansize::DECIMAL)); + println!( + "- Module size: {}", + humansize::format_size(zip_uncompressed_size, humansize::DECIMAL) + ); if !modules_img_exist && !modules_update_img_exist { // if no modules and modules_update, it is brand new installation, we should create a new img diff --git a/userspace/ksud/src/restorecon.rs b/userspace/ksud/src/restorecon.rs index e9658ee4..20e653f4 100644 --- a/userspace/ksud/src/restorecon.rs +++ b/userspace/ksud/src/restorecon.rs @@ -24,4 +24,4 @@ pub fn restore_syscon(dir: &str) -> Result<()> { let result = Exec::shell(cmd).join()?; ensure!(result.success(), "chcon for: {} failed.", dir); Ok(()) -} \ No newline at end of file +}