call_end

    • Pl chevron_right

      Sebastian Wick: Three Little Rust Crates

      news.movim.eu / PlanetGnome • 0:15 • 2 minutes

    I published three Rust crates:

    • name-to-handle-at : Safe, low-level Rust bindings for Linux name_to_handle_at and open_by_handle_at system calls
    • pidfd-util : Safe Rust wrapper for Linux process file descriptors (pidfd)
    • listen-fds : A Rust library for handling systemd socket activation

    They might seem like rather arbitrary, unconnected things – but there is a connection!

    systemd socket activation passes file descriptors and a bit of metadata as environment variables to the activated process. If the activated process exec’s another program, the file descriptors get passed along because they are not CLOEXEC . If that process then picks them up, things could go very wrong. So, the activated process is supposed to mark the file descriptors CLOEXEC , and unset the socket activation environment variables. If a process doesn’t do this for whatever reason however, the same problems can arise. So there is another mechanism to help prevent it: another bit of metadata contains the PID of the target. Processes can check it against their own PID to figure out if they were the target of the activation, without having to depend on all other processes doing the right thing.

    PIDs however are racy because they wrap around pretty fast, and that’s why nowadays we have pidfds. They are file descriptors which act as a stable handle to a process and avoid the ID wrap-around issue. Socket activation with systemd nowadays also passes a pidfd ID. A pidfd ID however is not the same as a pidfd file descriptor! It is the 64 bit inode of the pidfd file descriptor on the pidfd filesystem. This has the advantage that systemd doesn’t have to install another file descriptor in the target process which might not get closed. It can just put the pidfd ID number into the $LISTEN_PIDFDID environment variable.

    Getting the inode of a file descriptor doesn’t sound hard. fstat(2) fills out struct stat which has the st_ino field. The problem is that it has a type of ino_t , which is 32 bits on some systems so we might end up with a process identifier which wraps around pretty fast again.

    We can however use the name_to_handle syscall on the pidfd to get a struct file_handle with a f_handle field. The man page helpfully says that “the caller should treat the file_handle structure as an opaque data type”. We’re going to ignore that, though, because at least on the pidfd filesystem, the first 64 bits are the 64 bit inode. With systemd already depending on this and the kernel rule of “don’t break user-space”, this is now API, no matter what the man page tells you.

    So there you have it. It’s all connected.

    Obviously both pidfds and name_to_handle have more exciting uses, many of which serve my broader goal: making Varlink services a first-class citizen. More about that another time.