diff --git a/bin/aot.rs b/bin/aot.rs new file mode 100644 index 0000000000000000000000000000000000000000..047f5429cb82e21b9b2f89bb778ffac5f46e7910 --- /dev/null +++ b/bin/aot.rs @@ -0,0 +1,155 @@ +// Copyright (c) 2023 Huawei Technologies Co., Ltd. +// sysboost is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Create: 2023-8-26 + +use crate::lib::fs_ext; +use crate::lib::process_ext::run_child; +use crate::common::SYSBOOST_PATH; +use crate::config::RtoConfig; + +use std::{fs, env}; +use std::path::Path; +use goblin::elf::Elf; + +// Obtain the full path from real path, environment variable PATH, current dir +fn get_lib_full_path(lib: &str, confpaths:Vec<&str>, rpaths: Vec<&str>, paths: Vec<&str>) -> Option { + if !(confpaths.is_empty()) { + for confpath in confpaths { + let full_dir = fs_ext::find_file_in_dirs(&lib, &confpath); + if let Some(ref _n) = full_dir { + return full_dir; + } + } + } else if !(rpaths.is_empty()) { + for rpath in rpaths { + let full_dir = fs_ext::find_file_in_dirs(&lib, &rpath); + if let Some(ref _n) = full_dir { + return full_dir; + } + } + } else if !(paths.is_empty()) { + for path in paths { + let full_dir = fs_ext::find_file_in_dirs(&lib, &path); + if let Some(ref _n) = full_dir { + return full_dir; + } + } + } else { + let d = "./"; + let full_dir = fs_ext::find_file_in_dirs(&lib, &d); + if let Some(ref _n) = full_dir { + return full_dir; + } + } + None +} + +// read elf file as using readelf +pub fn parse_elf_file(elf_path: &str) -> Option { + let elf_bytes = match fs::read(&elf_path) { + Ok(elf_bytes) => elf_bytes, + Err(_e) => { + log::info!("Error: read elf file fault, please check config."); + return None + } + }; + match Elf::parse(&elf_bytes) { + Ok(elf) => Some(elf), + Err(_e) => { + log::info!("Error: parse elf file fault, please check the elf file"); + None + } + }; + None +} + +pub fn find_libs(conf: &RtoConfig, elf: &Elf) -> Vec { + let mut libs = conf.libs.clone(); + + let confpaths_temp = conf.path.as_ref().map_or_else(String::new, |v| v.clone()); + let confpaths: Vec<&str> = confpaths_temp.split(':').collect(); + let rpaths = elf.rpaths.clone(); + if let Some(paths_temp) = env::var_os("PATH") { + let paths_str = paths_temp.to_string_lossy(); + let lib_paths: Vec<&str> = paths_str.split(':').collect(); + for lib in elf.libraries.iter() { + let findlib = get_lib_full_path(lib, confpaths.clone(), rpaths.clone(), lib_paths.clone()).unwrap_or("".to_string()); + libs.push(findlib); + } + libs + } else { + log::info!("The environment variable PATH is empty. Please check."); + libs + } +} + +pub fn set_app_aot_flag(old_path: &String, is_set: bool) -> i32 { + let mut args: Vec = Vec::new(); + let setfattr = "setfattr".to_string(); + args.push("-n".to_string()); + args.push("trusted.sysboost_flags".to_string()); + args.push("-v".to_string()); + if is_set { + args.push("true".to_string()); + } else { + args.push("false".to_string()); + } + let old_path = Path::new(old_path); + let old_path = match fs::canonicalize(old_path) { + Ok(p) => p, + Err(e) => { + log::error!("get realpath failed: {}", e); + return -1; + } + }; + let new_path = old_path.with_extension("bak"); + match fs::copy(&old_path, &new_path) { + Ok(_) => {} + Err(e) => { + log::error!("Copy failed: {}", e); + return -1; + } + } + args.push(new_path.to_str().unwrap().to_string()); + let ret = run_child(&setfattr, &args); + match fs::rename(&new_path, &old_path) { + Ok(_) => {} + Err(e) => { + log::error!("Mv failed: {}", e); + return -1; + } + } + return ret; +} + +// 生成rto文件 +// rto文件先生成到临时文件, 然后mv到最终路径, 避免并发操作文件问题 +// sysboost --output=/usr/bin/bash.tmp.rto -static /usr/bin/bash lib1 lib2 +pub fn gen_app_rto(conf: &RtoConfig) -> i32 { + if let Some(_p) = &conf.profile_path.clone() { + log::error!("Configuration file fail"); + return -1; + } + + let mut args: Vec = Vec::new(); + args.push(format!("--output={}.tmp.rto", conf.elf_path)); + args.push(format!("-{}", conf.mode)); + args.push(conf.elf_path.to_owned()); + for lib in conf.libs.iter() { + args.push(lib.split_whitespace().collect()); + } + let mut ret = run_child(SYSBOOST_PATH, &args); + if ret != 0 { + return ret; + } + + ret = fs_ext::move_file(&format!("{}.rto", conf.elf_path), &format!("{}.tmp.rto", conf.elf_path)); + return ret; +} diff --git a/bin/common.rs b/bin/common.rs new file mode 100644 index 0000000000000000000000000000000000000000..1ce5c980c7d628e02998abe4de4c636c60eb65df --- /dev/null +++ b/bin/common.rs @@ -0,0 +1,12 @@ +// Copyright (c) 2023 Huawei Technologies Co., Ltd. +// sysboost is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Create: 2023-8-26 + +pub const SYSBOOST_PATH: &str = "/usr/bin/sysboost"; diff --git a/bin/config.rs b/bin/config.rs index 897ed7dea9e7b649c939ec3299e0bca8dc129d85..dd3b134acf20f4e65e621b7ead0abae2f8857ffe 100644 --- a/bin/config.rs +++ b/bin/config.rs @@ -9,8 +9,12 @@ // See the Mulan PSL v2 for more details. // Create: 2023-8-28 +use crate::common::SYSBOOST_PATH; + use serde::Deserialize; use std::str::FromStr; +use std::path::PathBuf; +use std::fs; #[derive(Debug, Deserialize)] pub struct RtoConfig { @@ -33,3 +37,44 @@ impl FromStr for RtoConfig { toml::from_str(s) } } + +// elf_path = "/usr/bin/bash" +// mode = "static" +// libs = "/usr/lib64/libtinfo.so.6" +fn parse_config(contents: String) -> Option { + let conf_e = contents.parse::(); + match conf_e { + Ok(ref c) => log::info!("parse config: {:?}", c), + Err(_) => { + log::error!("parse config fail"); + return None; + } + }; + + let conf = conf_e.unwrap(); + if conf.mode != "static" && conf.mode != "static-nolibc" && conf.mode != "share" && conf.mode != "bolt" { + return None; + } + if conf.elf_path == SYSBOOST_PATH { + // the tool can not renew self code + return None; + } + + return Some(conf); +} + +pub fn read_config(path: &PathBuf) -> Option { + let ext = path.extension(); + if ext == None || ext.unwrap() != "toml" { + return None; + } + + let contents = match fs::read_to_string(path) { + Ok(c) => c, + Err(e) => { + log::error!("reading file fail {}", e); + return None; + } + }; + return parse_config(contents); +} diff --git a/bin/coredump_monitor.rs b/bin/coredump_monitor.rs index c6dfad042ebf40ca3020e53625c669870a4c84fb..57da3b61a307de04734486988a89d4b11e836019 100644 --- a/bin/coredump_monitor.rs +++ b/bin/coredump_monitor.rs @@ -9,6 +9,7 @@ // See the Mulan PSL v2 for more details. // Create: 2023-7-13 +use crate::aot::set_app_aot_flag; use crate::daemon; use log::{self}; @@ -59,7 +60,7 @@ fn process_exec_event(pid: i32) { fn do_bash_rollback() -> i32 { // unset flag - let ret = daemon::set_app_aot_flag(&BASH_PATH.to_string(), false); + let ret = set_app_aot_flag(&BASH_PATH.to_string(), false); if ret != 0 { log::error!("Failed to unset flag for bash!"); return ret; diff --git a/bin/daemon.rs b/bin/daemon.rs index 1686a6071c444d9d1d6735eace595c344844c710..8f552f1cc9666f8dbf239f5165a41d9993fb1ff8 100644 --- a/bin/daemon.rs +++ b/bin/daemon.rs @@ -10,23 +10,25 @@ // Create: 2023-4-20 use crate::lib::fs_ext; -use crate::lib::process_ext::run_child; +use crate::kmod_util::set_ko_rto_flag; +use crate::kmod_util::insmod_sysboost_ko; use crate::config::RtoConfig; +use crate::config::read_config; +use crate::aot::gen_app_rto; +use crate::aot::set_app_aot_flag; +use crate::aot::parse_elf_file; +use crate::aot::find_libs; use crate::bolt::bolt_optimize; use inotify::{EventMask, Inotify, WatchMask}; use log::{self}; -use std::{fs, env}; +use std::fs; use std::os::unix::fs as UnixFs; use std::path::{Path, PathBuf}; use std::thread; use std::time::Duration; -use goblin::elf::Elf; -const SYSBOOST_PATH: &str = "/usr/bin/sysboost"; const SYSBOOST_DB_PATH: &str = "/var/lib/sysboost/"; -const KO_PATH: &str = "/lib/modules/sysboost/sysboost_loader.ko"; -const KO_RTO_PARAM_PATH: &str = "/sys/module/sysboost_loader/parameters/use_rto"; const LDSO: &str = "ld-"; const LIBCSO: &str = "libc.so"; @@ -62,197 +64,6 @@ pub fn db_remove_link(path: &String) { }; } -// echo 1 > /sys/module/sysboost_loader/parameters/use_rto -fn set_ko_rto_flag(is_set: bool) -> i32 { - let mut args: Vec = Vec::new(); - if is_set { - args.push("1".to_string()); - } else { - args.push("0".to_string()); - } - args.push(">".to_string()); - args.push(KO_RTO_PARAM_PATH.to_string()); - let ret = run_child("/usr/bin/echo", &args); - return ret; -} - -// 生成rto文件 -// rto文件先生成到临时文件, 然后mv到最终路径, 避免并发操作文件问题 -// sysboost --output=/usr/bin/bash.tmp.rto -static /usr/bin/bash lib1 lib2 -fn gen_app_rto(conf: &RtoConfig) -> i32 { - if let Some(_p) = &conf.profile_path.clone() { - log::error!("Configuration file fail"); - return -1; - } - - let mut args: Vec = Vec::new(); - args.push(format!("--output={}.tmp.rto", conf.elf_path)); - args.push(format!("-{}", conf.mode)); - args.push(conf.elf_path.to_owned()); - for lib in conf.libs.iter() { - args.push(lib.split_whitespace().collect()); - } - let mut ret = run_child(SYSBOOST_PATH, &args); - if ret != 0 { - return ret; - } - - ret = fs_ext::move_file(&format!("{}.rto", conf.elf_path), &format!("{}.tmp.rto", conf.elf_path)); - return ret; -} - -pub fn set_app_aot_flag(old_path: &String, is_set: bool) -> i32 { - let mut args: Vec = Vec::new(); - let setfattr = "setfattr".to_string(); - args.push("-n".to_string()); - args.push("trusted.sysboost_flags".to_string()); - args.push("-v".to_string()); - if is_set { - args.push("true".to_string()); - } else { - args.push("false".to_string()); - } - let old_path = Path::new(old_path); - let old_path = match fs::canonicalize(old_path) { - Ok(p) => p, - Err(e) => { - log::error!("get realpath failed: {}", e); - return -1; - } - }; - let new_path = old_path.with_extension("bak"); - match fs::copy(&old_path, &new_path) { - Ok(_) => {} - Err(e) => { - log::error!("Copy failed: {}", e); - return -1; - } - } - args.push(new_path.to_str().unwrap().to_string()); - let ret = run_child(&setfattr, &args); - match fs::rename(&new_path, &old_path) { - Ok(_) => {} - Err(e) => { - log::error!("Mv failed: {}", e); - return -1; - } - } - return ret; -} - -// elf_path = "/usr/bin/bash" -// mode = "static" -// libs = "/usr/lib64/libtinfo.so.6" -fn parse_config(contents: String) -> Option { - let conf_e = contents.parse::(); - match conf_e { - Ok(ref c) => log::info!("parse config: {:?}", c), - Err(_) => { - log::error!("parse config fail"); - return None; - } - }; - - let conf = conf_e.unwrap(); - if conf.mode != "static" && conf.mode != "static-nolibc" && conf.mode != "share" && conf.mode != "bolt" { - return None; - } - if conf.elf_path == SYSBOOST_PATH { - // the tool can not renew self code - return None; - } - - return Some(conf); -} - -fn read_config(path: &PathBuf) -> Option { - let ext = path.extension(); - if ext == None || ext.unwrap() != "toml" { - return None; - } - - let contents = match fs::read_to_string(path) { - Ok(c) => c, - Err(e) => { - log::error!("reading file fail {}", e); - return None; - } - }; - return parse_config(contents); -} - -// Obtain the full path from real path, environment variable PATH, current dir -fn get_lib_full_path(lib: &str, confpaths:Vec<&str>, rpaths: Vec<&str>, paths: Vec<&str>) -> Option { - if !(confpaths.is_empty()) { - for confpath in confpaths { - let full_dir = fs_ext::find_file_in_dirs(&lib, &confpath); - if let Some(ref _n) = full_dir { - return full_dir; - } - } - } else if !(rpaths.is_empty()) { - for rpath in rpaths { - let full_dir = fs_ext::find_file_in_dirs(&lib, &rpath); - if let Some(ref _n) = full_dir { - return full_dir; - } - } - } else if !(paths.is_empty()) { - for path in paths { - let full_dir = fs_ext::find_file_in_dirs(&lib, &path); - if let Some(ref _n) = full_dir { - return full_dir; - } - } - } else { - let d = "./"; - let full_dir = fs_ext::find_file_in_dirs(&lib, &d); - if let Some(ref _n) = full_dir { - return full_dir; - } - } - None -} - -// read elf file as using readelf -fn parse_elf_file(elf_path: &str) -> Option { - let elf_bytes = match fs::read(&elf_path) { - Ok(elf_bytes) => elf_bytes, - Err(_e) => { - log::info!("Error: read elf file fault, please check config."); - return None - } - }; - match Elf::parse(&elf_bytes) { - Ok(elf) => Some(elf), - Err(_e) => { - log::info!("Error: parse elf file fault, please check the elf file"); - None - } - }; - None -} - -fn find_libs(conf: &RtoConfig, elf: &Elf) -> Vec { - let mut libs = conf.libs.clone(); - - let confpaths_temp = conf.path.as_ref().map_or_else(String::new, |v| v.clone()); - let confpaths: Vec<&str> = confpaths_temp.split(':').collect(); - let rpaths = elf.rpaths.clone(); - if let Some(paths_temp) = env::var_os("PATH") { - let paths_str = paths_temp.to_string_lossy(); - let lib_paths: Vec<&str> = paths_str.split(':').collect(); - for lib in elf.libraries.iter() { - let findlib = get_lib_full_path(lib, confpaths.clone(), rpaths.clone(), lib_paths.clone()).unwrap_or("".to_string()); - libs.push(findlib); - } - libs - } else { - log::info!("The environment variable PATH is empty. Please check."); - libs - } -} - // TODO: use bolt to optimize dynamic library and then merge them fn sysboost_core_process(conf: &RtoConfig) -> i32 { match conf.mode.as_str() { @@ -496,14 +307,8 @@ fn start_service() { } } -fn insmod_ko(path: &String) { - let mut args: Vec = Vec::new(); - args.push(path.to_string()); - run_child("/usr/sbin/insmod", &args); -} - pub fn daemon_loop() { - insmod_ko(&KO_PATH.to_string()); + insmod_sysboost_ko(); // When rebooting, you should clean up the backup environment loop { diff --git a/bin/kmod_util.rs b/bin/kmod_util.rs new file mode 100644 index 0000000000000000000000000000000000000000..193142c6befdfe05282c9231ce751b6ad891996c --- /dev/null +++ b/bin/kmod_util.rs @@ -0,0 +1,52 @@ +// Copyright (c) 2023 Huawei Technologies Co., Ltd. +// sysboost is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +// PURPOSE. +// See the Mulan PSL v2 for more details. +// Create: 2023-8-26 + +use crate::lib::process_ext::run_child; + +const KO_RTO_PARAM_PATH: &str = "/sys/module/sysboost_loader/parameters/use_rto"; +const KO_PATH: &str = "/lib/modules/sysboost/sysboost_loader.ko"; + +// echo 1 > /sys/module/sysboost_loader/parameters/use_rto +pub fn set_ko_rto_flag(is_set: bool) -> i32 { + let mut args: Vec = Vec::new(); + if is_set { + args.push("1".to_string()); + } else { + args.push("0".to_string()); + } + args.push(">".to_string()); + args.push(KO_RTO_PARAM_PATH.to_string()); + let ret = run_child("/usr/bin/echo", &args); + return ret; +} + +fn insmod_ko(path: &String) { + let mut args: Vec = Vec::new(); + args.push(path.to_string()); + run_child("/usr/sbin/insmod", &args); +} + +pub fn insmod_sysboost_ko() { + insmod_ko(&KO_PATH.to_string()); +} + +pub fn test_kmod() -> i32 { + let mut args: Vec = Vec::new(); + args.push("-c".to_string()); + args.push("lsmod | grep sysboost_loader".to_string()); + let ret = run_child("/usr/bin/bash", &args); + if ret == 0 { + println!("sysboost_loader.ko is ready"); + } else { + println!("sysboost_loader.ko is not ready"); + } + return ret; +} diff --git a/bin/main.rs b/bin/main.rs index 295c494e1bc76e35029e2c9caf5cb285028da0d9..4158b7e047b226b5a6746be36fa65384b456b582 100644 --- a/bin/main.rs +++ b/bin/main.rs @@ -10,12 +10,15 @@ // Create: 2023-4-20 mod lib; +mod common; mod config; +mod kmod_util; +mod aot; mod bolt; mod daemon; mod coredump_monitor; -use crate::lib::process_ext::run_child; +use crate::kmod_util::test_kmod; use crate::daemon::daemon_loop; use crate::coredump_monitor::coredump_monitor_loop; @@ -27,19 +30,6 @@ use std::thread; const APP_NAME: &str = "sysboostd"; -fn test_kmod() -> i32 { - let mut args: Vec = Vec::new(); - args.push("-c".to_string()); - args.push("lsmod | grep sysboost_loader".to_string()); - let ret = run_child("/usr/bin/bash", &args); - if ret == 0 { - println!("sysboost_loader.ko is ready"); - } else { - println!("sysboost_loader.ko is not ready"); - } - return ret; -} - fn main() { let args: Vec = env::args().collect(); let mut is_debug = false;