diff --git a/Cargo.lock b/Cargo.lock index ae389bd..8b8b62d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,7 @@ dependencies = [ "mio", "net2", "parking_lot", + "privdrop", "quickcheck", "quickcheck_macros", "rand", @@ -425,6 +426,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "nix" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "void", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -587,6 +601,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "privdrop" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939fa7cbfef9c15c65cf2fb3ed57f3f2a14dca1757a556aa1ba4a7f998b2b479" +dependencies = [ + "libc", + "nix", +] + [[package]] name = "proc-macro2" version = "1.0.10" @@ -839,6 +863,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/README.md b/README.md index 1e24eeb..0b06790 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,11 @@ interval = 5 interval = 30 max_peer_age = 1200 max_connection_age = 300 + +[privileges] +drop_privileges = false +chroot_path = '.' +user = 'nobody' ``` To adjust the settings, save this text to a file and make your changes. The diff --git a/aquatic/Cargo.toml b/aquatic/Cargo.toml index 15633f0..d08e063 100644 --- a/aquatic/Cargo.toml +++ b/aquatic/Cargo.toml @@ -23,6 +23,7 @@ mimalloc = { version = "0.1", default-features = false } mio = { version = "0.7", features = ["udp", "os-poll", "os-util"] } net2 = "0.2" parking_lot = "0.10" +privdrop = "0.3" rand = { version = "0.7", features = ["small_rng"] } serde = { version = "1", features = ["derive"] } diff --git a/aquatic/src/lib/config.rs b/aquatic/src/lib/config.rs index 3d81760..289f5a6 100644 --- a/aquatic/src/lib/config.rs +++ b/aquatic/src/lib/config.rs @@ -17,6 +17,7 @@ pub struct Config { pub handlers: HandlerConfig, pub statistics: StatisticsConfig, pub cleaning: CleaningConfig, + pub privileges: PrivilegeConfig, } @@ -80,6 +81,18 @@ pub struct CleaningConfig { } +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(default)] +pub struct PrivilegeConfig { + /// Chroot and switch user after binding to sockets + pub drop_privileges: bool, + /// Chroot to this path + pub chroot_path: String, + /// User to switch to after chrooting + pub user: String, +} + + impl Default for Config { fn default() -> Self { Self { @@ -89,6 +102,7 @@ impl Default for Config { handlers: HandlerConfig::default(), statistics: StatisticsConfig::default(), cleaning: CleaningConfig::default(), + privileges: PrivilegeConfig::default(), } } } @@ -136,3 +150,14 @@ impl Default for CleaningConfig { } } } + + +impl Default for PrivilegeConfig { + fn default() -> Self { + Self { + drop_privileges: false, + chroot_path: ".".to_string(), + user: "nobody".to_string(), + } + } +} \ No newline at end of file diff --git a/aquatic/src/lib/lib.rs b/aquatic/src/lib/lib.rs index 544a813..07f0476 100644 --- a/aquatic/src/lib/lib.rs +++ b/aquatic/src/lib/lib.rs @@ -1,7 +1,9 @@ +use std::sync::{Arc, atomic::{AtomicUsize, Ordering}}; use std::time::Duration; use std::thread::Builder; use crossbeam_channel::unbounded; +use privdrop::PrivDrop; pub mod common; pub mod config; @@ -35,11 +37,14 @@ pub fn run(config: Config){ ).expect("spawn request worker"); } + let num_bound_sockets = Arc::new(AtomicUsize::new(0)); + for i in 0..config.socket_workers { let state = state.clone(); let config = config.clone(); let request_sender = request_sender.clone(); let response_receiver = response_receiver.clone(); + let num_bound_sockets = num_bound_sockets.clone(); Builder::new().name(format!("socket-{:02}", i + 1)).spawn(move || network::run_socket_worker( @@ -48,6 +53,7 @@ pub fn run(config: Config){ i, request_sender, response_receiver, + num_bound_sockets, ) ).expect("spawn socket worker"); } @@ -67,6 +73,24 @@ pub fn run(config: Config){ ).expect("spawn statistics thread"); } + if config.privileges.drop_privileges { + loop { + let sockets = num_bound_sockets.load(Ordering::SeqCst); + + if sockets == config.socket_workers { + PrivDrop::default() + .chroot(config.privileges.chroot_path) + .user(config.privileges.user) + .apply() + .expect("drop privileges"); + + break; + } + + ::std::thread::sleep(Duration::from_millis(10)); + } + } + loop { ::std::thread::sleep(Duration::from_secs(config.cleaning.interval)); diff --git a/aquatic/src/lib/network.rs b/aquatic/src/lib/network.rs index decb620..3f9bf34 100644 --- a/aquatic/src/lib/network.rs +++ b/aquatic/src/lib/network.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::Ordering; +use std::sync::{Arc, atomic::{AtomicUsize, Ordering}}; use std::io::{Cursor, ErrorKind}; use std::net::SocketAddr; use std::time::Duration; @@ -23,6 +23,7 @@ pub fn run_socket_worker( token_num: usize, request_sender: Sender<(Request, SocketAddr)>, response_receiver: Receiver<(Response, SocketAddr)>, + num_bound_sockets: Arc, ){ let mut buffer = [0u8; MAX_PACKET_SIZE]; @@ -34,6 +35,8 @@ pub fn run_socket_worker( poll.registry() .register(&mut socket, Token(token_num), interests) .unwrap(); + + num_bound_sockets.fetch_add(1, Ordering::SeqCst); let mut events = Events::with_capacity(config.network.poll_event_capacity);