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 <me@ylarod.cn>

* ci: use custom key to sign official bootimgs

* format ksud

* reject non root

* remove

Signed-off-by: Ylarod <me@ylarod.cn>
This commit is contained in:
Ylarod
2023-01-26 11:29:02 +08:00
committed by GitHub
parent 22b66b6672
commit db600d5ea0
19 changed files with 170 additions and 37 deletions

View File

@@ -5,8 +5,9 @@
#include "linux/printk.h" #include "linux/printk.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "selinux/selinux.h"
#include "klog.h" // IWYU pragma: keep #include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32 #define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 1 // u32 #define FILE_FORMAT_VERSION 1 // u32
@@ -27,7 +28,8 @@ static struct work_struct ksu_load_work;
bool persistent_allow_list(void); bool persistent_allow_list(void);
void ksu_show_allow_list(void){ void ksu_show_allow_list(void)
{
struct perm_data *p = NULL; struct perm_data *p = NULL;
struct list_head *pos = NULL; struct list_head *pos = NULL;
pr_info("ksu_show_allow_list"); pr_info("ksu_show_allow_list");
@@ -179,7 +181,8 @@ void do_load_allow_list(struct work_struct *work)
#ifdef CONFIG_KSU_DEBUG #ifdef CONFIG_KSU_DEBUG
int errno = PTR_ERR(fp); int errno = PTR_ERR(fp);
if (errno == -ENOENT) { 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 { } else {
pr_err("load_allow_list open file failed: %d\n", pr_err("load_allow_list open file failed: %d\n",
PTR_ERR(fp)); PTR_ERR(fp));

View File

@@ -4,6 +4,7 @@
#include "linux/kernel.h" #include "linux/kernel.h"
#include "linux/kprobes.h" #include "linux/kprobes.h"
#include "linux/lsm_hooks.h" #include "linux/lsm_hooks.h"
#include "linux/printk.h"
#include "linux/uaccess.h" #include "linux/uaccess.h"
#include "linux/uidgid.h" #include "linux/uidgid.h"
#include "linux/version.h" #include "linux/version.h"
@@ -15,11 +16,12 @@
#include "allowlist.h" #include "allowlist.h"
#include "arch.h" #include "arch.h"
#include "core_hook.h" #include "core_hook.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h" #include "ksu.h"
#include "ksud.h"
#include "manager.h" #include "manager.h"
#include "selinux/selinux.h" #include "selinux/selinux.h"
#include "uid_observer.h" #include "uid_observer.h"
#include "klog.h" // IWYU pragma: keep
static inline bool is_allow_su() 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' // all other cmds are for 'root manager'
if (!is_manager()) { if (!is_manager()) {
pr_info("Only manager can do cmd: %d\n", arg2); pr_info("Only manager can do cmd: %d\n", arg2);

View File

@@ -1,13 +1,13 @@
#include "linux/fs.h"
#include "linux/module.h" #include "linux/module.h"
#include "linux/workqueue.h" #include "linux/workqueue.h"
#include "linux/fs.h"
#include "allowlist.h" #include "allowlist.h"
#include "arch.h" #include "arch.h"
#include "core_hook.h" #include "core_hook.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h" #include "ksu.h"
#include "uid_observer.h" #include "uid_observer.h"
#include "klog.h" // IWYU pragma: keep
static struct workqueue_struct *ksu_workqueue; static struct workqueue_struct *ksu_workqueue;

View File

@@ -8,13 +8,16 @@
#define KERNEL_SU_OPTION 0xDEADBEEF #define KERNEL_SU_OPTION 0xDEADBEEF
#define CMD_GRANT_ROOT 0 #define CMD_GRANT_ROOT 0
#define CMD_BECOME_MANAGER 1 #define CMD_BECOME_MANAGER 1
#define CMD_GET_VERSION 2 #define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3 #define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4 #define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5 #define CMD_GET_ALLOW_LIST 5
#define CMD_GET_DENY_LIST 6 #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); bool ksu_queue_work(struct work_struct *work);

View File

@@ -4,6 +4,7 @@
#include "linux/err.h" #include "linux/err.h"
#include "linux/fs.h" #include "linux/fs.h"
#include "linux/kprobes.h" #include "linux/kprobes.h"
#include "linux/printk.h"
#include "linux/types.h" #include "linux/types.h"
#include "linux/uaccess.h" #include "linux/uaccess.h"
#include "linux/version.h" #include "linux/version.h"
@@ -11,8 +12,8 @@
#include "allowlist.h" #include "allowlist.h"
#include "arch.h" #include "arch.h"
#include "selinux/selinux.h"
#include "klog.h" // IWYU pragma: keep #include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
static const char KERNEL_SU_RC[] = static const char KERNEL_SU_RC[] =
"\n" "\n"
@@ -47,6 +48,18 @@ static bool vfs_read_hook = true;
static bool execveat_hook = true; static bool execveat_hook = true;
#endif #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, int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags) 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)) { !memcmp(filename->name, app_process, sizeof(app_process) - 1)) {
first_app_process = false; first_app_process = false;
pr_info("exec app_process, /data prepared!\n"); 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(); stop_execve_hook();
} }

6
kernel/ksud.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __KSU_H_KSUD
#define __KSU_H_KSUD
void on_post_fs_data(void);
#endif

View File

@@ -9,9 +9,9 @@
#include "linux/rcupdate.h" #include "linux/rcupdate.h"
#include "apk_sign.h" #include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h" #include "ksu.h"
#include "manager.h" #include "manager.h"
#include "klog.h" // IWYU pragma: keep
uid_t ksu_manager_uid = INVALID_UID; uid_t ksu_manager_uid = INVALID_UID;

View File

@@ -1,9 +1,9 @@
#include "linux/version.h" #include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep
#include "selinux.h" #include "selinux.h"
#include "sepolicy.h" #include "sepolicy.h"
#include "ss/services.h" #include "ss/services.h"
#include "../klog.h" // IWYU pragma: keep
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
#define SELINUX_POLICY_INSTEAD_SELINUX_SS #define SELINUX_POLICY_INSTEAD_SELINUX_SS

View File

@@ -1,5 +1,5 @@
#include "objsec.h"
#include "selinux.h" #include "selinux.h"
#include "objsec.h"
#include "../klog.h" // IWYU pragma: keep #include "../klog.h" // IWYU pragma: keep

View File

@@ -8,10 +8,10 @@
#include "linux/workqueue.h" #include "linux/workqueue.h"
#include "allowlist.h" #include "allowlist.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h" #include "ksu.h"
#include "manager.h" #include "manager.h"
#include "uid_observer.h" #include "uid_observer.h"
#include "klog.h" // IWYU pragma: keep
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list" #define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
static struct work_struct ksu_update_uid_work; static struct work_struct ksu_update_uid_work;

View File

@@ -445,6 +445,7 @@ dependencies = [
"env_logger", "env_logger",
"humansize", "humansize",
"java-properties", "java-properties",
"libc",
"log", "log",
"regex", "regex",
"retry", "retry",

View File

@@ -22,6 +22,7 @@ regex = "1.5.4"
encoding = "0.2.33" encoding = "0.2.33"
retry = "2.0.0" retry = "2.0.0"
humansize = "2.0.0" humansize = "2.0.0"
libc = "0.2"
[profile.release] [profile.release]
strip = true strip = true

View File

@@ -1,7 +1,7 @@
use anyhow::Result; use anyhow::{Ok, Result};
use clap::Parser; use clap::Parser;
use crate::{event, module, debug, apk_sign}; use crate::{apk_sign, debug, event, module};
/// KernelSU userspace cli /// KernelSU userspace cli
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@@ -58,6 +58,9 @@ enum Debug {
apk: String, apk: String,
}, },
/// Get kernel version
Version,
/// For testing /// For testing
Test, Test,
} }
@@ -115,17 +118,19 @@ pub fn run() -> Result<()> {
Commands::Sepolicy => todo!(), Commands::Sepolicy => todo!(),
Commands::Services => event::on_services(), Commands::Services => event::on_services(),
Commands::Debug { command } => { Commands::Debug { command } => match command {
match command { Debug::SetManager { apk } => debug::set_manager(&apk),
Debug::SetManager { apk } => debug::set_manager(&apk), Debug::GetSign { apk } => {
Debug::GetSign { apk } => { let sign = apk_sign::get_apk_signature(&apk)?;
let sign = apk_sign::get_apk_signature(&apk)?; println!("size: {:#x}, hash: {:#x}", sign.0, sign.1);
println!("size: {:#x}, hash: {:#x}", sign.0, sign.1); Ok(())
Ok(())
},
Debug::Test => todo!(),
} }
} Debug::Version => {
println!("Kernel Version: {}", crate::ksu::get_version());
Ok(())
}
Debug::Test => todo!(),
},
}; };
if let Err(e) = &result { if let Err(e) = &result {

View File

@@ -89,6 +89,7 @@ pub fn do_systemless_mount(module_dir: &str) -> Result<()> {
} }
pub fn on_post_data_fs() -> Result<()> { pub fn on_post_data_fs() -> Result<()> {
crate::ksu::report_post_fs_data();
let module_update_img = defs::MODULE_UPDATE_IMG; let module_update_img = defs::MODULE_UPDATE_IMG;
let module_img = defs::MODULE_IMG; let module_img = defs::MODULE_IMG;
let module_dir = defs::MODULE_DIR; let module_dir = defs::MODULE_DIR;
@@ -151,6 +152,7 @@ pub fn on_services() -> Result<()> {
} }
pub fn on_boot_completed() -> Result<()> { pub fn on_boot_completed() -> Result<()> {
crate::ksu::report_boot_complete();
let module_update_img = Path::new(defs::MODULE_UPDATE_IMG); let module_update_img = Path::new(defs::MODULE_UPDATE_IMG);
let module_img = Path::new(defs::MODULE_IMG); let module_img = Path::new(defs::MODULE_IMG);
if module_update_img.exists() { if module_update_img.exists() {

58
userspace/ksud/src/ksu.rs Normal file
View File

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

View File

@@ -1,11 +1,12 @@
mod cli;
mod event;
mod module;
mod defs;
mod utils;
mod restorecon;
mod debug;
mod apk_sign; mod apk_sign;
mod cli;
mod debug;
mod defs;
mod event;
mod ksu;
mod module;
mod restorecon;
mod utils;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
cli::run() cli::run()

View File

@@ -109,7 +109,11 @@ fn check_image(img: &str) -> Result<()> {
// 0: no error // 0: no error
// 1: file system errors corrected // 1: file system errors corrected
// https://man7.org/linux/man-pages/man8/e2fsck.8.html // 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(()) Ok(())
} }
@@ -120,7 +124,10 @@ fn grow_image_size(img: &str, extra_size: u64) -> Result<()> {
// check image // check image
check_image(img)?; 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 target_size = target_size / 1024 + 1;
let result = Exec::shell(format!("resize2fs {} {}K", img, target_size)) 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; let grow_size_per_m = grow_size / 1024 / 1024 + 1;
println!("- Preparing image"); 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 !modules_img_exist && !modules_update_img_exist {
// if no modules and modules_update, it is brand new installation, we should create a new img // if no modules and modules_update, it is brand new installation, we should create a new img