diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-03-18 11:17:59 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-06-02 10:05:02 +0200 |
| commit | 0961e1096cabc07916124c7c56987b959756c0d3 (patch) | |
| tree | 7932a52c8ae553ec958c6ee3dd931176bfaf75b7 | |
| parent | 36c1dd005e79e3d2beb9bfb04235150e7e82b34c (diff) | |
| download | mullvadvpn-0961e1096cabc07916124c7c56987b959756c0d3.tar.xz mullvadvpn-0961e1096cabc07916124c7c56987b959756c0d3.zip | |
Add launcher binary for excluded apps (mullvad-exclude)
| -rw-r--r-- | Cargo.lock | 9 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rwxr-xr-x | build.sh | 1 | ||||
| -rw-r--r-- | dist-assets/linux/after-install.sh | 2 | ||||
| -rw-r--r-- | gui/tasks/distribution.js | 2 | ||||
| -rw-r--r-- | mullvad-exclude/Cargo.toml | 12 | ||||
| -rw-r--r-- | mullvad-exclude/src/main.rs | 90 |
7 files changed, 117 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock index 92246ebd57..08cff3260c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1410,6 +1410,15 @@ dependencies = [ ] [[package]] +name = "mullvad-exclude" +version = "0.1.0" +dependencies = [ + "err-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "mullvad-ipc-client" version = "0.1.0" dependencies = [ diff --git a/Cargo.toml b/Cargo.toml index bbaaee503a..2debcc071c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "mullvad-types", "mullvad-rpc", "mullvad-tests", + "mullvad-exclude", "talpid-openvpn-plugin", "talpid-core", "talpid-ipc", @@ -167,6 +167,7 @@ elif [[ ("$(uname -s)" == "Linux") ]]; then mullvad-problem-report libtalpid_openvpn_plugin.so mullvad-setup + mullvad-exclude ) elif [[ ("$(uname -s)" == "MINGW"*) ]]; then binaries=( diff --git a/dist-assets/linux/after-install.sh b/dist-assets/linux/after-install.sh index 0abe49cbe5..b75b72dc31 100644 --- a/dist-assets/linux/after-install.sh +++ b/dist-assets/linux/after-install.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -eu +chmod u+s "/usr/bin/mullvad-exclude" + if which systemctl &> /dev/null; then systemctl enable "/opt/Mullvad VPN/resources/mullvad-daemon.service" systemctl start mullvad-daemon.service diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js index 30c0fe1f03..4e8061a7fa 100644 --- a/gui/tasks/distribution.js +++ b/gui/tasks/distribution.js @@ -126,6 +126,7 @@ const config = { '--config-files', '/opt/Mullvad VPN/resources/mullvad-daemon.conf', distAssets('mullvad') + '=/usr/bin/', + distAssets('mullvad-exclude') + '=/usr/bin/', distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report', distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad', @@ -149,6 +150,7 @@ const config = { '--config-files', '/opt/Mullvad VPN/resources/mullvad-daemon.conf', distAssets('mullvad') + '=/usr/bin/', + distAssets('mullvad-exclude') + '=/usr/bin/', distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report', distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad', diff --git a/mullvad-exclude/Cargo.toml b/mullvad-exclude/Cargo.toml new file mode 100644 index 0000000000..06e0c8ab56 --- /dev/null +++ b/mullvad-exclude/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mullvad-exclude" +version = "0.1.0" +authors = ["Mullvad VPN"] +license = "GPL-3.0" +edition = "2018" +publish = false + +[target.'cfg(target_os = "linux")'.dependencies] +nix = "0.17" +err-derive = "0.2.1" +void = "1.0.2" diff --git a/mullvad-exclude/src/main.rs b/mullvad-exclude/src/main.rs new file mode 100644 index 0000000000..133424c027 --- /dev/null +++ b/mullvad-exclude/src/main.rs @@ -0,0 +1,90 @@ +#[cfg(target_os = "linux")] +use nix::unistd::{execvp, getgid, getpid, getuid, setgid, setuid}; +#[cfg(target_os = "linux")] +use std::{ + env, + error::Error as StdError, + ffi::{CStr, CString, NulError}, + fs, io, + os::unix::ffi::OsStrExt, +}; + +#[cfg(target_os = "linux")] +const CGROUP_PROCS_PATH: &str = "/sys/fs/cgroup/net_cls/mullvad-exclusions/cgroup.procs"; + +#[cfg(target_os = "linux")] +const PROGRAM_NAME: &str = "mullvad-exclude"; + +#[cfg(target_os = "linux")] +#[derive(err_derive::Error, Debug)] +#[error(no_from)] +enum Error { + #[error(display = "Invalid arguments")] + InvalidArguments, + + #[error(display = "Cannot set the cgroup")] + AddProcToCGroup(#[error(source)] io::Error), + + #[error(display = "Failed to drop root user privileges for the process")] + DropRootUid(#[error(source)] nix::Error), + + #[error(display = "Failed to drop root group privileges for the process")] + DropRootGid(#[error(source)] nix::Error), + + #[error(display = "Failed to launch the process")] + Exec(#[error(source)] nix::Error), + + #[error(display = "An argument contains interior nul bytes")] + ArgumentNulError(#[error(source)] NulError), +} + +fn main() { + #[cfg(target_os = "linux")] + match run() { + Err(Error::InvalidArguments) => { + let mut args = env::args(); + let program = args.next().unwrap_or(PROGRAM_NAME.to_string()); + eprintln!("Usage {} COMMAND [ARGS]", program); + std::process::exit(1); + } + Err(e) => { + let mut s = format!("{}", e); + let mut source = e.source(); + while let Some(error) = source { + s.push_str(&format!("\nCaused by: {}", error)); + source = error.source(); + } + eprintln!("{}", s); + + std::process::exit(1); + } + _ => unreachable!("execv returned unexpectedly"), + } +} + +#[cfg(target_os = "linux")] +fn run() -> Result<void::Void, Error> { + let mut args_iter = env::args_os().skip(1); + let program = args_iter.next().ok_or(Error::InvalidArguments)?; + let program = CString::new(program.as_bytes()).map_err(Error::ArgumentNulError)?; + + let args: Vec<CString> = env::args_os() + .skip(1) + .map(|arg| CString::new(arg.as_bytes())) + .collect::<Result<Vec<CString>, NulError>>() + .map_err(Error::ArgumentNulError)?; + let args: Vec<&CStr> = args.iter().map(|arg| &**arg).collect(); + + // Set the cgroup of this process + fs::write(CGROUP_PROCS_PATH, getpid().to_string().as_bytes()) + .map_err(Error::AddProcToCGroup)?; + + // Drop root privileges + let real_uid = getuid(); + setuid(real_uid).map_err(Error::DropRootUid)?; + let real_gid = getgid(); + setgid(real_gid).map_err(Error::DropRootGid)?; + + // Launch the process + execvp(&program, &args).map_err(Error::Exec) +} |
