aquatic: add setting for dropping privileges after opening sockets

This commit is contained in:
Joakim Frostegård 2020-05-06 01:26:35 +02:00
parent e0526ac828
commit 6110017980
6 changed files with 89 additions and 1 deletions

30
Cargo.lock generated
View file

@ -35,6 +35,7 @@ dependencies = [
"mio", "mio",
"net2", "net2",
"parking_lot", "parking_lot",
"privdrop",
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",
"rand", "rand",
@ -425,6 +426,19 @@ dependencies = [
"winapi", "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]] [[package]]
name = "nodrop" name = "nodrop"
version = "0.1.14" version = "0.1.14"
@ -587,6 +601,16 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.10" version = "1.0.10"
@ -839,6 +863,12 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.9.0+wasi-snapshot-preview1" version = "0.9.0+wasi-snapshot-preview1"

View file

@ -49,6 +49,11 @@ interval = 5
interval = 30 interval = 30
max_peer_age = 1200 max_peer_age = 1200
max_connection_age = 300 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 To adjust the settings, save this text to a file and make your changes. The

View file

@ -23,6 +23,7 @@ mimalloc = { version = "0.1", default-features = false }
mio = { version = "0.7", features = ["udp", "os-poll", "os-util"] } mio = { version = "0.7", features = ["udp", "os-poll", "os-util"] }
net2 = "0.2" net2 = "0.2"
parking_lot = "0.10" parking_lot = "0.10"
privdrop = "0.3"
rand = { version = "0.7", features = ["small_rng"] } rand = { version = "0.7", features = ["small_rng"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -17,6 +17,7 @@ pub struct Config {
pub handlers: HandlerConfig, pub handlers: HandlerConfig,
pub statistics: StatisticsConfig, pub statistics: StatisticsConfig,
pub cleaning: CleaningConfig, 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 { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -89,6 +102,7 @@ impl Default for Config {
handlers: HandlerConfig::default(), handlers: HandlerConfig::default(),
statistics: StatisticsConfig::default(), statistics: StatisticsConfig::default(),
cleaning: CleaningConfig::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(),
}
}
}

View file

@ -1,7 +1,9 @@
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
use std::time::Duration; use std::time::Duration;
use std::thread::Builder; use std::thread::Builder;
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
use privdrop::PrivDrop;
pub mod common; pub mod common;
pub mod config; pub mod config;
@ -35,11 +37,14 @@ pub fn run(config: Config){
).expect("spawn request worker"); ).expect("spawn request worker");
} }
let num_bound_sockets = Arc::new(AtomicUsize::new(0));
for i in 0..config.socket_workers { for i in 0..config.socket_workers {
let state = state.clone(); let state = state.clone();
let config = config.clone(); let config = config.clone();
let request_sender = request_sender.clone(); let request_sender = request_sender.clone();
let response_receiver = response_receiver.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 || Builder::new().name(format!("socket-{:02}", i + 1)).spawn(move ||
network::run_socket_worker( network::run_socket_worker(
@ -48,6 +53,7 @@ pub fn run(config: Config){
i, i,
request_sender, request_sender,
response_receiver, response_receiver,
num_bound_sockets,
) )
).expect("spawn socket worker"); ).expect("spawn socket worker");
} }
@ -67,6 +73,24 @@ pub fn run(config: Config){
).expect("spawn statistics thread"); ).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 { loop {
::std::thread::sleep(Duration::from_secs(config.cleaning.interval)); ::std::thread::sleep(Duration::from_secs(config.cleaning.interval));

View file

@ -1,4 +1,4 @@
use std::sync::atomic::Ordering; use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
use std::io::{Cursor, ErrorKind}; use std::io::{Cursor, ErrorKind};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::time::Duration; use std::time::Duration;
@ -23,6 +23,7 @@ pub fn run_socket_worker(
token_num: usize, token_num: usize,
request_sender: Sender<(Request, SocketAddr)>, request_sender: Sender<(Request, SocketAddr)>,
response_receiver: Receiver<(Response, SocketAddr)>, response_receiver: Receiver<(Response, SocketAddr)>,
num_bound_sockets: Arc<AtomicUsize>,
){ ){
let mut buffer = [0u8; MAX_PACKET_SIZE]; let mut buffer = [0u8; MAX_PACKET_SIZE];
@ -35,6 +36,8 @@ pub fn run_socket_worker(
.register(&mut socket, Token(token_num), interests) .register(&mut socket, Token(token_num), interests)
.unwrap(); .unwrap();
num_bound_sockets.fetch_add(1, Ordering::SeqCst);
let mut events = Events::with_capacity(config.network.poll_event_capacity); let mut events = Events::with_capacity(config.network.poll_event_capacity);
let mut requests: Vec<(Request, SocketAddr)> = Vec::new(); let mut requests: Vec<(Request, SocketAddr)> = Vec::new();