nix icon indicating copy to clipboard operation
nix copied to clipboard

No longer able to create an unnamed `UnixAddr` as of nix 23.0

Open stevenengler opened this issue 4 years ago • 5 comments
trafficstars

It seems that the UnixAddr type no longer provides a way to generate an unnamed unix address (a unix address with an addrlen of 2, or UnixAddrKind::Unnamed). This used to be possible in nix 22.0 when the internal struct fields were public.

stevenengler avatar Oct 27 '21 21:10 stevenengler

Do you mean an abstract socket? What about https://docs.rs/nix/0.23.0/nix/sys/socket/struct.UnixAddr.html#method.new_abstract ?

asomers avatar Oct 27 '21 22:10 asomers

No, an abstract socket implies that it is bound in the abstract namespace, and has a length >= 3. The new_abstract method always adds at least one empty byte to the address name, so new_abstract(&[]) returns an address with a length of 3. An unnamed unix socket is not bound to any address and should have a length of 2 for the 2 bytes of the u16 address family.

unix(7) can probably explain it better than me:

unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name. Likewise, the two sockets created by socketpair(2) are unnamed. When the address of an unnamed socket is returned, its length is sizeof(sa_family_t), and sun_path should not be inspected.

stevenengler avatar Oct 27 '21 22:10 stevenengler

Ok, I get it. And what do you normally do with unnamed UnixAddrs?

asomers avatar Oct 27 '21 22:10 asomers

We have code that intercepts syscalls, so we need to work with libc::sockaddr types. Within the internals of our application, it's nice to convert these to nix SockAddr types to work with them, and then convert them back to libc::sockaddr types when needed. For example when we intercept socketpair(), we create a custom socket object within our application and set its socket address to a nix UnixAddr which represents an unnamed unix socket, so that later if we intercept getsockname(), we can convert that UnixAddr to a libc::sockaddr using SockAddr::as_ffi_pair() and return it as the result to getsockname(). Calling getsockname() on an unnamed unix socket should return an addrlen of 2, so if UnixSocket supported unnamed sockets, SockAddr::as_ffi_pair() would return an addrlen of 2 and everything would work seamlessly.

Edit: A simpler example, an unnamed socket address can also be passed to bind() to auto-bind the socket to an abstract address.

For a unix socket:

If a bind(2) call specifies addrlen as sizeof(sa_family_t), or the SO_PASSCRED socket option was specified for a socket that was not explicitly bound to an address, then the socket is autobound to an abstract address.

stevenengler avatar Oct 27 '21 22:10 stevenengler

I think maybe this could be implemented with something like:

impl UnixAddr {
    pub fn new_unnamed() -> Result<UnixAddr> {
        unsafe {
            let mut ret = libc::sockaddr_un {
                sun_family: AddressFamily::Unix as sa_family_t,
                .. mem::zeroed()
            };

            Ok(UnixAddr::from_raw_parts(ret, 2))
        }
    }
}

If you're interested in a PR, let me know. But from #1544 it looks like you might be rewriting the SockAddr code anyways.

stevenengler avatar Oct 27 '21 22:10 stevenengler