udp, http: move privilege drop code into aquatic_common

This commit is contained in:
Joakim Frostegård 2021-10-27 20:49:15 +02:00
parent ead7650d41
commit d6d5cc78b7
11 changed files with 72 additions and 87 deletions

2
Cargo.lock generated
View file

@ -79,6 +79,7 @@ dependencies = [
"hashbrown 0.11.2", "hashbrown 0.11.2",
"hex", "hex",
"indexmap", "indexmap",
"privdrop",
"rand", "rand",
"serde", "serde",
] ]
@ -179,7 +180,6 @@ dependencies = [
"mimalloc", "mimalloc",
"mio", "mio",
"parking_lot", "parking_lot",
"privdrop",
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",
"rand", "rand",

View file

@ -16,5 +16,6 @@ arc-swap = "1"
hashbrown = "0.11.2" hashbrown = "0.11.2"
hex = "0.4" hex = "0.4"
indexmap = "1" indexmap = "1"
privdrop = "0.5"
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -6,6 +6,7 @@ use rand::Rng;
pub mod access_list; pub mod access_list;
pub mod cpu_pinning; pub mod cpu_pinning;
pub mod privileges;
/// Peer or connection valid until this instant /// Peer or connection valid until this instant
/// ///

View file

@ -0,0 +1,59 @@
use std::{sync::{Arc, atomic::{AtomicUsize, Ordering}}, time::Duration};
use privdrop::PrivDrop;
use serde::{Serialize, Deserialize};
#[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 PrivilegeConfig {
fn default() -> Self {
Self {
drop_privileges: false,
chroot_path: ".".to_string(),
user: "nobody".to_string(),
}
}
}
pub fn drop_privileges_after_socket_binding(
config: &PrivilegeConfig,
num_bound_sockets: Arc<AtomicUsize>,
target_num: usize,
) -> anyhow::Result<()> {
if config.drop_privileges {
let mut counter = 0usize;
loop {
let num_bound = num_bound_sockets.load(Ordering::SeqCst);
if num_bound == target_num {
PrivDrop::default()
.chroot(config.chroot_path.clone())
.user(config.user.clone())
.apply()?;
break;
}
::std::thread::sleep(Duration::from_millis(10));
counter += 1;
if counter == 500 {
panic!("Sockets didn't bind in time for privilege drop.");
}
}
}
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::{net::SocketAddr, path::PathBuf}; use std::{net::SocketAddr, path::PathBuf};
use aquatic_common::access_list::AccessListConfig; use aquatic_common::{access_list::AccessListConfig, privileges::PrivilegeConfig};
use aquatic_common::cpu_pinning::CpuPinningConfig; use aquatic_common::cpu_pinning::CpuPinningConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -94,17 +94,6 @@ pub struct StatisticsConfig {
pub interval: u64, pub interval: u64,
} }
#[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 {
@ -118,7 +107,7 @@ impl Default for Config {
statistics: StatisticsConfig::default(), statistics: StatisticsConfig::default(),
privileges: PrivilegeConfig::default(), privileges: PrivilegeConfig::default(),
access_list: AccessListConfig::default(), access_list: AccessListConfig::default(),
cpu_pinning: CpuPinningConfig::default(), cpu_pinning: Default::default(),
} }
} }
} }
@ -171,16 +160,6 @@ impl Default for StatisticsConfig {
} }
} }
impl Default for PrivilegeConfig {
fn default() -> Self {
Self {
drop_privileges: false,
chroot_path: ".".to_string(),
user: "nobody".to_string(),
}
}
}
impl Default for TlsConfig { impl Default for TlsConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {

View file

@ -4,7 +4,7 @@ use std::{
sync::{atomic::AtomicUsize, Arc}, sync::{atomic::AtomicUsize, Arc},
}; };
use aquatic_common::access_list::AccessList; use aquatic_common::{access_list::AccessList, privileges::drop_privileges_after_socket_binding};
use glommio::{channels::channel_mesh::MeshBuilder, prelude::*}; use glommio::{channels::channel_mesh::MeshBuilder, prelude::*};
use crate::config::Config; use crate::config::Config;
@ -94,7 +94,7 @@ pub fn run(config: Config) -> anyhow::Result<()> {
executors.push(executor); executors.push(executor);
} }
// drop_privileges_after_socket_binding(&config, num_bound_sockets).unwrap(); drop_privileges_after_socket_binding(&config.privileges, num_bound_sockets, config.socket_workers).unwrap();
for executor in executors { for executor in executors {
executor executor

View file

@ -32,7 +32,6 @@ indexmap = "1"
log = "0.4" log = "0.4"
mimalloc = { version = "0.1", default-features = false } mimalloc = { version = "0.1", default-features = false }
parking_lot = "0.11" parking_lot = "0.11"
privdrop = "0.5"
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -1,6 +1,6 @@
use std::net::SocketAddr; use std::net::SocketAddr;
use aquatic_common::access_list::AccessListConfig; use aquatic_common::{access_list::AccessListConfig, privileges::PrivilegeConfig};
use aquatic_common::cpu_pinning::CpuPinningConfig; use aquatic_common::cpu_pinning::CpuPinningConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -99,17 +99,6 @@ pub struct CleaningConfig {
pub max_connection_age: u64, pub max_connection_age: u64,
} }
#[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 {
@ -177,13 +166,3 @@ 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,11 +1,11 @@
use std::sync::{atomic::AtomicUsize, Arc}; use std::sync::{atomic::AtomicUsize, Arc};
use aquatic_common::access_list::AccessList; use aquatic_common::access_list::AccessList;
use aquatic_common::privileges::drop_privileges_after_socket_binding;
use glommio::channels::channel_mesh::MeshBuilder; use glommio::channels::channel_mesh::MeshBuilder;
use glommio::prelude::*; use glommio::prelude::*;
use crate::config::Config; use crate::config::Config;
use crate::drop_privileges_after_socket_binding;
mod common; mod common;
pub mod handlers; pub mod handlers;
@ -88,7 +88,7 @@ pub fn run(config: Config) -> anyhow::Result<()> {
executors.push(executor); executors.push(executor);
} }
drop_privileges_after_socket_binding(&config, num_bound_sockets).unwrap(); drop_privileges_after_socket_binding(&config.privileges, num_bound_sockets, config.socket_workers).unwrap();
for executor in executors { for executor in executors {
executor executor

View file

@ -16,7 +16,6 @@ pub mod glommio;
pub mod mio; pub mod mio;
use config::Config; use config::Config;
use privdrop::PrivDrop;
pub const APP_NAME: &str = "aquatic_udp: UDP BitTorrent tracker"; pub const APP_NAME: &str = "aquatic_udp: UDP BitTorrent tracker";
@ -28,36 +27,4 @@ pub fn run(config: Config) -> ::anyhow::Result<()> {
mio::run(config) mio::run(config)
} }
} }
} }
fn drop_privileges_after_socket_binding(
config: &Config,
num_bound_sockets: Arc<AtomicUsize>,
) -> anyhow::Result<()> {
if config.privileges.drop_privileges {
let mut counter = 0usize;
loop {
let sockets = num_bound_sockets.load(Ordering::SeqCst);
if sockets == config.socket_workers {
PrivDrop::default()
.chroot(config.privileges.chroot_path.clone())
.user(config.privileges.user.clone())
.apply()?;
break;
}
::std::thread::sleep(Duration::from_millis(10));
counter += 1;
if counter == 500 {
panic!("Sockets didn't bind in time for privilege drop.");
}
}
}
Ok(())
}

View file

@ -6,6 +6,7 @@ use std::{
}; };
use anyhow::Context; use anyhow::Context;
use aquatic_common::privileges::drop_privileges_after_socket_binding;
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
pub mod common; pub mod common;
@ -16,7 +17,6 @@ pub mod tasks;
use aquatic_common::access_list::{AccessListArcSwap, AccessListMode, AccessListQuery}; use aquatic_common::access_list::{AccessListArcSwap, AccessListMode, AccessListQuery};
use crate::config::Config; use crate::config::Config;
use crate::drop_privileges_after_socket_binding;
use common::State; use common::State;
@ -35,7 +35,7 @@ pub fn run(config: Config) -> ::anyhow::Result<()> {
start_workers(config.clone(), state.clone(), num_bound_sockets.clone())?; start_workers(config.clone(), state.clone(), num_bound_sockets.clone())?;
drop_privileges_after_socket_binding(&config, num_bound_sockets).unwrap(); drop_privileges_after_socket_binding(&config.privileges, num_bound_sockets, config.socket_workers).unwrap();
loop { loop {
::std::thread::sleep(Duration::from_secs(config.cleaning.interval)); ::std::thread::sleep(Duration::from_secs(config.cleaning.interval));