diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2022-09-21 15:06:31 +0200 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2022-09-21 15:06:31 +0200 |
| commit | 38dbbabc416076456ff9c80f5d5e62c573a13f0d (patch) | |
| tree | 816703c1465157759b1bfdf2ff2484952127412d | |
| parent | d4b7d8004ac0074aa27048d0c97b988e740abab7 (diff) | |
| parent | 55ab6decf719e9769fe7864ec7961118c275f404 (diff) | |
| download | mullvadvpn-38dbbabc416076456ff9c80f5d5e62c573a13f0d.tar.xz mullvadvpn-38dbbabc416076456ff9c80f5d5e62c573a13f0d.zip | |
Merge branch 'linux-block-during-shutdown'
| -rw-r--r-- | CHANGELOG.md | 5 | ||||
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 3 | ||||
| -rw-r--r-- | mullvad-daemon/src/main.rs | 10 | ||||
| -rw-r--r-- | mullvad-daemon/src/shutdown.rs | 25 | ||||
| -rw-r--r-- | talpid-dbus/src/lib.rs | 1 | ||||
| -rw-r--r-- | talpid-dbus/src/systemd.rs | 67 |
8 files changed, 108 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 125cd3bab5..b1ed1e7d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,10 +74,13 @@ Line wrap the file at 100 chars. Th - Don't fail install if the device tree contains nameless callout driver devices. ### Security -#### Linux - Added traffic blocking during early boot, before the daemon starts, to prevent leaks in the case that the system service starts after a networking daemon has already configured a network interface. +- When the system process is being shut down and the target state is _secured_, maintain the + blocking firewall rules unless it's possible to deduce that the system isn't shutting down and the + system service is being stopped by the user intentionally. This is to prevent leaks that might + occur during system shutdown. ## [android/2022.2-beta2] - 2022-09-09 diff --git a/Cargo.lock b/Cargo.lock index 201b3f31d6..c53f7641df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1593,6 +1593,7 @@ dependencies = [ "serde_json", "simple-signal", "talpid-core", + "talpid-dbus", "talpid-platform-metadata", "talpid-time", "talpid-types", diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml index 6a811659c5..6eac4eb156 100644 --- a/mullvad-daemon/Cargo.toml +++ b/mullvad-daemon/Cargo.toml @@ -34,6 +34,7 @@ mullvad-relay-selector = { path = "../mullvad-relay-selector" } mullvad-types = { path = "../mullvad-types" } mullvad-api = { path = "../mullvad-api" } talpid-core = { path = "../talpid-core" } +talpid-dbus = { path = "../talpid-dbus" } talpid-types = { path = "../talpid-types" } talpid-platform-metadata = { path = "../talpid-platform-metadata" } talpid-time = { path = "../talpid-time" } diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index 88dd9da735..d2aea87af8 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -22,6 +22,7 @@ mod migrations; pub mod rpc_uniqueness_check; pub mod runtime; pub mod settings; +pub mod shutdown; mod target_state; mod tunnel; pub mod version; @@ -2159,11 +2160,9 @@ where } } - #[cfg_attr(not(target_os = "windows"), allow(unused_variables))] fn trigger_shutdown_event(&mut self, user_init_shutdown: bool) { // Block all traffic before shutting down to ensure that no traffic can leak on boot or // shutdown. - #[cfg(windows)] if !user_init_shutdown && (*self.target_state == TargetState::Secured || self.settings.auto_connect) { diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index 1d929c2d4a..23946fbf1a 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -14,7 +14,6 @@ mod cli; #[cfg(target_os = "linux")] mod early_boot_firewall; mod exception_logging; -mod shutdown; #[cfg(windows)] mod system_service; @@ -138,7 +137,14 @@ async fn run_standalone(log_dir: Option<PathBuf>) -> Result<(), String> { let daemon = create_daemon(log_dir).await?; let shutdown_handle = daemon.shutdown_handle(); - shutdown::set_shutdown_signal_handler(move || shutdown_handle.shutdown(true)) + #[cfg(any(target_os = "linux", target_os = "macos"))] + mullvad_daemon::shutdown::set_shutdown_signal_handler(move || { + shutdown_handle.shutdown(!mullvad_daemon::shutdown::is_shutdown_user_initiated()) + }) + .map_err(|e| e.display_chain())?; + + #[cfg(any(windows, target_os = "android"))] + mullvad_daemon::shutdown::set_shutdown_signal_handler(move || shutdown_handle.shutdown(true)) .map_err(|e| e.display_chain())?; daemon.run().await.map_err(|e| e.display_chain())?; diff --git a/mullvad-daemon/src/shutdown.rs b/mullvad-daemon/src/shutdown.rs index 8dff1bc553..a3f04a0c49 100644 --- a/mullvad-daemon/src/shutdown.rs +++ b/mullvad-daemon/src/shutdown.rs @@ -27,4 +27,29 @@ mod platform { } } +/// Returns true if systemd successfully reported that the machine is not shutting down or entering +/// maintenance. If obtaining this information fails, the return value will be `false` and it will +/// be assumed that the machine is shutting down. +#[cfg(target_os = "linux")] +pub fn is_shutdown_user_initiated() -> bool { + match talpid_dbus::systemd::is_host_running() { + Ok(is_host_running) => is_host_running, + Err(err) => { + log::error!( + "{}", + talpid_types::ErrorExt::display_chain_with_msg( + &err, + "Failed to determine if host is shutting down, assuming it is shutting down" + ) + ); + false + } + } +} + +#[cfg(target_os = "macos")] +pub fn is_shutdown_user_initiated() -> bool { + false +} + pub use self::platform::*; diff --git a/talpid-dbus/src/lib.rs b/talpid-dbus/src/lib.rs index c4b9bb7e12..f85581864a 100644 --- a/talpid-dbus/src/lib.rs +++ b/talpid-dbus/src/lib.rs @@ -4,6 +4,7 @@ pub use dbus; use dbus::blocking::SyncConnection; use std::sync::{Arc, Mutex}; pub mod network_manager; +pub mod systemd; pub mod systemd_resolved; lazy_static::lazy_static! { diff --git a/talpid-dbus/src/systemd.rs b/talpid-dbus/src/systemd.rs new file mode 100644 index 0000000000..521f2a1b8e --- /dev/null +++ b/talpid-dbus/src/systemd.rs @@ -0,0 +1,67 @@ +use dbus::blocking::{stdintf::org_freedesktop_dbus::Properties, Proxy, SyncConnection}; +use std::{sync::Arc, time::Duration}; + +type Result<T> = std::result::Result<T, Error>; + +#[derive(err_derive::Error, Debug)] +#[error(no_from)] +pub enum Error { + #[error(display = "Failed to create a DBus connection")] + ConnectError(#[error(source)] dbus::Error), + + #[error(display = "Failed to read SystemState property")] + ReadSystemStateError(#[error(source)] dbus::Error), +} + +const SYSTEMD_BUS: &str = "org.freedesktop.systemd1"; +const SYSTEMD_PATH: &str = "/org/freedesktop/systemd1"; +const MANAGER_INTERFACE: &str = "org.freedesktop.systemd1.Manager"; +const SYSTEM_STATE: &str = "SystemState"; +const SYSTEM_STATE_STARTING: &str = "starting"; +const SYSTEM_STATE_INITIALIZING: &str = "initializing"; +const SYSTEM_STATE_RUNNING: &str = "running"; +const SYSTEM_STATE_DEGRADED: &str = "degraded"; + +const RPC_TIMEOUT: Duration = Duration::from_secs(1); + +/// Returns true if the host is not shutting down or entering maintenance mode or some other weird +/// state. +pub fn is_host_running() -> Result<bool> { + Systemd::new()?.system_is_running() +} + +struct Systemd { + pub dbus_connection: Arc<SyncConnection>, +} + +impl Systemd { + fn new() -> Result<Self> { + Ok(Self { + dbus_connection: crate::get_connection().map_err(Error::ConnectError)?, + }) + } + + fn system_is_running(&self) -> Result<bool> { + self.as_manager_object() + .get(MANAGER_INTERFACE, SYSTEM_STATE) + .map(|state: String| { + ![ + SYSTEM_STATE_STARTING, + SYSTEM_STATE_INITIALIZING, + SYSTEM_STATE_RUNNING, + SYSTEM_STATE_DEGRADED, + ] + .contains(&state.as_str()) + }) + .map_err(Error::ReadSystemStateError) + } + + fn as_manager_object(&self) -> Proxy<'_, &SyncConnection> { + Proxy::new( + SYSTEMD_BUS, + SYSTEMD_PATH, + RPC_TIMEOUT, + &self.dbus_connection, + ) + } +} |
