From cc67ce5dbb97b995c4d7cd76608f93b984bf7367 Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Fri, 19 Jul 2024 10:12:24 +0100 Subject: [PATCH] Support loading appsec helper in sidecar --- sidecar/src/config.rs | 79 +++++++++++++++++++++++++++++++++++++++---- sidecar/src/entry.rs | 9 ++++- sidecar/src/unix.rs | 56 ++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/sidecar/src/config.rs b/sidecar/src/config.rs index 78632e84d..ac4fcc978 100644 --- a/sidecar/src/config.rs +++ b/sidecar/src/config.rs @@ -24,6 +24,12 @@ const DEFAULT_IDLE_LINGER_TIME: Duration = Duration::from_secs(60); const ENV_SIDECAR_SELF_TELEMETRY: &str = "_DD_SIDECAR_SELF_TELEMETRY"; +const ENV_SIDECAR_APPSEC_SHARED_LIB_PATH: &str = "_DD_SIDECAR_APPSEC_SHARED_LIB_PATH"; +const ENV_SIDECAR_APPSEC_SOCKET_FILE_PATH: &str = "_DD_SIDECAR_APPSEC_SOCKET_FILE_PATH"; +const ENV_SIDECAR_APPSEC_LOCK_FILE_PATH: &str = "_DD_SIDECAR_APPSEC_LOCK_FILE_PATH"; +const ENV_SIDECAR_APPSEC_LOG_FILE_PATH: &str = "_DD_SIDECAR_APPSEC_LOG_FILE_PATH"; +const ENV_SIDECAR_APPSEC_LOG_LEVEL: &str = "_DD_SIDECAR_APPSEC_LOG_LEVEL"; + #[derive(Debug, Copy, Clone)] pub enum IpcMode { Shared, @@ -78,6 +84,16 @@ pub struct Config { pub self_telemetry: bool, pub library_dependencies: Vec, pub child_env: HashMap, + pub appsec_config: Option, +} + +#[derive(Debug, Clone)] +pub struct AppSecConfig { + pub shared_lib_path: std::ffi::OsString, + pub socket_file_path: std::ffi::OsString, + pub lock_file_path: std::ffi::OsString, + pub log_file_path: std::ffi::OsString, + pub log_level: String, } impl Config { @@ -85,15 +101,49 @@ impl Config { FromEnv::config() } - pub fn to_env(&self) -> HashMap<&'static str, String> { - HashMap::from([ - (ENV_SIDECAR_IPC_MODE, self.ipc_mode.to_string()), - (ENV_SIDECAR_LOG_METHOD, self.log_method.to_string()), + pub fn to_env(&self) -> HashMap<&'static str, std::ffi::OsString> { + let mut res = HashMap::from([ + (ENV_SIDECAR_IPC_MODE, self.ipc_mode.to_string().into()), + (ENV_SIDECAR_LOG_METHOD, self.log_method.to_string().into()), ( ENV_IDLE_LINGER_TIME_SECS, - self.idle_linger_time.as_secs().to_string(), + self.idle_linger_time.as_secs().to_string().into(), + ), + ( + ENV_SIDECAR_SELF_TELEMETRY, + self.self_telemetry.to_string().into(), + ), + ]); + if self.appsec_config.is_some() { + res.extend(self.appsec_config.as_ref().unwrap().to_env()); + } + res + } +} + +impl AppSecConfig { + pub fn to_env(&self) -> HashMap<&'static str, std::ffi::OsString> { + HashMap::from([ + ( + ENV_SIDECAR_APPSEC_SHARED_LIB_PATH, + self.shared_lib_path.to_owned(), + ), + ( + ENV_SIDECAR_APPSEC_SOCKET_FILE_PATH, + self.socket_file_path.to_owned(), + ), + ( + ENV_SIDECAR_APPSEC_LOCK_FILE_PATH, + self.lock_file_path.to_owned(), + ), + ( + ENV_SIDECAR_APPSEC_LOG_FILE_PATH, + self.log_file_path.to_owned(), + ), + ( + ENV_SIDECAR_APPSEC_LOG_LEVEL, + self.log_level.to_owned().into(), ), - (ENV_SIDECAR_SELF_TELEMETRY, self.self_telemetry.to_string()), ]) } } @@ -159,8 +209,25 @@ impl FromEnv { self_telemetry: Self::self_telemetry(), library_dependencies: vec![], child_env: std::env::vars_os().collect(), + appsec_config: Self::appsec_config(), } } + + pub fn appsec_config() -> Option { + let shared_lib_path = std::env::var_os(ENV_SIDECAR_APPSEC_SHARED_LIB_PATH)?; + let socket_file_path = std::env::var_os(ENV_SIDECAR_APPSEC_SOCKET_FILE_PATH)?; + let lock_file_path = std::env::var_os(ENV_SIDECAR_APPSEC_LOCK_FILE_PATH)?; + let log_file_path = std::env::var_os(ENV_SIDECAR_APPSEC_LOG_FILE_PATH)?; + let log_level = std::env::var(ENV_SIDECAR_APPSEC_LOG_LEVEL).ok()?; + + Some(AppSecConfig { + shared_lib_path, + socket_file_path, + lock_file_path, + log_file_path, + log_level, + }) + } } pub fn get_product_endpoint(subdomain: &str, endpoint: &Endpoint) -> Endpoint { diff --git a/sidecar/src/entry.rs b/sidecar/src/entry.rs index 29d621435..77a4f3406 100644 --- a/sidecar/src/entry.rs +++ b/sidecar/src/entry.rs @@ -166,8 +166,15 @@ pub fn daemonize(listener: IpcServer, cfg: Config) -> anyhow::Result<()> { setup_daemon_process(listener, &mut spawn_cfg)?; + let mut lib_deps = cfg.library_dependencies; + if cfg.appsec_config.is_some() { + lib_deps.push(spawn_worker::LibDependency::Path( + cfg.appsec_config.unwrap().shared_lib_path.into(), + )); + } + spawn_cfg - .shared_lib_dependencies(cfg.library_dependencies) + .shared_lib_dependencies(lib_deps) .wait_spawn() .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) .context("Could not spawn the sidecar daemon")?; diff --git a/sidecar/src/unix.rs b/sidecar/src/unix.rs index dc322b5c2..95feb30bb 100644 --- a/sidecar/src/unix.rs +++ b/sidecar/src/unix.rs @@ -3,8 +3,10 @@ use spawn_worker::{getpid, SpawnWorker, Stdio}; +use std::ffi::CString; use std::os::unix::net::UnixListener as StdUnixListener; +use crate::config::FromEnv; use crate::enter_listener_loop; use nix::fcntl::{fcntl, OFlag, F_GETFL, F_SETFL}; use nix::sys::socket::{shutdown, Shutdown}; @@ -28,6 +30,8 @@ pub extern "C" fn ddog_daemon_entry_point() { let now = Instant::now(); + let appsec_started = maybe_start_appsec(); + if let Some(fd) = spawn_worker::recv_passed_fd() { let listener: StdUnixListener = fd.into(); info!("Starting sidecar, pid: {}", getpid()); @@ -56,6 +60,10 @@ pub extern "C" fn ddog_daemon_entry_point() { } } + if appsec_started { + shutdown_appsec(); + } + info!( "shutting down sidecar, pid: {}, total runtime: {:.3}s", getpid(), @@ -89,3 +97,51 @@ pub fn setup_daemon_process( pub fn primary_sidecar_identifier() -> u32 { unsafe { libc::geteuid() } } + +fn maybe_start_appsec() -> bool { + let cfg = FromEnv::appsec_config(); + if cfg.is_none() { + return false; + } + + info!("Starting appsec helper"); + + let entrypoint_sym_name = CString::new("appsec_helper_main").unwrap(); + + let func_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, entrypoint_sym_name.as_ptr()) }; + if func_ptr.is_null() { + error!("Failed to load appsec helper: can't find the symbol 'appsec_helper_main'"); + return false; + } + + let appsec_entry_fn: extern "C" fn() -> i32 = unsafe { std::mem::transmute(func_ptr) }; + let res = appsec_entry_fn(); + if res != 0 { + error!("Appsec helper failed to start"); + return false; + } + + info!("Appsec helper started"); + true +} + +fn shutdown_appsec() -> bool { + info!("Shutting down appsec helper"); + + let shutdown_sym_name = CString::new("appsec_helper_shutdown").unwrap(); + + let func_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, shutdown_sym_name.as_ptr()) }; + if func_ptr.is_null() { + error!("Failed to load appsec helper: can't find the symbol 'appsec_helper_shutdown'"); + return false; + } + let appsec_shutdown_fn: extern "C" fn() -> i32 = unsafe { std::mem::transmute(func_ptr) }; + let res = appsec_shutdown_fn(); + if res != 0 { + error!("Appsec helper failed to shutdown"); + return false; + } + + info!("Appsec helper shutdown"); + true +}