simolus3 opened PR #14294 from simolus3:serve-listenfds to bytecodealliance:main:
This adds the
--listenfdoption towasmtime serve. When it's enabled andwasmtimeis launched from a systemd socket unit, we use the socket created by systemd instead of creating a new one. The main benefit of this is efficiency: Thewasmtimeprocess is only started when the first client connects. Additionally, this allows sandboxing the process in a private network namespace (since the only socket it will use is inherited).To test this, the systemfd utility may be convenient:
systemfd -s http::5000 -- cargo run -- serve file.wasm --listenfdThis also removes the old
-S listenfdoption: The only place using that option was a check that errors when it's set.Closes https://github.com/bytecodealliance/wasmtime/issues/14289. As suggested in that thread, I've also linked the used systemd protocol for this in a comment.
simolus3 requested pchickey for a review on PR #14294.
simolus3 requested wasmtime-core-reviewers for a review on PR #14294.
simolus3 requested alexcrichton for a review on PR #14294.
simolus3 requested wasmtime-default-reviewers for a review on PR #14294.
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
Would it make sense to emit an explicit error outside Unix rather than treat it as non-existent flag?
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
This should probably be called at the start of main to ensure no other fd takes the place of a missing fd, violating I/O-safety.
github-actions[bot] added the label wasmtime:docs on PR #14294.
simolus3 updated PR #14294.
:memo: simolus3 submitted PR review.
:speech_balloon: simolus3 created PR review comment:
I've changed that now to be called at the beginning of the command, but it's somewhat ugly.
What is this supposed to defend against, someone passing the
LISTEN_FDSenvironment variable but no file descriptors? We only considerAF_INETsockets and this runs before the components so I don't see how we could confuse this with another fd.
:memo: alexcrichton submitted PR review.
:speech_balloon: alexcrichton created PR review comment:
The implementation in this crate looks pretty thin -- would it be possible to vendor the implementation here? Given that this is in theory a protocol set by someone else it seems like it shouldn't be changing all that much.
:speech_balloon: alexcrichton created PR review comment:
This looks like it's a man page for a function in a library somewhere, but do you know if there's documentation on what systemd does beyond this manpage? I'm not sure where this function lives, for example, and whether it's expected to link against this C library and this C library only to do things. Glancing at the
listenfdcrate it's not processing all the env vars that this function seems to document, so I'm not sure of the discrepancy there.
:speech_balloon: alexcrichton created PR review comment:
Should this perhaps be named something like
systemd_listenfd? This seems specific to systemd itself and a bland name like--listenfdsounds like it's a more general option. Do you know if there happens to be a convention about how this is handled by other tools?
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
This function is in libsystemd. I seem to recall that at some point the systemd docs actually contained a standalone C implementation to copy into programs that otherwise don't depend on libsystemd, so it is definitively intended for this interface to be usable without libsystemd.
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
There is nothing intrinsically tying listenfd to systemd. The systemfd util implements the same interface and there is no reason other init systems can't implement it either.
:memo: simolus3 submitted PR review.
:speech_balloon: simolus3 created PR review comment:
Apologies, I was not familiar with the concept of IO safety. I'll find a way to call this first thing in
main().
:memo: alexcrichton submitted PR review.
:speech_balloon: alexcrichton created PR review comment:
Personally I wouldn't sweat this too much. I don't think it's worth contorting Wasmtime's CLI to make it apparent that this is happening right as
fn mainstarts -- Wasmtime controls all the CLI entrypoints anyway. Where it currently is looks fine to me, and it's all during startup/CLI processing anyway so anywhere around there is fine.
:memo: alexcrichton submitted PR review.
:speech_balloon: alexcrichton created PR review comment:
This might then tie into my above question -- if the only documentation for this functionality is a man page for a function in
libsystemdthat doesn't sound like a generally reusable primitive, but if there's some documentation which is more general I think that would be good to have as a case for not naming this systemd-specific.
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
Before the portability page of systemd got changed to just list a general policy, it explicitly listed
LISTEN_FDSas being a stable interface that is reimplementable independently of systemd: https://github.com/systemd/systemd/blob/0c40aef7ef1419233826b6fb7ccac12f7623033b/docs/PORTABILITY_AND_STABILITY.mdFWIW this is not the only generally reusable interface that is effectively only documented in the systemd man pages. Another example is
/etc/os-release(replacement for/etc/lsb-releaseand distro specific files like/etc/debian_version), or/etc/machine-id(normally has the same value as/var/lib/dbus/machine-id). The "Boot Loader Specification" also originates from systemd, but nowadays Grub and Limine also supports it, not just sd-boot (this one has a specification at https://uapi-group.org/specifications/specs/boot_loader_specification/ though).
simolus3 updated PR #14294.
:memo: simolus3 submitted PR review.
:speech_balloon: simolus3 created PR review comment:
I've vendored the implementation. I've also taken inspiration from command-fds and @bjorn3's suggestion to call this as early as possible.
:memo: simolus3 submitted PR review.
:speech_balloon: simolus3 created PR review comment:
The man page describes the protocol, in the "Notes" section:
Internally, sd_listen_fds() checks whether the $LISTEN_PID environment variable equals the daemon PID. If not, it returns immediately. [...] It parses the number passed in the $LISTEN_FDS environment variable, then sets the FD_CLOEXEC flag for the parsed number of file descriptors starting from SD_LISTEN_FDS_START. Finally, it returns the parsed number.
simolus3 updated PR #14294.
:memo: alexcrichton submitted PR review:
Thanks! I've got some suggestions to use
rustixinstead oflibcsince that helps us with more typesafe/safe wrappers, and I've additionally put a comment about moving the handshake-style protocol to just one function called inserve.rs. Otherwise looks reasonable to me.Also, sorry I forgot this earlier, but can you add a test for this as well? It's difficult to keep functionality like this working if it doesn't have any tests.
:speech_balloon: alexcrichton created PR review comment:
Could this use
rustix::io::fcntl_setfdwith error handling?
:speech_balloon: alexcrichton created PR review comment:
Could this use
rustix::fs::fstatfor safe bindings?
:speech_balloon: alexcrichton created PR review comment:
Could this use
rustix::net::sockopt::socket_typefor a safe alternative?
:speech_balloon: alexcrichton created PR review comment:
Could this use
rustix::net::getsocknamefor a safe alternative?
:speech_balloon: alexcrichton created PR review comment:
Personally I would prefer to keep all the
serve.rs-related code inserve.rsand avoid extra abstractions here (which have more #[cfg] which is more to validate, etc). I think it'd be fine to haveinit_inherited_fdsmarkedunsafe, that returns the inherited sockets, and the// SAFETY ...comment on the call inserve.rsis high enough in the function that it's clear that nothing happens inbetween. That should keep everything contained without the need for more #[cfg] without compromising on safety.
simolus3 updated PR #14294.
simolus3 updated PR #14294.
:memo: alexcrichton submitted PR review:
One question about returning an error if multiple sockets are inherited, but @simolus3 what do you think about calling this option
--systemd-listenfdvs--listenfd?
:speech_balloon: alexcrichton created PR review comment:
Could this use the
send_requestfunction? Otherwise this looks like a bit of duplication with what that's doing.
:speech_balloon: alexcrichton created PR review comment:
Should this perhaps return an error if therea re multiple TCP sockets listed? Because otherwise using the first feels like it might lead to odd behavior if that happens to be the wrong one
simolus3 updated PR #14294.
:memo: simolus3 submitted PR review.
:speech_balloon: simolus3 created PR review comment:
I've made that an error. I have also changed the function to error if no socket is passed at all, since it might be surprising to explicitly indicate that inherited sockets are requested with
--systemd-listenfdonly to then have wasmtime listen itself because of a mismatched environment variable that's ignored.
:speech_balloon: simolus3 edited PR review comment.
:thumbs_up: alexcrichton submitted PR review.
alexcrichton added PR #14294 wasmtime serve: Allow inheriting sockets from system manager to the merge queue.
github-merge-queue[bot] removed PR #14294 wasmtime serve: Allow inheriting sockets from system manager from the merge queue.
alexcrichton commented on PR #14294:
Ah the failure in CI is on a target where we're cross-compiling and running tests in QEMU. The best fix is to probably look at
wasmtime_test_util::cargo_test_runner()and if that'sSomethen to just skip this test
simolus3 updated PR #14294.
simolus3 edited PR #14294:
This adds the
--systemd-listenfdoption towasmtime serve. When it's enabled andwasmtimeis launched from a systemd socket unit, we use the socket created by systemd instead of creating a new one. The main benefit of this is efficiency: Thewasmtimeprocess is only started when the first client connects. Additionally, this allows sandboxing the process in a private network namespace (since the only socket it will use is inherited).To test this, the systemfd utility may be convenient:
systemfd -s http::5000 -- cargo run -- serve file.wasm --systemd-listenfdThis also removes the old
-S listenfdoption: The only place using that option was a check that errors when it's set.Closes https://github.com/bytecodealliance/wasmtime/issues/14289. As suggested in that thread, I've also linked the used systemd protocol for this in a comment.
simolus3 commented on PR #14294:
Done!
alexcrichton added PR #14294 wasmtime serve: Allow inheriting sockets from system manager to the merge queue.
:check: alexcrichton merged PR #14294.
alexcrichton removed PR #14294 wasmtime serve: Allow inheriting sockets from system manager from the merge queue.
Last updated: Sep 20 2026 at 18:08 UTC