Skip to content

wasmtime serve: Allow inheriting sockets from system manager - #14294

Open
simolus3 wants to merge 5 commits into
bytecodealliance:mainfrom
simolus3:serve-listenfds
Open

wasmtime serve: Allow inheriting sockets from system manager#14294
simolus3 wants to merge 5 commits into
bytecodealliance:mainfrom
simolus3:serve-listenfds

Conversation

@simolus3

@simolus3 simolus3 commented Sep 7, 2026

Copy link
Copy Markdown

This adds the --listenfd option to wasmtime serve. When it's enabled and wasmtime is 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: The wasmtime process 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 --listenfd

This also removes the old -S listenfd option: The only place using that option was a check that errors when it's set.

Closes #14289. As suggested in that thread, I've also linked the used systemd protocol for this in a comment.

@simolus3
simolus3 requested review from a team as code owners September 7, 2026 20:56
@simolus3
simolus3 requested review from alexcrichton and pchickey and removed request for a team September 7, 2026 20:56
Comment thread src/commands/serve.rs
Comment thread src/commands/serve.rs Outdated
@github-actions github-actions Bot added the wasmtime:docs Issues related to Wasmtime's documentation label Sep 7, 2026
Comment thread src/commands/serve.rs Outdated
Comment thread src/commands/serve.rs Outdated
Comment thread src/commands/serve.rs

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I've got some suggestions to use rustix instead of libc since 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 in serve.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.

Comment thread src/inherited_fd.rs
let fd = unsafe {
// Safety: This is called first in main and we checked the PID, so we have exclusive
// access to this fd.
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use rustix::io::fcntl_setfd with error handling?

Comment thread src/inherited_fd.rs

fn is_tcp_socket(fd: &OwnedFd) -> bool {
let mut stat: MaybeUninit<libc::stat> = MaybeUninit::uninit();
if unsafe { libc::fstat(fd.as_raw_fd(), stat.as_mut_ptr()) } != 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use rustix::fs::fstat for safe bindings?

Comment thread src/inherited_fd.rs
Comment on lines +90 to +98
let sa_family = unsafe {
let mut sockaddr: MaybeUninit<libc::sockaddr> = MaybeUninit::uninit();
let mut len = mem::size_of::<libc::sockaddr>() as libc::c_uint;

if libc::getsockname(fd.as_raw_fd(), sockaddr.as_mut_ptr(), &mut len) != 0 {
return false;
}
sockaddr.assume_init().sa_family
} as libc::c_int;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use rustix::net::getsockname for a safe alternative?

Comment thread src/inherited_fd.rs
Comment on lines +104 to +120
let mut socket_type: libc::c_int = 0;
unsafe {
let mut type_len = mem::size_of_val(&socket_type) as libc::c_uint;

if libc::getsockopt(
fd.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_TYPE,
std::ptr::from_mut(&mut socket_type).cast(),
&mut type_len,
) != 0
{
return false;
}
}

socket_type == libc::SOCK_STREAM

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use rustix::net::sockopt::socket_type for a safe alternative?

Comment thread src/bin/wasmtime.rs

#[allow(unreachable_code, reason = "empty enum with all features disabled")]
fn main() -> Result<()> {
setup();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I would prefer to keep all the serve.rs-related code in serve.rs and avoid extra abstractions here (which have more #[cfg] which is more to validate, etc). I think it'd be fine to have init_inherited_fds marked unsafe, that returns the inherited sockets, and the // SAFETY ... comment on the call in serve.rs is 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:docs Issues related to Wasmtime's documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restore listenfd suport for wasmtime serve

3 participants