syscare/0018-security-change-daemon-socket-permission.patch

827 lines
26 KiB
Diff
Raw Normal View History

From bbbcb0c08f4a6a63230288485d88492465e2a593 Mon Sep 17 00:00:00 2001
From: renoseven <dev@renoseven.net>
Date: Sat, 11 May 2024 10:21:58 +0800
Subject: [PATCH] security: change daemon socket permission
1. add socket uid & gid to config file
default uid: 0
default gid: 0
2. set socket permission by its uid & gid
uid == gid: 0600
uid != gid: 0660
Signed-off-by: renoseven <dev@renoseven.net>
---
Cargo.lock | 2 +
syscared/Cargo.toml | 1 +
syscared/src/args.rs | 8 ++-
syscared/src/config.rs | 88 ++++++++++++++++++++++++++++++
syscared/src/main.rs | 70 ++++++++++++++++++------
upatchd/Cargo.toml | 2 +-
upatchd/src/config.rs | 91 ++++++++++++++++++++++++++++++++
upatchd/src/hijacker/config.rs | 85 +++++------------------------
upatchd/src/hijacker/mod.rs | 47 +++--------------
upatchd/src/main.rs | 55 ++++++++++++++-----
upatchd/src/rpc/skeleton_impl.rs | 8 +--
11 files changed, 310 insertions(+), 147 deletions(-)
create mode 100644 syscared/src/config.rs
create mode 100644 upatchd/src/config.rs
diff --git a/Cargo.lock b/Cargo.lock
index e6d830b..e3074a6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -511,6 +511,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
+ "serde",
]
[[package]]
@@ -1185,6 +1186,7 @@ dependencies = [
"object",
"parking_lot",
"serde",
+ "serde_yaml",
"signal-hook",
"syscare-abi",
"syscare-common",
diff --git a/syscared/Cargo.toml b/syscared/Cargo.toml
index 2b148e7..27f27e2 100644
--- a/syscared/Cargo.toml
+++ b/syscared/Cargo.toml
@@ -26,5 +26,6 @@ nix = { version = "0.26" }
object = { version = "0.29" }
parking_lot = { version = "0.11" }
serde = { version = "1.0", features = ["derive"] }
+serde_yaml = { version = "0.8" }
signal-hook = { version = "0.3" }
uuid = { version = "0.8", features = ["v4", "serde"] }
diff --git a/syscared/src/args.rs b/syscared/src/args.rs
index 71cdf95..4c28dff 100644
--- a/syscared/src/args.rs
+++ b/syscared/src/args.rs
@@ -22,6 +22,7 @@ use syscare_common::fs;
use super::{DAEMON_ABOUT, DAEMON_NAME, DAEMON_VERSION};
+const DEFAULT_CONFIG_DIR: &str = "/etc/syscare";
const DEFAULT_DATA_ROOT: &str = "/usr/lib/syscare";
const DEFAULT_WORK_DIR: &str = "/var/run/syscare";
const DEFAULT_LOG_DIR: &str = "/var/log/syscare";
@@ -42,6 +43,10 @@ pub struct Arguments {
#[clap(short, long)]
pub daemon: bool,
+ /// Daemon config directory
+ #[clap(long, default_value=DEFAULT_CONFIG_DIR)]
+ pub config_dir: PathBuf,
+
/// Daemon data directory
#[clap(long, default_value = DEFAULT_DATA_ROOT)]
pub data_dir: PathBuf,
@@ -65,8 +70,9 @@ impl Arguments {
}
fn normalize_path(mut self) -> Result<Self> {
- self.work_dir = fs::normalize(&self.work_dir)?;
+ self.config_dir = fs::normalize(&self.config_dir)?;
self.data_dir = fs::normalize(&self.data_dir)?;
+ self.work_dir = fs::normalize(&self.work_dir)?;
self.log_dir = fs::normalize(&self.log_dir)?;
Ok(self)
diff --git a/syscared/src/config.rs b/syscared/src/config.rs
new file mode 100644
index 0000000..af98a51
--- /dev/null
+++ b/syscared/src/config.rs
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: Mulan PSL v2
+/*
+ * Copyright (c) 2024 Huawei Technologies Co., Ltd.
+ * upatchd is licensed under 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.
+ */
+
+use std::path::Path;
+
+use anyhow::{anyhow, Result};
+use serde::{Deserialize, Serialize};
+use syscare_common::fs;
+
+const DEFAULT_SOCKET_UID: u32 = 0;
+const DEFAULT_SOCKET_GID: u32 = 0;
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SocketConfig {
+ pub uid: u32,
+ pub gid: u32,
+}
+
+impl Default for SocketConfig {
+ fn default() -> Self {
+ Self {
+ uid: DEFAULT_SOCKET_UID,
+ gid: DEFAULT_SOCKET_GID,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct DaemonConfig {
+ pub socket: SocketConfig,
+}
+
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Config {
+ pub daemon: DaemonConfig,
+}
+
+impl Config {
+ pub fn parse<P: AsRef<Path>>(path: P) -> Result<Self> {
+ let config_path = path.as_ref();
+ let instance = serde_yaml::from_reader(fs::open_file(config_path)?)
+ .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?;
+
+ Ok(instance)
+ }
+
+ pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<()> {
+ let config_path = path.as_ref();
+ let config_file = fs::create_file(config_path)?;
+ serde_yaml::to_writer(config_file, self)
+ .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?;
+
+ Ok(())
+ }
+}
+
+#[test]
+fn test() -> Result<()> {
+ use anyhow::{ensure, Context};
+ use std::path::PathBuf;
+
+ let tmp_file = PathBuf::from("/tmp/syscared.yaml");
+
+ let orig_cfg = Config::default();
+ println!("{:#?}", orig_cfg);
+
+ orig_cfg
+ .write(&tmp_file)
+ .context("Failed to write config")?;
+
+ let new_cfg = Config::parse(tmp_file).context("Failed to read config")?;
+ println!("{:#?}", new_cfg);
+
+ ensure!(orig_cfg == new_cfg, "Config does not match");
+
+ Ok(())
+}
diff --git a/syscared/src/main.rs b/syscared/src/main.rs
index 22f01df..b840abf 100644
--- a/syscared/src/main.rs
+++ b/syscared/src/main.rs
@@ -22,7 +22,8 @@ use flexi_logger::{
};
use jsonrpc_core::IoHandler;
use jsonrpc_ipc_server::{Server, ServerBuilder};
-use log::{error, info, LevelFilter, Record};
+use log::{debug, error, info, warn, LevelFilter, Record};
+use nix::unistd::{chown, Gid, Uid};
use parking_lot::RwLock;
use patch::manager::PatchManager;
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_name};
@@ -30,38 +31,45 @@ use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_nam
use syscare_common::{fs, os};
mod args;
+mod config;
mod fast_reboot;
mod patch;
mod rpc;
use args::Arguments;
+use config::Config;
+use patch::monitor::PatchMonitor;
use rpc::{
skeleton::{FastRebootSkeleton, PatchSkeleton},
skeleton_impl::{FastRebootSkeletonImpl, PatchSkeletonImpl},
};
-use crate::patch::monitor::PatchMonitor;
-
const DAEMON_NAME: &str = env!("CARGO_PKG_NAME");
const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION");
const DAEMON_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION");
const DAEMON_UMASK: u32 = 0o077;
+const CONFIG_FILE_NAME: &str = "syscared.yaml";
+const PID_FILE_NAME: &str = "syscared.pid";
+const SOCKET_FILE_NAME: &str = "syscared.sock";
+
+const CONFIG_DIR_PERM: u32 = 0o700;
const DATA_DIR_PERM: u32 = 0o700;
const WORK_DIR_PERM: u32 = 0o755;
const LOG_DIR_PERM: u32 = 0o700;
-const PID_FILE_NAME: &str = "syscared.pid";
-const SOCKET_FILE_NAME: &str = "syscared.sock";
+const SOCKET_FILE_PERM: u32 = 0o660;
+const SOCKET_FILE_PERM_STRICT: u32 = 0o600;
const MAIN_THREAD_NAME: &str = "main";
const UNNAMED_THREAD_NAME: &str = "<unnamed>";
const LOG_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.6f";
-struct SyscareDaemon {
+struct Daemon {
args: Arguments,
+ config: Config,
}
-impl SyscareDaemon {
+impl Daemon {
fn format_log(
w: &mut dyn std::io::Write,
now: &mut DeferredNow,
@@ -101,9 +109,11 @@ impl SyscareDaemon {
os::umask::set_umask(DAEMON_UMASK);
let args = Arguments::new()?;
+ fs::create_dir_all(&args.config_dir)?;
fs::create_dir_all(&args.data_dir)?;
fs::create_dir_all(&args.work_dir)?;
fs::create_dir_all(&args.log_dir)?;
+ fs::set_permissions(&args.config_dir, Permissions::from_mode(CONFIG_DIR_PERM))?;
fs::set_permissions(&args.data_dir, Permissions::from_mode(DATA_DIR_PERM))?;
fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERM))?;
fs::set_permissions(&args.log_dir, Permissions::from_mode(LOG_DIR_PERM))?;
@@ -138,14 +148,29 @@ impl SyscareDaemon {
.start()
.context("Failed to initialize logger")?;
+ // Initialize config
+ debug!("Initializing configuation...");
+ let config_file = args.config_dir.join(CONFIG_FILE_NAME);
+ let config = match Config::parse(&config_file) {
+ Ok(config) => config,
+ Err(e) => {
+ warn!("{:?}", e);
+ info!("Using default configuration...");
+ let config = Config::default();
+ config.write(&config_file)?;
+
+ config
+ }
+ };
+
// Print panic to log incase it really happens
panic::set_hook(Box::new(|info| error!("{}", info)));
- Ok(Self { args })
+ Ok(Self { args, config })
}
}
-impl SyscareDaemon {
+impl Daemon {
fn daemonize(&self) -> Result<()> {
if !self.args.daemon {
return Ok(());
@@ -171,13 +196,24 @@ impl SyscareDaemon {
fn start_rpc_server(&self, io_handler: IoHandler) -> Result<Server> {
let socket_file = self.args.work_dir.join(SOCKET_FILE_NAME);
- let server = ServerBuilder::new(io_handler)
- .set_client_buffer_size(1)
- .start(
- socket_file
- .to_str()
- .context("Failed to convert socket path to string")?,
- )?;
+ let builder = ServerBuilder::new(io_handler).set_client_buffer_size(1);
+ let server = builder.start(
+ socket_file
+ .to_str()
+ .context("Failed to convert socket path to string")?,
+ )?;
+
+ let socket_owner = Uid::from_raw(self.config.daemon.socket.uid);
+ let socket_group = Gid::from_raw(self.config.daemon.socket.gid);
+ chown(&socket_file, Some(socket_owner), Some(socket_group))?;
+
+ fs::set_permissions(
+ &socket_file,
+ match socket_owner.as_raw() == socket_group.as_raw() {
+ true => Permissions::from_mode(SOCKET_FILE_PERM_STRICT),
+ false => Permissions::from_mode(SOCKET_FILE_PERM),
+ },
+ )?;
Ok(server)
}
@@ -227,7 +263,7 @@ impl SyscareDaemon {
}
fn main() {
- let daemon = match SyscareDaemon::new() {
+ let daemon = match Daemon::new() {
Ok(instance) => instance,
Err(e) => {
eprintln!("Error: {:?}", e);
diff --git a/upatchd/Cargo.toml b/upatchd/Cargo.toml
index dd9f5ca..fea0859 100644
--- a/upatchd/Cargo.toml
+++ b/upatchd/Cargo.toml
@@ -14,7 +14,7 @@ anyhow = { version = "1.0" }
clap = { version = "3.2", features = ["cargo", "derive"] }
daemonize = { version = "0.5" }
flexi_logger = { version = "0.24", features = ["compress"] }
-indexmap = { version = "1.9" }
+indexmap = { version = "1.9", features = ["serde"] }
jsonrpc-core = { version = "18.0" }
jsonrpc-derive = { version = "18.0" }
jsonrpc-ipc-server = { version = "18.0" }
diff --git a/upatchd/src/config.rs b/upatchd/src/config.rs
new file mode 100644
index 0000000..125770d
--- /dev/null
+++ b/upatchd/src/config.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: Mulan PSL v2
+/*
+ * Copyright (c) 2024 Huawei Technologies Co., Ltd.
+ * upatchd is licensed under 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.
+ */
+
+use std::path::Path;
+
+use anyhow::{anyhow, Result};
+use serde::{Deserialize, Serialize};
+use syscare_common::fs;
+
+use crate::hijacker::HijackerConfig;
+
+const DEFAULT_SOCKET_UID: u32 = 0;
+const DEFAULT_SOCKET_GID: u32 = 0;
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SocketConfig {
+ pub uid: u32,
+ pub gid: u32,
+}
+
+impl Default for SocketConfig {
+ fn default() -> Self {
+ Self {
+ uid: DEFAULT_SOCKET_UID,
+ gid: DEFAULT_SOCKET_GID,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct DaemonConfig {
+ pub socket: SocketConfig,
+}
+
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Config {
+ pub daemon: DaemonConfig,
+ pub hijacker: HijackerConfig,
+}
+
+impl Config {
+ pub fn parse<P: AsRef<Path>>(path: P) -> Result<Self> {
+ let config_path = path.as_ref();
+ let instance = serde_yaml::from_reader(fs::open_file(config_path)?)
+ .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?;
+
+ Ok(instance)
+ }
+
+ pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<()> {
+ let config_path = path.as_ref();
+ let config_file = fs::create_file(config_path)?;
+ serde_yaml::to_writer(config_file, self)
+ .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?;
+
+ Ok(())
+ }
+}
+
+#[test]
+fn test() -> Result<()> {
+ use anyhow::{ensure, Context};
+ use std::path::PathBuf;
+
+ let tmp_file = PathBuf::from("/tmp/upatchd.yaml");
+
+ let orig_cfg = Config::default();
+ println!("{:#?}", orig_cfg);
+
+ orig_cfg
+ .write(&tmp_file)
+ .context("Failed to write config")?;
+
+ let new_cfg = Config::parse(tmp_file).context("Failed to read config")?;
+ println!("{:#?}", new_cfg);
+
+ ensure!(orig_cfg == new_cfg, "Config does not match");
+
+ Ok(())
+}
diff --git a/upatchd/src/hijacker/config.rs b/upatchd/src/hijacker/config.rs
index f96cc05..5f97fb1 100644
--- a/upatchd/src/hijacker/config.rs
+++ b/upatchd/src/hijacker/config.rs
@@ -12,15 +12,10 @@
* See the Mulan PSL v2 for more details.
*/
-use std::{
- collections::HashMap,
- ops::Deref,
- path::{Path, PathBuf},
-};
+use std::path::PathBuf;
-use anyhow::{anyhow, Result};
+use indexmap::{indexmap, IndexMap};
use serde::{Deserialize, Serialize};
-use syscare_common::fs;
const CC_BINARY: &str = "/usr/bin/cc";
const CXX_BINARY: &str = "/usr/bin/c++";
@@ -34,73 +29,21 @@ const GCC_HIJACKER: &str = "/usr/libexec/syscare/gcc-hijacker";
const GXX_HIJACKER: &str = "/usr/libexec/syscare/g++-hijacker";
const AS_HIJACKER: &str = "/usr/libexec/syscare/as-hijacker";
-#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
-pub struct HijackerConfig(HashMap<PathBuf, PathBuf>);
-
-impl HijackerConfig {
- pub fn parse_from<P: AsRef<Path>>(path: P) -> Result<Self> {
- let config_path = path.as_ref();
- let config_file = fs::open_file(config_path)?;
- let instance: Self = serde_yaml::from_reader(config_file)
- .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?;
-
- Ok(instance)
- }
-
- pub fn write_to<P: AsRef<Path>>(&self, path: P) -> Result<()> {
- let config_path = path.as_ref();
- let config_file = fs::create_file(config_path)?;
- serde_yaml::to_writer(config_file, self)
- .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?;
-
- Ok(())
- }
-}
-
-impl Deref for HijackerConfig {
- type Target = HashMap<PathBuf, PathBuf>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct HijackerConfig {
+ pub mapping: IndexMap<PathBuf, PathBuf>,
}
impl Default for HijackerConfig {
fn default() -> Self {
- let mut map = HashMap::new();
- map.insert(PathBuf::from(CC_BINARY), PathBuf::from(CC_HIJACKER));
- map.insert(PathBuf::from(CXX_BINARY), PathBuf::from(CXX_HIJACKER));
- map.insert(PathBuf::from(GCC_BINARY), PathBuf::from(GCC_HIJACKER));
- map.insert(PathBuf::from(GXX_BINARY), PathBuf::from(GXX_HIJACKER));
- map.insert(PathBuf::from(AS_BINARY), PathBuf::from(AS_HIJACKER));
-
- Self(map)
+ Self {
+ mapping: indexmap! {
+ PathBuf::from(CC_BINARY) => PathBuf::from(CC_HIJACKER),
+ PathBuf::from(CXX_BINARY) => PathBuf::from(CXX_HIJACKER),
+ PathBuf::from(GCC_BINARY) => PathBuf::from(GCC_HIJACKER),
+ PathBuf::from(GXX_BINARY) => PathBuf::from(GXX_HIJACKER),
+ PathBuf::from(AS_BINARY) => PathBuf::from(AS_HIJACKER),
+ },
+ }
}
}
-
-impl std::fmt::Display for HijackerConfig {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_fmt(format_args!("{:#?}", &self.0))
- }
-}
-
-#[test]
-fn test() -> Result<()> {
- use anyhow::{ensure, Context};
-
- let tmp_file = PathBuf::from("/tmp/upatch_hijacker_config.yaml");
-
- let orig_cfg = HijackerConfig::default();
- println!("{}", orig_cfg);
-
- orig_cfg
- .write_to(&tmp_file)
- .context("Failed to write config")?;
-
- let new_cfg = HijackerConfig::parse_from(tmp_file).context("Failed to read config")?;
- println!("{}", new_cfg);
-
- ensure!(orig_cfg == new_cfg, "Config does not match");
-
- Ok(())
-}
diff --git a/upatchd/src/hijacker/mod.rs b/upatchd/src/hijacker/mod.rs
index 8ac12e7..d0f2c4d 100644
--- a/upatchd/src/hijacker/mod.rs
+++ b/upatchd/src/hijacker/mod.rs
@@ -12,7 +12,6 @@
* See the Mulan PSL v2 for more details.
*/
-use std::os::unix::prelude::MetadataExt;
use std::path::{Path, PathBuf};
use anyhow::{bail, Context, Result};
@@ -25,14 +24,14 @@ mod elf_resolver;
mod ioctl;
mod kmod;
-use config::HijackerConfig;
+pub use config::HijackerConfig;
use elf_resolver::ElfResolver;
use ioctl::HijackerIoctl;
use kmod::HijackerKmodGuard;
const KMOD_NAME: &str = "upatch_hijacker";
const KMOD_DEV_PATH: &str = "/dev/upatch-hijacker";
-const KMOD_FILE_PATH: &str = "/usr/libexec/syscare/upatch_hijacker.ko";
+const KMOD_PATH: &str = "/usr/libexec/syscare/upatch_hijacker.ko";
const HIJACK_SYMBOL_NAME: &str = "execve";
@@ -43,36 +42,6 @@ pub struct Hijacker {
}
impl Hijacker {
- fn initialize_config<P: AsRef<Path>>(config_path: P) -> Result<HijackerConfig> {
- const MODE_EXEC_MASK: u32 = 0o111;
-
- let config = match config_path.as_ref().exists() {
- true => HijackerConfig::parse_from(config_path)?,
- false => {
- info!("Generating default configuration...");
- let config = HijackerConfig::default();
- config.write_to(config_path)?;
-
- config
- }
- };
-
- for hijacker in config.values() {
- let is_executable_file = hijacker
- .symlink_metadata()
- .map(|m| m.is_file() && (m.mode() & MODE_EXEC_MASK != 0))
- .with_context(|| format!("Failed to read {} metadata", hijacker.display()))?;
- if !is_executable_file {
- bail!(
- "Hijack program {} is not an executable file",
- hijacker.display()
- );
- }
- }
-
- Ok(config)
- }
-
fn find_symbol_addr(symbol_name: &str) -> Result<(PathBuf, u64)> {
let exec_file = MappedFile::open(os::process::path())?;
let exec_resolver = ElfResolver::new(exec_file.as_bytes())?;
@@ -91,14 +60,9 @@ impl Hijacker {
}
impl Hijacker {
- pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Self> {
- debug!("Initializing hijacker configuation...");
- let config = Self::initialize_config(config_path)
- .context("Failed to initialize hijacker configuration")?;
- info!("Using elf mapping: {}", config);
-
+ pub fn new(config: HijackerConfig) -> Result<Self> {
debug!("Initializing hijacker kernel module...");
- let kmod = HijackerKmodGuard::new(KMOD_NAME, KMOD_FILE_PATH)?;
+ let kmod = HijackerKmodGuard::new(KMOD_NAME, KMOD_PATH)?;
debug!("Initializing hijacker ioctl channel...");
let ioctl = HijackerIoctl::new(KMOD_DEV_PATH)?;
@@ -113,9 +77,9 @@ impl Hijacker {
ioctl.enable_hijacker(lib_path, offset)?;
Ok(Self {
+ config,
_kmod: kmod,
ioctl,
- config,
})
}
}
@@ -124,6 +88,7 @@ impl Hijacker {
fn get_hijacker<P: AsRef<Path>>(&self, exec_path: P) -> Result<&Path> {
let hijacker = self
.config
+ .mapping
.get(exec_path.as_ref())
.with_context(|| format!("Cannot find hijacker for {}", exec_path.as_ref().display()))?
.as_path();
diff --git a/upatchd/src/main.rs b/upatchd/src/main.rs
index 1007ebb..066e53e 100644
--- a/upatchd/src/main.rs
+++ b/upatchd/src/main.rs
@@ -22,16 +22,19 @@ use flexi_logger::{
};
use jsonrpc_core::IoHandler;
use jsonrpc_ipc_server::{Server, ServerBuilder};
-use log::{error, info, LevelFilter, Record};
+use log::{debug, error, info, warn, LevelFilter, Record};
+use nix::unistd::{chown, Gid, Uid};
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_name};
use syscare_common::{fs, os};
mod args;
+mod config;
mod hijacker;
mod rpc;
use args::Arguments;
+use config::Config;
use rpc::{Skeleton, SkeletonImpl};
const DAEMON_NAME: &str = env!("CARGO_PKG_NAME");
@@ -46,17 +49,19 @@ const SOCKET_FILE_NAME: &str = "upatchd.sock";
const CONFIG_DIR_PERM: u32 = 0o700;
const WORK_DIR_PERM: u32 = 0o755;
const LOG_DIR_PERM: u32 = 0o700;
-const SOCKET_FILE_PERM: u32 = 0o666;
+const SOCKET_FILE_PERM: u32 = 0o660;
+const SOCKET_FILE_PERM_STRICT: u32 = 0o600;
const MAIN_THREAD_NAME: &str = "main";
const UNNAMED_THREAD_NAME: &str = "<unnamed>";
const LOG_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.6f";
-struct UpatchDaemon {
+struct Daemon {
args: Arguments,
+ config: Config,
}
-impl UpatchDaemon {
+impl Daemon {
fn format_log(
w: &mut dyn std::io::Write,
now: &mut DeferredNow,
@@ -133,14 +138,28 @@ impl UpatchDaemon {
.start()
.context("Failed to initialize logger")?;
+ // Initialize config
+ debug!("Initializing configuation...");
+ let config_file = args.config_dir.join(CONFIG_FILE_NAME);
+ let config = match Config::parse(&config_file) {
+ Ok(config) => config,
+ Err(e) => {
+ warn!("{:?}", e);
+ info!("Using default configuration...");
+ let config = Config::default();
+ config.write(&config_file)?;
+
+ config
+ }
+ };
+
// Print panic to log incase it really happens
panic::set_hook(Box::new(|info| error!("{}", info)));
-
- Ok(Self { args })
+ Ok(Self { args, config })
}
}
-impl UpatchDaemon {
+impl Daemon {
fn daemonize(&self) -> Result<()> {
if !self.args.daemon {
return Ok(());
@@ -156,10 +175,11 @@ impl UpatchDaemon {
}
fn initialize_skeleton(&self) -> Result<IoHandler> {
- let mut io_handler = IoHandler::new();
+ let config = self.config.hijacker.clone();
+ let methods = SkeletonImpl::new(config)?.to_delegate();
- let config_file = self.args.config_dir.join(CONFIG_FILE_NAME);
- io_handler.extend_with(SkeletonImpl::new(config_file)?.to_delegate());
+ let mut io_handler = IoHandler::new();
+ io_handler.extend_with(methods);
Ok(io_handler)
}
@@ -173,7 +193,17 @@ impl UpatchDaemon {
.context("Failed to convert socket path to string")?,
)?;
- fs::set_permissions(&socket_file, Permissions::from_mode(SOCKET_FILE_PERM))?;
+ let socket_owner = Uid::from_raw(self.config.daemon.socket.uid);
+ let socket_group = Gid::from_raw(self.config.daemon.socket.gid);
+ chown(&socket_file, Some(socket_owner), Some(socket_group))?;
+
+ fs::set_permissions(
+ &socket_file,
+ match socket_owner.as_raw() == socket_group.as_raw() {
+ true => Permissions::from_mode(SOCKET_FILE_PERM_STRICT),
+ false => Permissions::from_mode(SOCKET_FILE_PERM),
+ },
+ )?;
Ok(server)
}
@@ -183,6 +213,7 @@ impl UpatchDaemon {
info!("Upatch Daemon - {}", DAEMON_VERSION);
info!("================================");
info!("Start with {:#?}", self.args);
+ info!("Using {:#?}", self.config);
self.daemonize()?;
info!("Initializing skeleton...");
@@ -213,7 +244,7 @@ impl UpatchDaemon {
}
fn main() {
- let daemon = match UpatchDaemon::new() {
+ let daemon = match Daemon::new() {
Ok(instance) => instance,
Err(e) => {
eprintln!("Error: {:?}", e);
diff --git a/upatchd/src/rpc/skeleton_impl.rs b/upatchd/src/rpc/skeleton_impl.rs
index a334120..d725166 100644
--- a/upatchd/src/rpc/skeleton_impl.rs
+++ b/upatchd/src/rpc/skeleton_impl.rs
@@ -12,12 +12,12 @@
* See the Mulan PSL v2 for more details.
*/
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
use anyhow::{Context, Result};
use log::{debug, info};
-use crate::hijacker::Hijacker;
+use crate::hijacker::{Hijacker, HijackerConfig};
use super::{
function::{RpcFunction, RpcResult},
@@ -29,10 +29,10 @@ pub struct SkeletonImpl {
}
impl SkeletonImpl {
- pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Self> {
+ pub fn new(config: HijackerConfig) -> Result<Self> {
debug!("Initializing hijacker...");
Ok(Self {
- hijacker: Hijacker::new(config_path).context("Failed to initialize hijacker")?,
+ hijacker: Hijacker::new(config).context("Failed to initialize hijacker")?,
})
}
}
--
2.34.1