This review is from Crev, a distributed system for code reviews. To add your review, set up cargo-crev.

0.5.0 (current) Rating: Positive Thoroughness: Medium Understanding: Medium

by gitlab.com/phgsng on 2019-10-04

Disclaimer: as far as syscall usage is concerned, this review considers only the behavior on Linux.

Cons

  • “unsafe”, “unsafe” everywhere; 32× as of version 0.5.0. Not really avoidable when working closely with C APIs though.
  • C APIs can still be handled incorrectly in the public API, e. g. calling shutdown() twice on one socket. The result is handled safely though even under programmer errors.
  • As of 2019 the code is a bit stale, e. g. it uses the soon to be deprecatedtry!() and thus may not build with a future version of Rust.

Pros

  • Excellent API documentation.
  • Minimal dependencies (libc, cfg-if).
  • Use of unsafe is never gratuitous.
  • Public API exposes safe interfaces that ensure correctness on the type level.
  • Thoroughly unit-tested (all tests ok).

lib.rs

general considerations

    • Unix syscalls are handled using two wrappers that convert return values to io::Result.
    • Most uses of unsafe use safe lower level constructs.

unsafe code

There is only one source file, lib.rs, so all uses of “unsafe” are found there.

    • fn sun_path_offset(): calculates the offset of a struct member using pointer arithmetic. Circumnavigates possible UB (cf. https://internals.rust-lang.org/t/9273/127). offsetof() is still an unsolved problem in Rust.
    • impl Drop for Inner: obligatory dtor.
    • fn Inner::new(): wraps socket(2); return value handled ok.
    • fn Inner::new_pair(): wraps socketpair(2); return value handled ok; out parameter handled correctly.
    • fn Inter::try_clone(): wraps dup(2); return value handled ok.
    • fn Inner::shutdown(): wraps shutdown(2); return value handled ok; API safe by accepting an enum wrapper over the int how argument.
    • fn Inner::timeout(): wraps getsockopt(2); return value handled ok; out parameter (struct timeval) handled ok.
    • fn Inner::set_timeout(): wraps setsockopt(2); return value handled ok; correct input validation, catching out of range values for time_t argument using saturating arithmetic.
  • ± fn Inner::set_nonblocking(): wraps ioctl(2) with FIONBIO; return value handled ok. Why not use fcntl(2) with O_NONBLOCK instead? Probably to save one syscall? This warrants an explantory comment.

    • fn Inner::take_error(): wraps getsockopt(2); return value handled ok; out parameter ok.
    • unsafe fn sockaddr_un(): initializes a struct sockaddr_un; inputs validated appropriately; raw pointer access provably within bounds.
    • fn SocketAddr::new(): obtains a socket address; for use with getpeername() / getsockname() etc.; return value handled ok (assuming the passed function returns the syscall return value).
    • fn SocketAddr::address(): casts memory of a wrapped type from [char] to [u8]; array bounds are preserved thus subsequent accesses return slices with valid bounds.
    • fn UnixStream::connect()`: public API wrapping socket creation and connect(2)``; arguments obtained from internal APIs deemed safe; return value handled ok.
    • fn UnixStream::local_addr()`: wraps getsockname(2); return value and arguments handled by SocketAddr::new()``.
    • fn UnixStream::peer_addr()`: wraps getpeername(2); return value and arguments handled by SocketAddr::new()``.
    • impl Read for UnixStream, fn read(): wraps recv(2); return value handled ok; argument values obtained from safe rust type.
    • impl Write for UnixStream, fn write(): wraps send(2); return value handled ok; argument values obtained from safe rust type.
    • impl FromRawFd for UnixStream, fn from_raw_fd(): unsafe trait; constructs a UnixStream without validating the arugment.
  • ± fn UnixListener::bind(): wraps socket creation, bind(2) and listen(2; return values handled ok; backlog of socket queue hard-coded to the default Linux maximum of 128 which is reasonable but deserves mention in the docs.

    • fn UnixListener::accept(): wrapper for accept(2); return value and argument checks deferred to SocketAddr::new().
    • fn UnixListener::local_addr(): wrapper for getsockname(2); return value and arguments handled by SocketAddr::new().
    • impl FromRawFd for UnixListener, fn from_raw_fd(): unsafe trait, constructs UnixListener without validating anything.
    • fn UnixDatagram::bind(): wraps bind(2) for SOCK_DGRAM type sockets; return value handled ok; args obtained from safe wrappers.
    • fn UnixDatagram::connect(): wraps connect(2); return value handled ok; args obtained from safe wrappers.
    • fn UnixDatagram::local_addr()`: wraps getsockname(2); return value and arguments handled by SocketAddr::new()``.
    • fn UnixDatagram::peer_addr()`: wraps getpeername(2); return value and arguments handled by SocketAddr::new()``.
    • fn UnixDatagram::recv_from()`: wraps recvfrom(2)``; return value handled ok; args obtained from safe wrappers.
    • fn UnixDatagram::recv()`: wraps recv(2)``; args obtained from safe types; return value handled ok.
    • fn UnixDatagram::send_to()`: wraps send_to(2)``; args obtained from safe types; return value handled ok.
    • fn UnixDatagram::send()`: wraps send_to(2)``; args obtained from safe types; return value handled ok.
    • impl FromRawFd for UnixDatagram, fn from_raw_fd(): unsafe trait, constructs UnixDatagram without validating anything.

This review is from cargo-vet. To add your review, set up cargo-vet and submit your URL to its registry.

cargo-vet does not verify reviewers' identity. You have to fully trust the source the audits are from.

unknown

May have been packaged automatically without a review


Crates in the crates.io registry are tarball snapshots uploaded by crates' publishers. The registry is not using crates' git repositories. There is absolutely no guarantee that the repository URL declared by the crate belongs to the crate, or that the code in the repository is the code inside the published tarball.

To review the actual code of the crate, it's best to use cargo crev open unix_socket. Alternatively, you can download the tarball of unix_socket v0.5.0 or view the source online.