diff options
| author | Joakim Hulthe <joakim.hulthe@mullvad.net> | 2025-02-25 14:10:59 +0100 |
|---|---|---|
| committer | Joakim Hulthe <joakim.hulthe@mullvad.net> | 2025-02-25 14:10:59 +0100 |
| commit | 60ccaee30c558ec05dbe36224cdb66464fab4272 (patch) | |
| tree | 1d9f0950f9a3209f5ad4d928f4d342a9da7c2586 | |
| parent | c06b29d60703bcfcfbbb48deef3c526631f847b7 (diff) | |
| parent | 148e43dc21254caab5edcabfad6bbda957208e0e (diff) | |
| download | mullvadvpn-60ccaee30c558ec05dbe36224cdb66464fab4272.tar.xz mullvadvpn-60ccaee30c558ec05dbe36224cdb66464fab4272.zip | |
Merge branch 'document-and-lint-all-usages-of-unsafe-des-1459'
50 files changed, 268 insertions, 154 deletions
diff --git a/Cargo.lock b/Cargo.lock index 4afca015ea..aa087cf126 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4615,8 +4615,10 @@ version = "0.0.0" dependencies = [ "libc", "log", + "nix 0.29.0", "socket2", "talpid-types", + "thiserror 2.0.9", ] [[package]] @@ -4705,7 +4707,7 @@ dependencies = [ name = "talpid-time" version = "0.0.0" dependencies = [ - "libc", + "nix 0.29.0", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 0931b8a534..603912f350 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ single_use_lifetimes = "warn" [workspace.lints.clippy] unused_async = "deny" +undocumented_unsafe_blocks = "warn" [workspace.dependencies] hickory-proto = "0.24.3" diff --git a/desktop/packages/nseventforwarder/nseventforwarder-rs/lib.rs b/desktop/packages/nseventforwarder/nseventforwarder-rs/lib.rs index 09c7271e5a..152019828e 100644 --- a/desktop/packages/nseventforwarder/nseventforwarder-rs/lib.rs +++ b/desktop/packages/nseventforwarder/nseventforwarder-rs/lib.rs @@ -1,6 +1,5 @@ //! Forward [NSEvent]s from macOS to node. #![cfg(target_os = "macos")] -#![warn(clippy::undocumented_unsafe_blocks)] use std::ptr::NonNull; use std::sync::{mpsc, Arc, Mutex}; diff --git a/mullvad-api/src/ffi/mod.rs b/mullvad-api/src/ffi/mod.rs index 5eae180f01..3e0324d29b 100644 --- a/mullvad-api/src/ffi/mod.rs +++ b/mullvad-api/src/ffi/mod.rs @@ -1,4 +1,6 @@ #![cfg(not(target_os = "android"))] +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use std::{ ffi::{CStr, CString}, net::SocketAddr, diff --git a/mullvad-daemon/src/exception_logging/unix.rs b/mullvad-daemon/src/exception_logging/unix.rs index b956db8319..99bc0d8ec7 100644 --- a/mullvad-daemon/src/exception_logging/unix.rs +++ b/mullvad-daemon/src/exception_logging/unix.rs @@ -1,5 +1,4 @@ //! Install signal handlers to catch critical program faults and log them. See [`enable`]. -#![warn(clippy::undocumented_unsafe_blocks)] use libc::siginfo_t; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; diff --git a/mullvad-daemon/src/exception_logging/win.rs b/mullvad-daemon/src/exception_logging/win.rs index 3fa50aa506..2c11f61578 100644 --- a/mullvad-daemon/src/exception_logging/win.rs +++ b/mullvad-daemon/src/exception_logging/win.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] + use mullvad_paths::log_dir; use std::{ borrow::Cow, diff --git a/mullvad-daemon/src/macos_launch_daemon.rs b/mullvad-daemon/src/macos_launch_daemon.rs index 0c9c89080c..4b7a6c5efa 100644 --- a/mullvad-daemon/src/macos_launch_daemon.rs +++ b/mullvad-daemon/src/macos_launch_daemon.rs @@ -5,6 +5,8 @@ //! must be checked so that the user can be directed to approve the launch //! daemon in the system settings. +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use libc::c_longlong; use objc2::{class, msg_send, runtime::AnyObject, Encode, Encoding, RefEncode}; use std::ffi::CStr; diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index c2146752c7..58e542364f 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -229,8 +229,7 @@ async fn create_daemon(log_dir: Option<PathBuf>) -> Result<Daemon, String> { #[cfg(unix)] fn running_as_admin() -> bool { - let uid = unsafe { libc::getuid() }; - uid == 0 + nix::unistd::Uid::current().is_root() } #[cfg(windows)] diff --git a/mullvad-daemon/src/migrations/mod.rs b/mullvad-daemon/src/migrations/mod.rs index 635c2f6ebe..eaf3350e0c 100644 --- a/mullvad-daemon/src/migrations/mod.rs +++ b/mullvad-daemon/src/migrations/mod.rs @@ -227,15 +227,22 @@ pub(crate) fn migrate_device( #[cfg(windows)] mod windows { - use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, path::Path, ptr}; + use std::{ + ffi::OsStr, + io, + os::windows::ffi::OsStrExt, + path::Path, + ptr::{self, NonNull}, + }; use talpid_types::ErrorExt; use tokio::fs; use windows_sys::Win32::{ - Foundation::{LocalFree, ERROR_SUCCESS, HLOCAL, PSID}, + Foundation::{LocalFree, ERROR_SUCCESS, PSID}, Security::{ Authorization::{GetNamedSecurityInfoW, SE_FILE_OBJECT, SE_OBJECT_TYPE}, IsWellKnownSid, WinBuiltinAdministratorsSid, WinLocalSystemSid, - OWNER_SECURITY_INFORMATION, SECURITY_DESCRIPTOR, SID, WELL_KNOWN_SID_TYPE, + OWNER_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR, SID, + WELL_KNOWN_SID_TYPE, }, }; @@ -355,8 +362,8 @@ mod windows { } struct SecurityInformation { - security_descriptor: *mut SECURITY_DESCRIPTOR, - owner: PSID, + security_descriptor: NonNull<SECURITY_DESCRIPTOR>, + owner: Option<NonNull<SID>>, } impl SecurityInformation { @@ -375,9 +382,12 @@ mod windows { let mut u16_path: Vec<u16> = object_name.as_ref().encode_wide().collect(); u16_path.push(0u16); - let mut security_descriptor = ptr::null_mut(); - let mut owner = ptr::null_mut(); + let mut security_descriptor: PSECURITY_DESCRIPTOR = ptr::null_mut(); + let mut owner: PSID = ptr::null_mut(); + // SAFETY: + // - u16_path is a null-terminated UTF-16 string + // - The *mut pointers are allowed to be null let status = unsafe { GetNamedSecurityInfoW( u16_path.as_ptr(), @@ -395,25 +405,35 @@ mod windows { return Err(std::io::Error::from_raw_os_error(status as i32)); } + let Some(security_descriptor) = NonNull::new(security_descriptor) else { + return Err(std::io::Error::other("GetNamedSecurityInfoW returned null")); + }; + Ok(SecurityInformation { - security_descriptor: security_descriptor as *mut _, - owner, + security_descriptor: security_descriptor.cast::<SECURITY_DESCRIPTOR>(), + owner: NonNull::new(owner.cast::<SID>()), }) } pub fn owner(&self) -> Option<&SID> { - unsafe { (self.owner as *const SID).as_ref() } + // SAFETY: GetNamedSecurityInfoW promises that this pointer was valid, + // and it should stay valid until we deallocate self.security_descriptor. + self.owner.map(|ptr| unsafe { ptr.as_ref() }) } } impl Drop for SecurityInformation { fn drop(&mut self) { - unsafe { LocalFree(self.security_descriptor as HLOCAL) }; + // SAFETY: GetNamedSecurityInfoW promises that this pointer was valid, + // and we do not deallocate it before this point. Since we have &mut self, + // we know that no one else has a reference to security_descriptor. + unsafe { LocalFree(self.security_descriptor.as_ptr() as PSECURITY_DESCRIPTOR) }; } } fn is_well_known_sid(sid: &SID, well_known_sid_type: WELL_KNOWN_SID_TYPE) -> bool { - unsafe { IsWellKnownSid(sid as *const SID as *mut _, well_known_sid_type) == 1 } + // SAFETY: this function doesn't take ownership of sid, and is trivially safe to call. + unsafe { IsWellKnownSid(sid as *const SID as PSID, well_known_sid_type) == 1 } } } diff --git a/mullvad-daemon/src/system_service.rs b/mullvad-daemon/src/system_service.rs index ccec49486b..6b1f521474 100644 --- a/mullvad-daemon/src/system_service.rs +++ b/mullvad-daemon/src/system_service.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use crate::cli; use mullvad_daemon::{runtime::new_multi_thread, DaemonShutdownHandle}; use std::{ diff --git a/mullvad-ios/src/lib.rs b/mullvad-ios/src/lib.rs index fa23672e29..2fea39f9c7 100644 --- a/mullvad-ios/src/lib.rs +++ b/mullvad-ios/src/lib.rs @@ -1,4 +1,6 @@ #![cfg(target_os = "ios")] +#![allow(clippy::undocumented_unsafe_blocks)] + mod api_client; mod encrypted_dns_proxy; mod ephemeral_peer_proxy; diff --git a/mullvad-leak-checker/src/lib.rs b/mullvad-leak-checker/src/lib.rs index eb80211518..3a0bf43e22 100644 --- a/mullvad-leak-checker/src/lib.rs +++ b/mullvad-leak-checker/src/lib.rs @@ -47,9 +47,14 @@ impl fmt::Debug for Interface { match self { Self::Name(arg0) => f.debug_tuple("Name").field(arg0).finish(), - // SAFETY: u64 is valid for all bit patterns, so reading the union as a u64 is safe. #[cfg(target_os = "windows")] - Self::Luid(arg0) => f.debug_tuple("Luid").field(&unsafe { arg0.Value }).finish(), + Self::Luid(arg0) => f + .debug_tuple("Luid") + .field( + // SAFETY: u64 is valid for all bit patterns, so reading the union as a u64 is safe. + &unsafe { arg0.Value }, + ) + .finish(), #[cfg(target_os = "macos")] Self::Index(arg0) => f.debug_tuple("Luid").field(arg0).finish(), diff --git a/mullvad-paths/src/windows.rs b/mullvad-paths/src/windows.rs index 2898e76ba8..fa652f31f7 100644 --- a/mullvad-paths/src/windows.rs +++ b/mullvad-paths/src/windows.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use crate::{Error, Result}; use once_cell::sync::OnceCell; use std::{ @@ -362,6 +364,7 @@ fn adjust_token_privilege( privilege: &WideCStr, enable: bool, ) -> std::io::Result<()> { + // SAFETY: LUID is a C struct and can safely be zeroed. let mut privilege_luid: LUID = unsafe { mem::zeroed() }; if unsafe { LookupPrivilegeValueW(ptr::null(), privilege.as_ptr(), &mut privilege_luid) } == 0 { diff --git a/talpid-core/src/dns/macos.rs b/talpid-core/src/dns/macos.rs index aa40c0c4bc..09d9536836 100644 --- a/talpid-core/src/dns/macos.rs +++ b/talpid-core/src/dns/macos.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use parking_lot::Mutex; use std::{ collections::{BTreeSet, HashMap}, diff --git a/talpid-core/src/dns/windows/dnsapi.rs b/talpid-core/src/dns/windows/dnsapi.rs index 03d9d44abf..b33dbee592 100644 --- a/talpid-core/src/dns/windows/dnsapi.rs +++ b/talpid-core/src/dns/windows/dnsapi.rs @@ -62,6 +62,7 @@ impl DnsApi { std::thread::spawn(move || { let begin = Instant::now(); + // SAFETY: this function is trivially safe to call let result = if unsafe { (DnsFlushResolverCache)() } != 0 { let elapsed = begin.elapsed(); if elapsed >= FLUSH_TIMEOUT { diff --git a/talpid-core/src/dns/windows/iphlpapi.rs b/talpid-core/src/dns/windows/iphlpapi.rs index eeb4b3560c..a30543b4a1 100644 --- a/talpid-core/src/dns/windows/iphlpapi.rs +++ b/talpid-core/src/dns/windows/iphlpapi.rs @@ -2,6 +2,7 @@ //! <https://learn.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-setinterfacednssettings>, //! it requires at least Windows 10, build 19041. For that reason, use run-time linking and fall //! back on other methods if it is not available. +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. use crate::dns::{DnsMonitorT, ResolvedDnsConfig}; use once_cell::sync::OnceCell; diff --git a/talpid-core/src/dns/windows/netsh.rs b/talpid-core/src/dns/windows/netsh.rs index b731310056..cab3171d48 100644 --- a/talpid-core/src/dns/windows/netsh.rs +++ b/talpid-core/src/dns/windows/netsh.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use crate::dns::{DnsMonitorT, ResolvedDnsConfig}; use std::{ ffi::OsString, diff --git a/talpid-core/src/dns/windows/tcpip.rs b/talpid-core/src/dns/windows/tcpip.rs index 70bb4660d6..3e0a8ea6e1 100644 --- a/talpid-core/src/dns/windows/tcpip.rs +++ b/talpid-core/src/dns/windows/tcpip.rs @@ -164,8 +164,12 @@ fn flush_dns_cache() -> Result<(), Error> { /// Obtain a string representation for a GUID object. fn string_from_guid(guid: &GUID) -> String { let mut buffer = [0u16; 40]; - let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) } - as usize; + + let length = + // SAFETY: `guid` and `buffer` are valid references. + // StringFromGUID2 won't write past the end of the provided length. + unsafe { StringFromGUID2(guid, buffer.as_mut_ptr(), buffer.len() as i32 - 1) } as usize; + // cannot fail because `buffer` is large enough assert!(length > 0); let length = length - 1; diff --git a/talpid-core/src/firewall/windows/mod.rs b/talpid-core/src/firewall/windows/mod.rs index 8dadd7db5c..3ef49938dd 100644 --- a/talpid-core/src/firewall/windows/mod.rs +++ b/talpid-core/src/firewall/windows/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use crate::{dns::ResolvedDnsConfig, tunnel::TunnelMetadata}; use std::{ffi::CStr, io, net::IpAddr, ptr, sync::LazyLock}; diff --git a/talpid-core/src/linux/mod.rs b/talpid-core/src/linux/mod.rs index 4b5321e4f0..225534ea12 100644 --- a/talpid-core/src/linux/mod.rs +++ b/talpid-core/src/linux/mod.rs @@ -1,27 +1,16 @@ -use std::{ - ffi::{self, CString}, - io, -}; +use nix::{errno::Errno, net::if_::if_nametoindex}; /// Converts an interface name into the corresponding index. pub fn iface_index(name: &str) -> Result<libc::c_uint, IfaceIndexLookupError> { - let c_name = CString::new(name) - .map_err(|e| IfaceIndexLookupError::InvalidInterfaceName(name.to_owned(), e))?; - let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) }; - if index == 0 { - Err(IfaceIndexLookupError::InterfaceLookupError( - name.to_owned(), - io::Error::last_os_error(), - )) - } else { - Ok(index) - } + if_nametoindex(name).map_err(|error| IfaceIndexLookupError { + interface_name: name.to_owned(), + error, + }) } #[derive(Debug, thiserror::Error)] -pub enum IfaceIndexLookupError { - #[error("Invalid network interface name: {0}")] - InvalidInterfaceName(String, #[source] ffi::NulError), - #[error("Failed to get index for interface {0}")] - InterfaceLookupError(String, #[source] io::Error), +#[error("Failed to get index for interface {interface_name}: {error}")] +pub struct IfaceIndexLookupError { + pub interface_name: String, + pub error: Errno, } diff --git a/talpid-core/src/offline/windows.rs b/talpid-core/src/offline/windows.rs index 5e09763cd0..56616cba51 100644 --- a/talpid-core/src/offline/windows.rs +++ b/talpid-core/src/offline/windows.rs @@ -24,8 +24,6 @@ pub struct BroadcastListener { _notify_tx: Arc<UnboundedSender<Connectivity>>, } -unsafe impl Send for BroadcastListener {} - impl BroadcastListener { pub async fn start( notify_tx: UnboundedSender<Connectivity>, diff --git a/talpid-core/src/split_tunnel/macos/bpf.rs b/talpid-core/src/split_tunnel/macos/bpf.rs index 566cc1f56b..53d3d36fbe 100644 --- a/talpid-core/src/split_tunnel/macos/bpf.rs +++ b/talpid-core/src/split_tunnel/macos/bpf.rs @@ -132,16 +132,17 @@ impl Bpf { return Err(Error::InterfaceNameTooLong); } + // SAFETY: `name_bytes` cannot exceed the size of `ifr_name` unsafe { - // SAFETY: `name_bytes` cannot exceed the size of `ifr_name` std::ptr::copy_nonoverlapping( name_bytes.as_ptr(), &mut ifr.ifr_name as *mut _ as *mut _, name_bytes.len(), - ); - // SAFETY: The fd is valid for the lifetime of `self`, and `ifr` has a valid interface - ioctl!(self.file.as_raw_fd(), BIOCSETIF, &ifr) - } + ) + }; + + // SAFETY: The fd is valid for the lifetime of `self`, and `ifr` has a valid interface + unsafe { ioctl!(self.file.as_raw_fd(), BIOCSETIF, &ifr) } } /// Enable or disable immediate mode (BIOCIMMEDIATE) diff --git a/talpid-core/src/split_tunnel/macos/tun.rs b/talpid-core/src/split_tunnel/macos/tun.rs index 90581c736c..2533e8a360 100644 --- a/talpid-core/src/split_tunnel/macos/tun.rs +++ b/talpid-core/src/split_tunnel/macos/tun.rs @@ -20,7 +20,7 @@ use pnet_packet::{ MutablePacket, Packet, }; use std::{ - ffi::{c_uint, CStr}, + ffi::c_uint, io::{self, IoSlice, Write}, net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; @@ -887,8 +887,14 @@ impl PacketCodec for PktapCodec { return None; } - let iface = unsafe { CStr::from_ptr(header.pth_ifname.as_ptr() as *const _) }; - if iface.to_bytes() != self.interface.as_bytes() { + // cast the array from [i8] to [u8] to enable comparison with String::as_bytes + let iface = header.pth_ifname.map(|b| b as u8); + // get the interface name by splitting on the first null byte (if any) + let iface = iface + .split(|&b| b == 0) + .next() + .expect("split will yield at least one element"); + if iface != self.interface.as_bytes() { return None; } diff --git a/talpid-core/src/split_tunnel/windows/driver.rs b/talpid-core/src/split_tunnel/windows/driver.rs index e3026b0d95..9625e41406 100644 --- a/talpid-core/src/split_tunnel/windows/driver.rs +++ b/talpid-core/src/split_tunnel/windows/driver.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use super::windows::{ get_device_path, get_process_creation_time, get_process_device_path, open_process, ProcessAccess, diff --git a/talpid-core/src/split_tunnel/windows/mod.rs b/talpid-core/src/split_tunnel/windows/mod.rs index 1c446377fc..79c0d09a5c 100644 --- a/talpid-core/src/split_tunnel/windows/mod.rs +++ b/talpid-core/src/split_tunnel/windows/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + mod driver; mod path_monitor; mod service; diff --git a/talpid-core/src/window.rs b/talpid-core/src/window.rs index 30df21f2da..33e83614b3 100644 --- a/talpid-core/src/window.rs +++ b/talpid-core/src/window.rs @@ -1,4 +1,5 @@ //! Utilities for working with windows on Windows. +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. use std::{os::windows::io::AsRawHandle, ptr, sync::Arc, thread}; use tokio::sync::broadcast; diff --git a/talpid-net/Cargo.toml b/talpid-net/Cargo.toml index 861e1765cc..485eaa37d0 100644 --- a/talpid-net/Cargo.toml +++ b/talpid-net/Cargo.toml @@ -15,3 +15,5 @@ libc = "0.2" talpid-types = { path = "../talpid-types" } socket2 = { workspace = true, features = ["all"] } log = { workspace = true } +thiserror = { workspace = true } +nix = { version = "0.29", features = ["net"] } diff --git a/talpid-net/src/unix.rs b/talpid-net/src/unix.rs index ef2bfdeb27..48d65c45f0 100644 --- a/talpid-net/src/unix.rs +++ b/talpid-net/src/unix.rs @@ -1,10 +1,26 @@ #![cfg(any(target_os = "linux", target_os = "macos"))] -use std::{io, os::fd::AsRawFd}; +use std::{ffi::c_uint, io, os::fd::AsRawFd}; +use nix::{errno::Errno, net::if_::if_nametoindex}; use socket2::Domain; use talpid_types::ErrorExt; +/// Converts an interface name into the corresponding index. +pub fn iface_index(name: &str) -> Result<c_uint, IfaceIndexLookupError> { + if_nametoindex(name).map_err(|error| IfaceIndexLookupError { + interface_name: name.to_owned(), + error, + }) +} + +#[derive(Debug, thiserror::Error)] +#[error("Failed to get index for interface {interface_name}: {error}")] +pub struct IfaceIndexLookupError { + pub interface_name: String, + pub error: Errno, +} + #[cfg(target_os = "macos")] const SIOCSIFMTU: u64 = 0x80206934; #[cfg(target_os = "macos")] @@ -21,6 +37,7 @@ pub fn set_mtu(interface_name: &str, mtu: u16) -> Result<(), io::Error> { Some(socket2::Protocol::TCP), )?; + // SAFETY: ifreq is a C struct, these can safely be zeroed. let mut ifr: libc::ifreq = unsafe { std::mem::zeroed() }; if interface_name.len() >= ifr.ifr_name.len() { return Err(io::Error::new( @@ -55,6 +72,7 @@ pub fn get_mtu(interface_name: &str) -> Result<u16, io::Error> { Some(socket2::Protocol::TCP), )?; + // SAFETY: ifreq is a C struct, these can safely be zeroed. let mut ifr: libc::ifreq = unsafe { std::mem::zeroed() }; if interface_name.len() >= ifr.ifr_name.len() { return Err(io::Error::new( diff --git a/talpid-openvpn/src/lib.rs b/talpid-openvpn/src/lib.rs index d01290e6f3..399bc3fa36 100644 --- a/talpid-openvpn/src/lib.rs +++ b/talpid-openvpn/src/lib.rs @@ -200,6 +200,7 @@ impl std::fmt::Debug for dyn WintunContext { write!( f, "WintunContext {{ luid: {}, ipv6: {} }}", + // SAFETY: It's always safe to interpet a LUID as an u64 unsafe { self.luid().Value }, self.ipv6() ) diff --git a/talpid-openvpn/src/wintun.rs b/talpid-openvpn/src/wintun.rs index e3e7938828..ef5ebd5482 100644 --- a/talpid-openvpn/src/wintun.rs +++ b/talpid-openvpn/src/wintun.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use once_cell::sync::OnceCell; use std::{ffi::CStr, fmt, io, mem, os::windows::io::RawHandle, path::Path, ptr}; use talpid_types::{win32_err, ErrorExt}; @@ -347,8 +349,11 @@ fn find_adapter_registry_key(find_guid: &str, permissions: REG_SAM_FLAGS) -> io: /// Obtain a string representation for a GUID object. fn string_from_guid(guid: &GUID) -> String { let mut buffer = [0u16; 40]; - let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) } - as usize; + + // SAFETY: `guid` and `buffer` are valid references. + let length = + unsafe { StringFromGUID2(guid, buffer.as_mut_ptr(), buffer.len() as i32 - 1) } as usize; + // cannot fail because `buffer` is large enough assert!(length > 0); let length = length - 1; diff --git a/talpid-platform-metadata/src/windows.rs b/talpid-platform-metadata/src/windows.rs index 1df2cb0f12..99e2f18b3c 100644 --- a/talpid-platform-metadata/src/windows.rs +++ b/talpid-platform-metadata/src/windows.rs @@ -4,10 +4,13 @@ use std::{ mem::{self, MaybeUninit}, os::windows::ffi::OsStrExt, }; -use windows_sys::Win32::System::{ - LibraryLoader::{GetModuleHandleW, GetProcAddress}, - SystemInformation::OSVERSIONINFOEXW, - SystemServices::VER_NT_WORKSTATION, +use windows_sys::Win32::{ + Foundation::{NTSTATUS, STATUS_SUCCESS}, + System::{ + LibraryLoader::{GetModuleHandleW, GetProcAddress}, + SystemInformation::OSVERSIONINFOEXW, + SystemServices::VER_NT_WORKSTATION, + }, }; #[allow(non_camel_case_types)] @@ -49,27 +52,43 @@ impl WindowsVersion { .chain(iter::once(0u16)) .collect(); + // SAFETY: module_name is a valid UTF-16/WTF-16 null-terminated string. let ntdll = unsafe { GetModuleHandleW(module_name.as_ptr()) }; if ntdll == 0 { return Err(io::Error::last_os_error()); } + // SAFETY: ntdll is a valid pointer, RtlGetVersion is a valid null-terminated ANSI string. let function_address = unsafe { GetProcAddress(ntdll, b"RtlGetVersion\0" as *const u8) } .ok_or_else(io::Error::last_os_error)?; - let rtl_get_version: extern "stdcall" fn(*mut RTL_OSVERSIONINFOEXW) = - unsafe { *(&function_address as *const _ as *const _) }; + // SAFETY: We're correcting this function pointer to the ACTUAL type of RtlGetVersion. + // https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion + let rtl_get_version = unsafe { + mem::transmute::< + unsafe extern "system" fn() -> isize, + unsafe extern "stdcall" fn(*mut RTL_OSVERSIONINFOEXW) -> NTSTATUS, + >(function_address) + }; - let mut version_info: MaybeUninit<RTL_OSVERSIONINFOEXW> = mem::MaybeUninit::zeroed(); - unsafe { - (*version_info.as_mut_ptr()).dwOSVersionInfoSize = - mem::size_of_val(&version_info) as u32; - rtl_get_version(version_info.as_mut_ptr()); + let mut version_info: RTL_OSVERSIONINFOEXW = + // SAFETY: RTL_OSVERSIONINFOEXW is a C struct and can safely be zeroed. + unsafe { MaybeUninit::zeroed().assume_init() }; - Ok(WindowsVersion { - inner: version_info.assume_init(), - }) - } + version_info.dwOSVersionInfoSize = mem::size_of_val(&version_info) as u32; + + // SAFETY: + // - &mut version_info is a valid pointer. + // - rtl_get_version was provided by GetProcAddress and should be valid. + let status = unsafe { rtl_get_version(&mut version_info) }; + debug_assert_eq!( + status, STATUS_SUCCESS, + "RtlGetVersion always returns success" + ); + + Ok(WindowsVersion { + inner: version_info, + }) } pub fn windows_version_string(&self) -> String { diff --git a/talpid-routing/src/unix/macos/data.rs b/talpid-routing/src/unix/macos/data.rs index 5ac83d0885..66644d6ce3 100644 --- a/talpid-routing/src/unix/macos/data.rs +++ b/talpid-routing/src/unix/macos/data.rs @@ -647,7 +647,12 @@ impl Interface { actual_size: buffer.len(), }); } - let header: libc::if_msghdr = unsafe { std::ptr::read(buffer.as_ptr() as *const _) }; + let header = buffer.as_ptr().cast::<libc::if_msghdr>(); + + // SAFETY: + // - `buffer` points to initialized memory of the correct size. + // - if_msghdr is a C struct, and valid for any bit pattern + let header: libc::if_msghdr = unsafe { header.read_unaligned() }; // let payload = buffer[INTERFACE_MESSAGE_HEADER_SIZE..header.ifm_msglen.into()].to_vec(); Ok(Self { header }) } @@ -856,17 +861,17 @@ impl RouteSocketAddress { // The "serialized" socket addresses must be padded to be aligned to 4 bytes, with // the smallest size being 4 bytes. - let buffer_size = len + len % 4; + let buffer_size = len.next_multiple_of(4); let mut buffer = vec![0u8; buffer_size]; + // SAFETY: copying contents of addr into buffer is safe, as long as addr.len() + // returns a correct size for the socket address pointer. unsafe { - // SAFETY: copying conents of addr into buffer is safe, as long as addr.len() - // returns a correct size for the socket address pointer. std::ptr::copy_nonoverlapping( addr.as_ptr() as *const _, buffer.as_mut_ptr(), len, - ); - } + ) + }; buffer } } diff --git a/talpid-routing/src/unix/macos/interface.rs b/talpid-routing/src/unix/macos/interface.rs index 43e30d3549..7de3f84cc5 100644 --- a/talpid-routing/src/unix/macos/interface.rs +++ b/talpid-routing/src/unix/macos/interface.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender}; use ipnetwork::IpNetwork; use nix::{ diff --git a/talpid-routing/src/windows/get_best_default_route.rs b/talpid-routing/src/windows/get_best_default_route.rs index 21dc6edd7b..798bc37285 100644 --- a/talpid-routing/src/windows/get_best_default_route.rs +++ b/talpid-routing/src/windows/get_best_default_route.rs @@ -153,10 +153,12 @@ struct AnnotatedRoute<'a> { } fn annotate_route(route: &MIB_IPFORWARD_ROW2) -> Option<AnnotatedRoute<'_>> { - // SAFETY: `si_family` is valid in both `Ipv4` and `Ipv6` so we can safely access `si_family`. let iface = get_ip_interface_entry( - AddressFamily::try_from_af_family(unsafe { route.DestinationPrefix.Prefix.si_family }) - .ok()?, + AddressFamily::try_from_af_family( + // SAFETY: `si_family` is valid in both `Ipv4` and `Ipv6` so we can safely access `si_family`. + unsafe { route.DestinationPrefix.Prefix.si_family }, + ) + .ok()?, &route.InterfaceLuid, ) .ok()?; diff --git a/talpid-routing/src/windows/route_manager.rs b/talpid-routing/src/windows/route_manager.rs index 86ccff21fa..5cfc4b72e7 100644 --- a/talpid-routing/src/windows/route_manager.rs +++ b/talpid-routing/src/windows/route_manager.rs @@ -600,6 +600,7 @@ fn interface_luid_from_gateway(gateway: &SOCKADDR_INET) -> Result<NET_LUID_LH> { unsafe fn get_first_gateway_address_reference( adapter: &IP_ADAPTER_ADDRESSES_LH, ) -> &IP_ADAPTER_GATEWAY_ADDRESS_LH { + // SAFETY: See function docs unsafe { &*adapter.FirstGatewayAddress } } @@ -611,6 +612,7 @@ fn adapter_interface_enabled( // SAFETY: All fields in the Anonymous2 union are at represented by a u32 so dereferencing // them is safe AF_INET => Ok(0 != unsafe { adapter.Anonymous2.Flags } & IP_ADAPTER_IPV4_ENABLED), + // SAFETY: Same as above. AF_INET6 => Ok(0 != unsafe { adapter.Anonymous2.Flags } & IP_ADAPTER_IPV6_ENABLED), _ => Err(Error::InvalidSiFamily), } @@ -662,6 +664,7 @@ fn equal_address(lhs: &SOCKADDR_INET, rhs: &SOCKET_ADDRESS) -> Result<bool> { return Ok(false); } + // SAFETY: The si_family field is always valid match unsafe { lhs.si_family } { AF_INET => { let typed_rhs = rhs.lpSockaddr as *mut SOCKADDR_IN; diff --git a/talpid-time/Cargo.toml b/talpid-time/Cargo.toml index de5c13ec60..48742abbf3 100644 --- a/talpid-time/Cargo.toml +++ b/talpid-time/Cargo.toml @@ -19,4 +19,4 @@ test = [] tokio = { workspace = true, features = ["time"] } [target.'cfg(unix)'.dependencies] -libc = "0.2" +nix = { version = "0.29", features = ["time"] } diff --git a/talpid-time/src/unix.rs b/talpid-time/src/unix.rs index 5b247b2f5e..a2ea70b0af 100644 --- a/talpid-time/src/unix.rs +++ b/talpid-time/src/unix.rs @@ -1,17 +1,20 @@ -use libc::{c_long, clock_gettime, clockid_t, timespec}; -use std::{mem::MaybeUninit, time::Duration}; +use nix::{ + sys::time::TimeSpec, + time::{clock_gettime, ClockId}, +}; +use std::{ffi::c_long, time::Duration}; const NSEC_PER_SEC: c_long = 1_000_000_000; #[cfg(any(target_os = "macos", target_os = "ios"))] -const CLOCK_ID: clockid_t = libc::CLOCK_MONOTONIC; +const CLOCK_ID: ClockId = ClockId::CLOCK_MONOTONIC; #[cfg(any(target_os = "linux", target_os = "android"))] -const CLOCK_ID: clockid_t = libc::CLOCK_BOOTTIME; +const CLOCK_ID: ClockId = ClockId::CLOCK_BOOTTIME; #[derive(Clone, Copy)] pub struct Instant { - t: timespec, + t: TimeSpec, } impl Instant { @@ -24,15 +27,15 @@ impl Instant { // * `tv_sec >= 0` // * `tv_nsec < NSEC_PER_SEC` - let (tv_sec, tv_nsec) = if self.t.tv_nsec < earlier.t.tv_nsec { + let (tv_sec, tv_nsec) = if self.t.tv_nsec() < earlier.t.tv_nsec() { ( - self.t.tv_sec - earlier.t.tv_sec - 1, - NSEC_PER_SEC - earlier.t.tv_nsec + self.t.tv_nsec, + self.t.tv_sec() - earlier.t.tv_sec() - 1, + NSEC_PER_SEC - earlier.t.tv_nsec() + self.t.tv_nsec(), ) } else { ( - self.t.tv_sec - earlier.t.tv_sec, - self.t.tv_nsec - earlier.t.tv_nsec, + self.t.tv_sec() - earlier.t.tv_sec(), + self.t.tv_nsec() - earlier.t.tv_nsec(), ) }; @@ -49,10 +52,6 @@ impl Instant { } } -fn now() -> timespec { - let mut t = MaybeUninit::zeroed(); - unsafe { - clock_gettime(CLOCK_ID, t.as_mut_ptr()); - t.assume_init() - } +fn now() -> TimeSpec { + clock_gettime(CLOCK_ID).expect("Clock ID is valid") } diff --git a/talpid-tunnel-config-client/src/socket.rs b/talpid-tunnel-config-client/src/socket.rs index f7e48a6f8f..c7709ea9ba 100644 --- a/talpid-tunnel-config-client/src/socket.rs +++ b/talpid-tunnel-config-client/src/socket.rs @@ -16,7 +16,8 @@ mod sys { use super::*; pub use libc::{setsockopt, socklen_t, IPPROTO_TCP, TCP_MAXSEG}; - pub use std::os::fd::{AsRawFd, RawFd}; + use std::ffi::c_int; + pub use std::os::fd::AsRawFd; /// MTU to set on the tunnel config client socket. We want a low value to prevent fragmentation. /// Especially on Android, we've found that the real MTU is often lower than the default MTU, and @@ -33,7 +34,7 @@ mod sys { impl TcpSocket { pub fn new() -> io::Result<Self> { let socket = StdTcpSocket::new_v4()?; - try_set_tcp_sock_mtu(socket.as_raw_fd()); + try_set_tcp_sock_mtu(&socket); Ok(Self { socket }) } @@ -42,13 +43,16 @@ mod sys { } } - fn try_set_tcp_sock_mtu(sock: RawFd) { - let mss = desired_mss(); + fn try_set_tcp_sock_mtu(sock: &impl AsRawFd) { + let mss = c_int::from(desired_mss()); + log::debug!("Tunnel config TCP socket MSS: {mss}"); + // TODO: replace with nix when TcpMaxSeg is added for macos + // SAFETY: `mss` is a valid pointer to a c_int. let result = unsafe { setsockopt( - sock, + sock.as_raw_fd(), IPPROTO_TCP, TCP_MAXSEG, &mss as *const _ as _, @@ -63,11 +67,11 @@ mod sys { } } - const fn desired_mss() -> u32 { + const fn desired_mss() -> u16 { const IPV4_HEADER_SIZE: u16 = 20; const MAX_TCP_HEADER_SIZE: u16 = 60; let mtu = CONFIG_CLIENT_MTU.saturating_sub(IPV4_HEADER_SIZE); - mtu.saturating_sub(MAX_TCP_HEADER_SIZE) as u32 + mtu.saturating_sub(MAX_TCP_HEADER_SIZE) } } diff --git a/talpid-tunnel/src/tun_provider/android/mod.rs b/talpid-tunnel/src/tun_provider/android/mod.rs index d4adc6ba36..7b4b1ae3c3 100644 --- a/talpid-tunnel/src/tun_provider/android/mod.rs +++ b/talpid-tunnel/src/tun_provider/android/mod.rs @@ -102,6 +102,8 @@ impl AndroidTunProvider { pub fn open_tun(&mut self) -> Result<VpnServiceTun, Error> { let config = VpnServiceConfig::new(self.config.clone()); + // i have no idea why this is/isn't safe. + #[allow(clippy::undocumented_unsafe_blocks)] let jvm = unsafe { JavaVM::from_raw(self.jvm.get_java_vm_pointer()) } .map_err(Error::CloneJavaVm)?; @@ -125,6 +127,9 @@ impl AndroidTunProvider { /// Returns an open tunnel with the current configuration pub fn open_tun_forced(&mut self) -> Result<VpnServiceTun, Error> { let config = VpnServiceConfig::new(self.config.clone()); + + // i have no idea why this is/isn't safe. + #[allow(clippy::undocumented_unsafe_blocks)] let jvm = unsafe { JavaVM::from_raw(self.jvm.get_java_vm_pointer()) } .map_err(Error::CloneJavaVm)?; diff --git a/talpid-windows/src/io.rs b/talpid-windows/src/io.rs index 1bcffb30d3..8a8966f620 100644 --- a/talpid-windows/src/io.rs +++ b/talpid-windows/src/io.rs @@ -4,18 +4,22 @@ use windows_sys::Win32::System::IO::OVERLAPPED; use crate::sync::Event; /// Abstraction over `OVERLAPPED`. +/// +/// - https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped +/// - https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventw pub struct Overlapped { overlapped: OVERLAPPED, event: Option<Event>, } +// SAFETY: Both OVERLAPPED and Event is used for async I/O, so this *should* be safe. unsafe impl Send for Overlapped {} -unsafe impl Sync for Overlapped {} impl Overlapped { /// Creates an `OVERLAPPED` object with `hEvent` set. pub fn new(event: Option<Event>) -> io::Result<Self> { let mut overlapped = Overlapped { + // SAFETY: OVERLAPPED is a C struct and can safely be zeroed. overlapped: unsafe { mem::zeroed() }, event: None, }; diff --git a/talpid-windows/src/net.rs b/talpid-windows/src/net.rs index c744114a3a..33c79e1a9d 100644 --- a/talpid-windows/src/net.rs +++ b/talpid-windows/src/net.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use socket2::SockAddr; use std::{ ffi::{OsStr, OsString}, @@ -391,9 +393,7 @@ pub fn luid_from_alias<T: AsRef<OsStr>>(alias: T) -> io::Result<NET_LUID_LH> { /// Returns the alias of an interface given its LUID. pub fn alias_from_luid(luid: &NET_LUID_LH) -> io::Result<OsString> { let mut buffer = [0u16; IF_MAX_STRING_SIZE as usize + 1]; - win32_err!(unsafe { - ConvertInterfaceLuidToAlias(luid, &mut buffer[0] as *mut _, buffer.len()) - })?; + win32_err!(unsafe { ConvertInterfaceLuidToAlias(luid, buffer.as_mut_ptr(), buffer.len()) })?; let nul = buffer.iter().position(|&c| c == 0u16).unwrap(); Ok(OsString::from_wide(&buffer[0..nul])) } @@ -426,6 +426,7 @@ pub fn ipaddr_from_in6addr(addr: IN6_ADDR) -> Ipv6Addr { /// Converts a `SocketAddr` to `SOCKADDR_INET` pub fn inet_sockaddr_from_socketaddr(addr: SocketAddr) -> SOCKADDR_INET { + // SAFETY: SOCKADDR_INET is a union of C structs, these can be safely zeroed. let mut sockaddr: SOCKADDR_INET = unsafe { mem::zeroed() }; match addr { // SAFETY: `*const sockaddr` may be treated as `*const sockaddr_in` since we know it's a v4 @@ -444,6 +445,7 @@ pub fn inet_sockaddr_from_socketaddr(addr: SocketAddr) -> SOCKADDR_INET { /// Converts a `SOCKADDR_INET` to `SocketAddr`. Returns an error if the address family is invalid. pub fn try_socketaddr_from_inet_sockaddr(addr: SOCKADDR_INET) -> Result<SocketAddr> { + // SAFETY: si_family is always valid let family = unsafe { addr.si_family }; unsafe { let mut storage: sockaddr_storage = mem::zeroed(); diff --git a/talpid-windows/src/process.rs b/talpid-windows/src/process.rs index ecddbe09f2..fcf58c9654 100644 --- a/talpid-windows/src/process.rs +++ b/talpid-windows/src/process.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare + use std::{ ffi::{c_char, CStr}, io, mem, diff --git a/talpid-windows/src/sync.rs b/talpid-windows/src/sync.rs index 7b4ed59be3..79a86d6941 100644 --- a/talpid-windows/src/sync.rs +++ b/talpid-windows/src/sync.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use std::{io, ptr}; use windows_sys::Win32::{ Foundation::{CloseHandle, DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, HANDLE}, diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs index 73b22a452f..6e082870f4 100644 --- a/talpid-wireguard/src/wireguard_go/mod.rs +++ b/talpid-wireguard/src/wireguard_go/mod.rs @@ -761,12 +761,16 @@ mod logging { use std::ffi::c_char; // Callback that receives messages from WireGuard + // + // # Safety + // - `msg` must be a valid pointer to a null-terminated UTF-8 string. pub unsafe extern "system" fn wg_go_logging_callback( level: WgLogLevel, msg: *const c_char, context: u64, ) { let managed_msg = if !msg.is_null() { + // SAFETY: caller promises that the pointer is valid. unsafe { std::ffi::CStr::from_ptr(msg).to_string_lossy().to_string() } } else { "Logging message from WireGuard is NULL".to_string() diff --git a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs index ba3bca14be..46a394a59d 100644 --- a/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs +++ b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs @@ -13,6 +13,7 @@ use talpid_dbus::{ WireguardTunnel, }, }; +use talpid_net::unix::iface_index; use talpid_tunnel_config_client::DaitaSettings; #[derive(thiserror::Error, Debug)] @@ -209,30 +210,3 @@ fn convert_config_to_dbus(config: &Config) -> DeviceConfig { settings } - -/// Converts an interface name into the corresponding index. -#[cfg(target_os = "linux")] -fn iface_index(name: &str) -> std::result::Result<libc::c_uint, IfaceIndexLookupError> { - let c_name = std::ffi::CString::new(name) - .map_err(|e| IfaceIndexLookupError::InvalidInterfaceName(name.to_owned(), e))?; - let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) }; - if index == 0 { - Err(IfaceIndexLookupError::InterfaceLookupError( - name.to_owned(), - std::io::Error::last_os_error(), - )) - } else { - Ok(index) - } -} - -/// Failure to lookup an interfaces index by its name. -#[derive(Debug, thiserror::Error)] -pub enum IfaceIndexLookupError { - /// The interface name is invalid - contains null bytes or is too long. - #[error("Invalid network interface name: {0}")] - InvalidInterfaceName(String, #[source] std::ffi::NulError), - /// Interface wasn't found by its name. - #[error("Failed to get index for interface {0}")] - InterfaceLookupError(String, #[source] std::io::Error), -} diff --git a/talpid-wireguard/src/wireguard_kernel/parsers.rs b/talpid-wireguard/src/wireguard_kernel/parsers.rs index 86ecd025b5..a8c16d7d68 100644 --- a/talpid-wireguard/src/wireguard_kernel/parsers.rs +++ b/talpid-wireguard/src/wireguard_kernel/parsers.rs @@ -2,7 +2,7 @@ use byteorder::{ByteOrder, NativeEndian}; use nix::sys::{socket::InetAddr, time::TimeSpec}; use std::{ ffi::{CStr, CString}, - mem, + mem::{self, transmute}, net::IpAddr, }; @@ -36,30 +36,41 @@ pub fn parse_wg_key(buffer: &[u8]) -> Result<[u8; 32], DecodeError> { } pub fn parse_inet_sockaddr(buffer: &[u8]) -> Result<InetAddr, DecodeError> { - if buffer.len() != mem::size_of::<libc::sockaddr_in6>() - && buffer.len() != mem::size_of::<libc::sockaddr_in>() - { - return Err(format!( + let wrong_len = || { + format!( "Unexpected length for sockaddr_in: {}, expected {} or {}", buffer.len(), mem::size_of::<libc::sockaddr_in6>(), mem::size_of::<libc::sockaddr_in>() ) - .into()); - } - let ptr = buffer.as_ptr(); + }; + const AF_INET: u16 = libc::AF_INET as u16; const AF_INET6: u16 = libc::AF_INET6 as u16; + if buffer.len() < size_of::<u16>() { + return Err(wrong_len().into()); + } + match NativeEndian::read_u16(buffer) { - AF_INET => unsafe { - let sockaddr: *const libc::sockaddr_in = ptr as *const _; - Ok(InetAddr::V4(*sockaddr)) - }, - AF_INET6 => unsafe { - let sockaddr: *const libc::sockaddr_in6 = ptr as *const _; - Ok(InetAddr::V6(*sockaddr)) - }, + AF_INET => { + let buffer: &[u8; size_of::<libc::sockaddr_in>()] = + buffer.try_into().map_err(|_| wrong_len())?; + + // SAFETY: sockaddr_in has a defined repr(C) layout and is valid for all bit patterns + let sockaddr: libc::sockaddr_in = unsafe { transmute(*buffer) }; + + Ok(InetAddr::V4(sockaddr)) + } + AF_INET6 => { + let buffer: &[u8; size_of::<libc::sockaddr_in6>()] = + buffer.try_into().map_err(|_| wrong_len())?; + + // SAFETY: sockaddr_in6 has a defined repr(C) layout and is valid for all bit patterns + let sockaddr: libc::sockaddr_in6 = unsafe { transmute(*buffer) }; + + Ok(InetAddr::V6(sockaddr)) + } unexpected_addr_family => { Err(format!("Unexpected address family: {unexpected_addr_family}").into()) } diff --git a/talpid-wireguard/src/wireguard_kernel/wg_message.rs b/talpid-wireguard/src/wireguard_kernel/wg_message.rs index 14ab31ee76..9c299b4a04 100644 --- a/talpid-wireguard/src/wireguard_kernel/wg_message.rs +++ b/talpid-wireguard/src/wireguard_kernel/wg_message.rs @@ -386,14 +386,14 @@ impl Nla for PeerNla { Flags(value) | ProtocolVersion(value) => NativeEndian::write_u32(buffer, *value), Endpoint(endpoint) => match &endpoint { InetAddr::V4(sockaddr_in) => { - // SAFETY: `sockaddr_in` has no padding bytes buffer + // SAFETY: `sockaddr_in` has no padding bytes .write_all(unsafe { struct_as_slice(sockaddr_in) }) .expect("Buffer too small for sockaddr_in"); } InetAddr::V6(sockaddr_in6) => { - // SAFETY: `sockaddr_in` has no padding bytes buffer + // SAFETY: `sockaddr_in` has no padding bytes .write_all(unsafe { struct_as_slice(sockaddr_in6) }) .expect("Buffer too small for sockaddr_in6"); } @@ -403,8 +403,8 @@ impl Nla for PeerNla { } LastHandshakeTime(last_handshake) => { let timespec: &libc::timespec = last_handshake.as_ref(); - // SAFETY: `timespec` has no padding bytes buffer + // SAFETY: `timespec` has no padding bytes .write_all(unsafe { struct_as_slice(timespec) }) .expect("Buffer too small for timespec"); } diff --git a/talpid-wireguard/src/wireguard_nt/mod.rs b/talpid-wireguard/src/wireguard_nt/mod.rs index 4451f36281..ff5b082490 100644 --- a/talpid-wireguard/src/wireguard_nt/mod.rs +++ b/talpid-wireguard/src/wireguard_nt/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::undocumented_unsafe_blocks)] // Remove me if you dare. + use super::{ config::Config, logging, diff --git a/test/Cargo.lock b/test/Cargo.lock index 897e6c9645..e25c4d94d7 100644 --- a/test/Cargo.lock +++ b/test/Cargo.lock @@ -3478,7 +3478,7 @@ dependencies = [ name = "talpid-time" version = "0.0.0" dependencies = [ - "libc", + "nix 0.29.0", "tokio", ] diff --git a/windows-installer/src/main.rs b/windows-installer/src/main.rs index 64e70c282d..62f80ee024 100644 --- a/windows-installer/src/main.rs +++ b/windows-installer/src/main.rs @@ -1,5 +1,4 @@ #![windows_subsystem = "windows"] -#![warn(clippy::undocumented_unsafe_blocks)] #[cfg(target_os = "windows")] #[path = "windows.rs"] |
