From 5d4915d6b9236e4d9584f07524c04b778e2101f5 Mon Sep 17 00:00:00 2001 From: Ara Sadoyan Date: Fri, 19 Sep 2025 12:46:17 +0200 Subject: [PATCH] Fixed drop root privileges on ports below 1024 --- Cargo.lock | 79 +++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 3 ++ README.md | 4 +-- src/utils/structs.rs | 2 ++ src/web/start.rs | 61 ++++++++++++++++++++++------------ 5 files changed, 121 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0581504..db94e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,7 @@ dependencies = [ "axum-server", "base16ct", "base64", + "ctrlc", "dashmap", "env_logger", "futures", @@ -134,6 +135,8 @@ dependencies = [ "pingora-http", "pingora-limits", "pingora-proxy", + "port_check", + "privdrop", "prometheus 0.14.0", "rand 0.9.2", "reqwest", @@ -479,6 +482,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.39" @@ -610,6 +619,17 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "ctrlc" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" +dependencies = [ + "dispatch", + "nix 0.30.1", + "windows-sys 0.61.0", +] + [[package]] name = "daemonize" version = "0.5.0" @@ -694,6 +714,12 @@ dependencies = [ "crypto-common 0.2.0-rc.4", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + [[package]] name = "displaydoc" version = "0.2.5" @@ -1694,6 +1720,18 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1995,7 +2033,7 @@ dependencies = [ "httpdate", "libc", "log", - "nix", + "nix 0.24.3", "once_cell", "openssl-probe", "parking_lot", @@ -2189,6 +2227,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "port_check" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2749dcd0984ec1be3c01001bb1d83623a58c3c0049a99b9afec61464fa98e7" + [[package]] name = "portable-atomic" version = "1.11.0" @@ -2219,6 +2263,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "privdrop" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70722a5a3728c9603c8d9469b64b8d1ee54dae6d74e24146da7f501b4c76540f" +dependencies = [ + "libc", + "nix 0.30.1", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3492,13 +3546,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-registry" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -3509,7 +3569,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -3518,7 +3578,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -3557,6 +3617,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3594,7 +3663,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/Cargo.toml b/Cargo.toml index d01f873..0eda853 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,9 @@ x509-parser = "0.18.0" rustls-pemfile = "2.2.0" tower-http = { version = "0.6.6", features = ["fs"] } once_cell = "1.21.3" +privdrop = "0.5.6" +ctrlc = "3.5.0" +port_check = "0.3.0" #moka = { version = "0.12.10", features = ["sync"] } #rustls = { version = "0.23.27", features = ["ring"] } #hickory-client = { version = "0.25.2" } diff --git a/README.md b/README.md index f4ecc95..c013c82 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,8 @@ Built on Rust, on top of **Cloudflare’s Pingora engine**, **Aralez** delivers | Key | Example Value | Description | |----------------------------------|--------------------------------------|----------------------------------------------------------------------------------------------------| | **threads** | 12 | Number of running daemon threads. Optional, defaults to 1 | -| **user** | aralez | Optional, Username for running aralez after dropping root privileges, requires to launch as root | -| **group** | aralez | Optional,Group for running aralez after dropping root privileges, requires to launch as root | +| **runuser** | aralez | Optional, Username for running aralez after dropping root privileges, requires to launch as root | +| **rungroup** | aralez | Optional,Group for running aralez after dropping root privileges, requires to launch as root | | **daemon** | false | Run in background (boolean) | | **upstream_keepalive_pool_size** | 500 | Pool size for upstream keepalive connections | | **pid_file** | /tmp/aralez.pid | Path to PID file | diff --git a/src/utils/structs.rs b/src/utils/structs.rs index cce0d67..5965c83 100644 --- a/src/utils/structs.rs +++ b/src/utils/structs.rs @@ -99,6 +99,8 @@ pub struct AppConfig { pub proxy_tls_grade: Option, pub file_server_address: Option, pub file_server_folder: Option, + pub runuser: Option, + pub rungroup: Option, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/web/start.rs b/src/web/start.rs index 669a045..419fcaf 100644 --- a/src/web/start.rs +++ b/src/web/start.rs @@ -5,15 +5,19 @@ use crate::utils::tls::CertificateConfig; use crate::utils::tools::*; use crate::web::proxyhttp::LB; use arc_swap::ArcSwap; +use ctrlc; use dashmap::DashMap; use log::info; use pingora::tls::ssl::{SslAlert, SslRef}; use pingora_core::listeners::tls::TlsSettings; use pingora_core::prelude::{background_service, Opt}; use pingora_core::server::Server; +use port_check::is_port_reachable; +use privdrop::PrivDrop; +use std::os::unix::fs::MetadataExt; use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; -use std::thread; +use std::{thread, time}; pub fn run() { // default_provider().install_default().expect("Failed to install rustls crypto provider"); @@ -46,24 +50,7 @@ pub fn run() { headers: hh_config, extraparams: ec_config, }; - /* - let log_level = cfg.log_level.clone(); - unsafe { - match log_level.as_str() { - "info" => env::set_var("RUST_LOG", "info"), - "error" => env::set_var("RUST_LOG", "error"), - "warn" => env::set_var("RUST_LOG", "warn"), - "debug" => env::set_var("RUST_LOG", "debug"), - "trace" => env::set_var("RUST_LOG", "trace"), - "off" => env::set_var("RUST_LOG", "off"), - _ => { - println!("Error reading log level, defaulting to: INFO"); - env::set_var("RUST_LOG", "info") - } - } - } - env_logger::builder().init(); - */ + let grade = cfg.proxy_tls_grade.clone().unwrap_or("medium".to_string()); info!("TLS grade set to: [ {} ]", grade); @@ -104,7 +91,6 @@ pub fn run() { match new_certs { Some(new_certs) => { certs_for_watcher.store(Arc::new(new_certs)); - info!("Reload TLS certificates from {}", cfg.proxy_certificates.clone().unwrap()) } None => {} }; @@ -117,5 +103,38 @@ pub fn run() { proxy.add_tcp(bind_address_http.as_str()); server.add_service(proxy); server.add_service(bg_srvc); - server.run_forever(); + + thread::spawn(move || server.run_forever()); + drop_priv(cfg.rungroup.clone(), cfg.runuser.clone(), cfg.proxy_address_http.clone(), cfg.proxy_address_tls.clone()); + + let (tx, rx) = channel(); + ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel.")).expect("Error setting Ctrl-C handler"); + rx.recv().expect("Could not receive from channel."); + println!("\nSignal received ! Exiting..."); +} +fn drop_priv(user: Option, group: Option, http_addr: String, tls_addr: Option) { + thread::sleep(time::Duration::from_millis(10)); + loop { + thread::sleep(time::Duration::from_millis(10)); + if is_port_reachable(http_addr.clone()) { + break; + } + } + if let Some(tls_addr) = tls_addr { + loop { + thread::sleep(time::Duration::from_millis(10)); + if is_port_reachable(tls_addr.clone()) { + break; + } + } + } + + if let (Some(u), Some(g)) = (user, group) { + if std::fs::metadata("/proc/self").map(|m| m.uid()).unwrap_or(1) == 0 { + info!("Dropping ROOT privileges to: {}:{}", u, g); + if let Err(e) = PrivDrop::default().user(u).group(g).apply() { + panic!("Failed to drop privileges: {}", e); + } + } + } }