summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2025-03-12 13:29:35 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2025-03-12 17:11:37 +0100
commit54e0beacffabe26e216e32fb808c643b1e59022d (patch)
tree0971bdc53aa817cbb3011bcc22e99e2900f5a10c
parent619276793f4162e92da4d02b072e10f3ed24a0da (diff)
downloadmullvadvpn-54e0beacffabe26e216e32fb808c643b1e59022d.tar.xz
mullvadvpn-54e0beacffabe26e216e32fb808c643b1e59022d.zip
Handle `SIGPIPE`
Fix `SIGPIPE` being ignored, which would cause the `mullvad-cli` to panic if it received a `PIPE` signal (e.g. it was piped into `echo`).
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock1
-rw-r--r--mullvad-cli/Cargo.toml1
-rw-r--r--mullvad-cli/src/main.rs18
4 files changed, 22 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5cbecd44cb..5650f6bbe0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,8 @@ Line wrap the file at 100 chars. Th
- Remove "Any" option for tunnel protocol. The default is now WireGuard.
### Fixed
+- Fix `mullvad-cli` panicking if it tried to write to a closed pipe on Linux and macOS.
+
#### macOS
- Fix routing issue caused by upgrading `tun`.
diff --git a/Cargo.lock b/Cargo.lock
index 03ab60ca35..8c6137b930 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2643,6 +2643,7 @@ dependencies = [
"mullvad-types",
"mullvad-version",
"natord",
+ "nix 0.29.0",
"serde",
"serde_json",
"talpid-types",
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index a489123847..70e7a63e1a 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -34,6 +34,7 @@ serde_json = { workspace = true }
[target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
clap_complete = { version = "4.4.8" }
+nix = { version = "0.29.0", features = ["signal"] }
[target.'cfg(windows)'.build-dependencies]
winres = "0.1"
diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs
index 67990bd888..c77e894d8e 100644
--- a/mullvad-cli/src/main.rs
+++ b/mullvad-cli/src/main.rs
@@ -152,6 +152,12 @@ enum Cli {
#[tokio::main]
async fn main() -> Result<()> {
+ // Handle SIGPIPE
+ // https://stackoverflow.com/questions/65755853/simple-word-count-rust-program-outputs-valid-stdout-but-panicks-when-piped-to-he/65760807
+ // https://github.com/typst/typst/pull/5444
+ #[cfg(unix)]
+ handle_sigpipe().unwrap();
+
match Cli::parse() {
Cli::Account(cmd) => cmd.handle().await,
Cli::Bridge(cmd) => cmd.handle().await,
@@ -189,3 +195,15 @@ async fn main() -> Result<()> {
}
}
}
+
+/// Install the default signal handler for `SIGPIPE`.
+///
+/// By default, Rust replaces it with an empty handler because reasons: https://github.com/rust-lang/rust/issues/119980
+#[cfg(unix)]
+fn handle_sigpipe() -> Result<(), nix::errno::Errno> {
+ use nix::sys::signal::{signal, SigHandler, Signal};
+ // SAFETY: We do not use the previous signal handler, which could cause UB if done carelessly:
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html
+ unsafe { signal(Signal::SIGPIPE, SigHandler::SigDfl) }?;
+ Ok(())
+}