diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-06-09 16:08:51 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-06-09 16:08:51 +0200 |
| commit | deaf23daa2e3aa2a3ece934481d105e0e46c99bc (patch) | |
| tree | baec8efc2d1fc9768d1cc76b240e894577bcd017 | |
| parent | 6b888626d14939f9c61583716363bfbb00182dad (diff) | |
| parent | f81f0d6bd22ef0bf33f577856d72e3ab6c81ce52 (diff) | |
| download | mullvadvpn-deaf23daa2e3aa2a3ece934481d105e0e46c99bc.tar.xz mullvadvpn-deaf23daa2e3aa2a3ece934481d105e0e46c99bc.zip | |
Merge branch 'win-pipe-permissions'
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | talpid-ipc/Cargo.toml | 3 | ||||
| -rw-r--r-- | talpid-ipc/src/lib.rs | 6 | ||||
| -rw-r--r-- | talpid-ipc/src/win.rs | 175 |
4 files changed, 184 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock index 12e09896f3..df894cd109 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2877,6 +2877,7 @@ dependencies = [ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/talpid-ipc/Cargo.toml b/talpid-ipc/Cargo.toml index 31ad7ca753..0a15db0f48 100644 --- a/talpid-ipc/Cargo.toml +++ b/talpid-ipc/Cargo.toml @@ -21,6 +21,9 @@ futures = "0.1" jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs", rev = "68aac55b" } jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs", rev = "68aac55b" } +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["accctrl", "aclapi", "securitybaseapi", "winbase", "winerror", "winnt"] } + [dev-dependencies] assert_matches = "1.0" env_logger = "0.7" diff --git a/talpid-ipc/src/lib.rs b/talpid-ipc/src/lib.rs index 83ddd03991..2ab6d506c3 100644 --- a/talpid-ipc/src/lib.rs +++ b/talpid-ipc/src/lib.rs @@ -6,9 +6,11 @@ use std::{io, thread}; use jsonrpc_core::{MetaIoHandler, Metadata}; use jsonrpc_ipc_server::{MetaExtractor, NoopExtractor, SecurityAttributes, Server, ServerBuilder}; - use std::fmt; +#[cfg(windows)] +mod win; + /// An Id created by the Ipc server that the client can use to connect to it pub type IpcServerId = String; @@ -78,6 +80,8 @@ impl IpcServer { fs::set_permissions(&path, PermissionsExt::from_mode(0o766)) .map_err(Error::PermissionsError)?; } + #[cfg(windows)] + win::deny_network_access(path).map_err(Error::PermissionsError)?; Ok(server) } diff --git a/talpid-ipc/src/win.rs b/talpid-ipc/src/win.rs new file mode 100644 index 0000000000..a555a652f9 --- /dev/null +++ b/talpid-ipc/src/win.rs @@ -0,0 +1,175 @@ +#![cfg(windows)] +use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr}; +use winapi::{ + shared::{minwindef::DWORD, winerror::ERROR_SUCCESS}, + um::{ + accctrl::*, + aclapi::{SetEntriesInAclW, SetSecurityInfo}, + fileapi::{CreateFileW, OPEN_EXISTING}, + handleapi::{CloseHandle, INVALID_HANDLE_VALUE}, + securitybaseapi::{AllocateAndInitializeSid, FreeSid}, + winbase::LocalFree, + winnt::*, + }, +}; + +struct Sid { + sid_ptr: PSID, +} + +impl Sid { + pub fn new(authority: PSID_IDENTIFIER_AUTHORITY, relative_id: DWORD) -> Result<Sid, io::Error> { + let mut sid = Sid { + sid_ptr: ptr::null_mut(), + }; + + let result = unsafe { + AllocateAndInitializeSid( + authority, + 1, + relative_id, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &mut sid.sid_ptr as *mut _, + ) + }; + if result != 0 { + Ok(sid) + } else { + Err(io::Error::last_os_error()) + } + } + + pub fn as_ptr(&self) -> PSID { + self.sid_ptr + } +} + +impl Drop for Sid { + fn drop(&mut self) { + unsafe { FreeSid(self.sid_ptr) }; + } +} + +struct WinHandle(HANDLE); + +impl WinHandle { + pub fn get_raw(&self) -> HANDLE { + self.0 + } +} + +impl Drop for WinHandle { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} + +pub fn deny_network_access<T: AsRef<OsStr>>(ipc_path: T) -> Result<(), io::Error> { + let ipc_w: Vec<_> = ipc_path.as_ref().encode_wide().collect(); + + let pipe_handle = unsafe { + CreateFileW( + ipc_w.as_ptr(), + GENERIC_WRITE | WRITE_DAC, + 0, + ptr::null_mut(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ) + }; + + if pipe_handle == INVALID_HANDLE_VALUE { + return Err(io::Error::last_os_error()); + } + + let pipe_handle = WinHandle(pipe_handle); + + let network_sid = Sid::new( + SECURITY_NT_AUTHORITY.as_mut_ptr() as *mut _, + SECURITY_NETWORK_RID, + )?; + + let mut network_access: EXPLICIT_ACCESS_W = unsafe { std::mem::zeroed() }; + network_access.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + network_access.grfAccessMode = DENY_ACCESS; + network_access.grfInheritance = NO_INHERITANCE; + network_access.Trustee.TrusteeForm = TRUSTEE_IS_SID; + network_access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + network_access.Trustee.ptstrName = network_sid.as_ptr() as *mut _; + + let network_svc_sid = Sid::new( + SECURITY_NT_AUTHORITY.as_mut_ptr() as *mut _, + SECURITY_NETWORK_SERVICE_RID, + )?; + + let mut network_svc_access: EXPLICIT_ACCESS_W = unsafe { std::mem::zeroed() }; + network_svc_access.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + network_svc_access.grfAccessMode = DENY_ACCESS; + network_svc_access.grfInheritance = NO_INHERITANCE; + network_svc_access.Trustee.TrusteeForm = TRUSTEE_IS_SID; + network_svc_access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + network_svc_access.Trustee.ptstrName = network_svc_sid.as_ptr() as *mut _; + + let everyone_sid = Sid::new( + SECURITY_WORLD_SID_AUTHORITY.as_mut_ptr() as *mut _, + SECURITY_WORLD_RID, + )?; + + let mut world_access: EXPLICIT_ACCESS_W = unsafe { std::mem::zeroed() }; + world_access.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + world_access.grfAccessMode = SET_ACCESS; + world_access.grfInheritance = NO_INHERITANCE; + world_access.Trustee.TrusteeForm = TRUSTEE_IS_SID; + world_access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + world_access.Trustee.ptstrName = everyone_sid.as_ptr() as *mut _; + + let mut ace_entries = vec![network_access, network_svc_access, world_access]; + + let mut new_dacl: PACL = unsafe { std::mem::zeroed() }; + let result = unsafe { + SetEntriesInAclW( + ace_entries.len() as u32, + ace_entries.as_mut_ptr(), + ptr::null_mut(), + &mut new_dacl as *mut PACL, + ) + }; + if result != ERROR_SUCCESS { + // A non-zero error code in WinError.h + return Err(io::Error::new( + io::ErrorKind::Other, + format!("SetEntriesInAclW failed: {}", result), + )); + } + + let result = unsafe { + SetSecurityInfo( + pipe_handle.get_raw(), + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + ptr::null_mut(), + ptr::null_mut(), + new_dacl as *mut ACL, + ptr::null_mut(), + ) + }; + + unsafe { LocalFree(new_dacl as *mut _) }; + + if result != ERROR_SUCCESS { + // A non-zero error code in WinError.h + return Err(io::Error::new( + io::ErrorKind::Other, + format!("SetSecurityInfo failed: {}", result), + )); + } + + Ok(()) +} |
