-
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_atandopen_by_handle_atsystem 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.