diff --git a/CHANGELOG.md b/CHANGELOG.md index f09b4bed34..8f906b6b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `nix::sys::uio::{process_vm_readv, process_vm_writev}` on Linux ([#568](https://github.com/nix-rust/nix/pull/568)) - Added `nix::unistd::{getgroups, setgroups, getgrouplist, initgroups}`. ([#733](https://github.com/nix-rust/nix/pull/733)) +- Added `nix::sys::socket::UnixAddr::as_abstract` on Linux and Android. + ([#785](https://github.com/nix-rust/nix/pull/785)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) @@ -69,6 +71,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly. ([#749](https://github.com/nix-rust/nix/pull/749)) - `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715)) +- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux and Android only. + ([#785](https://github.com/nix-rust/nix/pull/785)) + ### Fixed - Fix compilation and tests for OpenBSD targets diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index d57207ed50..29832b3700 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -521,7 +521,9 @@ impl fmt::Display for Ipv6Addr { * */ -/// A wrapper around `sockaddr_un`. We track the length of `sun_path` (excluding +/// A wrapper around `sockaddr_un`. +/// +/// This also tracks the length of `sun_path` address (excluding /// a terminating null), because it may not be null-terminated. For example, /// unconnected and Linux abstract sockets are never null-terminated, and POSIX /// does not require that `sun_len` include the terminating null even for normal @@ -555,10 +557,13 @@ impl UnixAddr { })) } - /// Create a new sockaddr_un representing an address in the - /// "abstract namespace". This is a Linux-specific extension, - /// primarily used to allow chrooted processes to communicate with - /// specific daemons. + /// Create a new `sockaddr_un` representing an address in the "abstract namespace". + /// + /// The leading null byte for the abstract namespace is automatically added; + /// thus the input `path` is expected to be the bare name, not null-prefixed. + /// This is a Linux-specific extension, primarily used to allow chrooted + /// processes to communicate with processes having a different filesystem view. + #[cfg(any(target_os = "android", target_os = "linux"))] pub fn new_abstract(path: &[u8]) -> Result { unsafe { let mut ret = libc::sockaddr_un { @@ -587,7 +592,7 @@ impl UnixAddr { /// If this address represents a filesystem path, return that path. pub fn path(&self) -> Option<&Path> { if self.1 == 0 || self.0.sun_path[0] == 0 { - // unbound or abstract + // unnamed or abstract None } else { let p = self.sun_path(); @@ -600,6 +605,20 @@ impl UnixAddr { Some(Path::new(::from_bytes(&p[..reallen]))) } } + + /// If this address represents an abstract socket, return its name. + /// + /// For abstract sockets only the bare name is returned, without the + /// leading null byte. `None` is returned for unnamed or path-backed sockets. + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn as_abstract(&self) -> Option<&[u8]> { + if self.1 >= 1 && self.0.sun_path[0] == 0 { + Some(&self.sun_path()[1..]) + } else { + // unnamed or filesystem path + None + } + } } impl PartialEq for UnixAddr { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 5f9c6fff07..b3d983d3d3 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -64,6 +64,28 @@ pub fn test_path_to_sock_addr() { assert_eq!(addr.path(), Some(actual)); } +// Test getting/setting abstract addresses (without unix socket creation) +#[cfg(target_os = "linux")] +#[test] +pub fn test_abstract_uds_addr() { + let empty = String::new(); + let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); + assert_eq!(addr.as_abstract(), Some(empty.as_bytes())); + + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + assert_eq!(addr.as_abstract(), Some(name.as_bytes())); + assert_eq!(addr.path(), None); + + // Internally, name is null-prefixed (abstract namespace) + let internal: &[u8] = unsafe { + slice::from_raw_parts(addr.0.sun_path.as_ptr() as *const u8, addr.1) + }; + let mut abstract_name = name.clone(); + abstract_name.insert(0, '\0'); + assert_eq!(internal, abstract_name.as_bytes()); +} + #[test] pub fn test_getsockname() { use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};