Skip to content

Commit b54c9a4

Browse files
committed
sys/socket: add UnixAddr abstract name getter
This introduces an `as_abstract()` getter to `UnixAddr` in order to retrieve the name of an abstract unix socket. This also adds tests around abstract addresses and clarify docs, adding explicit semantics.
1 parent 1b9d205 commit b54c9a4

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
3636
([#768](https:://github.com/nix-rust/nix/pull/768))
3737
- Added `nix::unistd::mkfifo`.
3838
([#602](https://github.com/nix-rust/nix/pull/774))
39+
- Added `nix::sys::socket::UnixAddr::as_abstract` for Linux.
40+
([#785](https://github.com/nix-rust/nix/pull/785))
3941

4042
### Changed
4143
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
@@ -64,6 +66,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
6466
- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly.
6567
([#749](https://github.com/nix-rust/nix/pull/749))
6668
- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715))
69+
- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux only.
70+
([#785](https://github.com/nix-rust/nix/pull/785))
71+
6772

6873
### Fixed
6974
- Fix compilation and tests for OpenBSD targets

src/sys/socket/addr.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,9 @@ impl fmt::Display for Ipv6Addr {
521521
*
522522
*/
523523

524-
/// A wrapper around `sockaddr_un`. We track the length of `sun_path` (excluding
524+
/// A wrapper around `sockaddr_un`.
525+
///
526+
/// This also tracks the length of `sun_path` address (excluding
525527
/// a terminating null), because it may not be null-terminated. For example,
526528
/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
527529
/// does not require that `sun_len` include the terminating null even for normal
@@ -555,10 +557,13 @@ impl UnixAddr {
555557
}))
556558
}
557559

558-
/// Create a new sockaddr_un representing an address in the
559-
/// "abstract namespace". This is a Linux-specific extension,
560-
/// primarily used to allow chrooted processes to communicate with
561-
/// specific daemons.
560+
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
561+
///
562+
/// The leading null byte for the abstract namespace is automatically added;
563+
/// thus the input `path` is expected to be the bare name, not null-prefixed.
564+
/// This is a Linux-specific extension, primarily used to allow chrooted
565+
/// processes to communicate with processes having a different filesystem view.
566+
#[cfg(target_os = "linux")]
562567
pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
563568
unsafe {
564569
let mut ret = libc::sockaddr_un {
@@ -587,7 +592,7 @@ impl UnixAddr {
587592
/// If this address represents a filesystem path, return that path.
588593
pub fn path(&self) -> Option<&Path> {
589594
if self.1 == 0 || self.0.sun_path[0] == 0 {
590-
// unbound or abstract
595+
// unnamed or abstract
591596
None
592597
} else {
593598
let p = self.sun_path();
@@ -600,6 +605,20 @@ impl UnixAddr {
600605
Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
601606
}
602607
}
608+
609+
/// If this address represents an abstract socket, return its name.
610+
///
611+
/// For abstract sockets only the bare name is returned, without the
612+
/// leading null byte. `None` is returned for unnamed or path-backed sockets.
613+
#[cfg(target_os = "linux")]
614+
pub fn as_abstract(&self) -> Option<&[u8]> {
615+
if self.1 >= 1 && self.0.sun_path[0] == 0 {
616+
Some(&self.sun_path()[1..])
617+
} else {
618+
// unnamed or filesystem path
619+
None
620+
}
621+
}
603622
}
604623

605624
impl PartialEq for UnixAddr {

test/sys/test_socket.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,28 @@ pub fn test_path_to_sock_addr() {
6464
assert_eq!(addr.path(), Some(actual));
6565
}
6666

67+
// Test getting/setting abstract addresses (without unix socket creation)
68+
#[cfg(target_os = "linux")]
69+
#[test]
70+
pub fn test_abstract_uds_addr() {
71+
let empty = String::new();
72+
let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
73+
assert_eq!(addr.as_abstract(), Some(empty.as_bytes()));
74+
75+
let name = String::from("nix\0abstract\0test");
76+
let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
77+
assert_eq!(addr.as_abstract(), Some(name.as_bytes()));
78+
assert_eq!(addr.path(), None);
79+
80+
// Internally, name is null-prefixed (abstract namespace)
81+
let internal: &[u8] = unsafe {
82+
slice::from_raw_parts(addr.0.sun_path.as_ptr() as *const u8, addr.1)
83+
};
84+
let mut abstract_name = name.clone();
85+
abstract_name.insert(0, '\0');
86+
assert_eq!(internal, abstract_name.as_bytes());
87+
}
88+
6789
#[test]
6890
pub fn test_getsockname() {
6991
use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};

0 commit comments

Comments
 (0)