From e18a762a1c892f0b5f0730b7e4672691be17fcdc Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Tue, 18 Nov 2025 10:19:54 +0100 Subject: [PATCH 1/2] handlers: add new hook to close fds Some handlers may need to preserve more fds than those related to stdio. Let's allow them to provide their own hook for doing that. Signed-off-by: Sergio Lopez --- src/libcrun/container.c | 11 ++++++++++- src/libcrun/custom-handler.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libcrun/container.c b/src/libcrun/container.c index c2f50a9b9e..d3b0813daf 100644 --- a/src/libcrun/container.c +++ b/src/libcrun/container.c @@ -1682,7 +1682,16 @@ container_init (void *args, char *notify_socket, int sync_socket, libcrun_error_ This is a best effort operation, because the seccomp filter is already in place and it could stop some syscalls used by mark_or_close_fds_ge_than. */ - ret = mark_or_close_fds_ge_than (entrypoint_args->container, entrypoint_args->context->preserve_fds + 3, true, err); + if (entrypoint_args->custom_handler->vtable->close_fds) + { + ret = entrypoint_args->custom_handler->vtable->close_fds (entrypoint_args->custom_handler->cookie, + entrypoint_args->container, + entrypoint_args->context->preserve_fds); + } + else + { + ret = mark_or_close_fds_ge_than (entrypoint_args->container, entrypoint_args->context->preserve_fds + 3, true, err); + } if (UNLIKELY (ret < 0)) crun_error_release (err); diff --git a/src/libcrun/custom-handler.h b/src/libcrun/custom-handler.h index 9351daa5be..aee032496e 100644 --- a/src/libcrun/custom-handler.h +++ b/src/libcrun/custom-handler.h @@ -48,6 +48,8 @@ struct custom_handler_s int (*modify_oci_configuration) (void *cookie, libcrun_context_t *context, runtime_spec_schema_config_schema *def, libcrun_error_t *err); + + int (*close_fds) (void *cookie, libcrun_container_t *container, int preserve_fds); }; struct custom_handler_manager_s; From fabde21458f2c45fce452b9c9b15408ec2989d7c Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Tue, 18 Nov 2025 18:45:00 +0100 Subject: [PATCH 2/2] krun: switch to passt-based networking Automatically start passt and use it for adding a virtio-net interface to the microVM. This allows us to have networking even when running generic kernels that doesn't support TSI. Signed-off-by: Sergio Lopez --- src/libcrun/handlers/krun.c | 117 ++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/libcrun/handlers/krun.c b/src/libcrun/handlers/krun.c index d7acdb150a..35e796cd49 100644 --- a/src/libcrun/handlers/krun.c +++ b/src/libcrun/handlers/krun.c @@ -24,6 +24,7 @@ #include "../linux.h" #include #include +#include #include #include #include @@ -68,6 +69,9 @@ #define KRUN_FLAVOR_AWS_NITRO "aws-nitro" #define KRUN_FLAVOR_SEV "sev" +#define PASST_FD_PARENT 0 +#define PASST_FD_CHILD 1 + struct krun_config { void *handle; @@ -80,6 +84,7 @@ struct krun_config int32_t ctx_id_awsnitro; bool has_kvm; bool has_awsnitro; + int passt_fds[2]; }; /* libkrun handler. */ @@ -366,6 +371,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname int32_t (*krun_set_console_output) (uint32_t ctx_id, const char *c_filepath); int32_t (*krun_set_exec) (uint32_t ctx_id, const char *exec_path, const char *const argv[], const char *const envp[]); + int32_t (*krun_add_net_unixstream) (uint32_t ctx_id, const char *c_path, int fd, uint8_t *const c_mac, uint32_t features, uint32_t flags); struct krun_config *kconf = (struct krun_config *) cookie; void *handle; uint32_t num_vcpus, ram_mib; @@ -498,6 +504,13 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname if (UNLIKELY (ret < 0)) error (EXIT_FAILURE, -ret, "could not set krun vm configuration"); + krun_add_net_unixstream = dlsym (handle, "krun_add_net_unixstream"); + + uint8_t mac[] = { 0x5a, 0x94, 0xef, 0xe4, 0x0c, 0xee }; + ret = krun_add_net_unixstream (ctx_id, NULL, kconf->passt_fds[PASST_FD_PARENT], &mac[0], COMPAT_NET_FEATURES, 0); + if (UNLIKELY (ret < 0)) + error (EXIT_FAILURE, -ret, "could not set krun net configuration"); + if (access ("/dev/dri", F_OK) == 0 && access ("/usr/libexec/virgl_render_server", F_OK) == 0) { ret = libkrun_enable_virtio_gpu (kconf); @@ -515,6 +528,69 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname return ret; } +static int +libkrun_start_passt (void *cookie) +{ + struct krun_config *kconf = (struct krun_config *) cookie; + pid_t pid; + char fd_as_str[16]; + int pipefd[2]; + int ret; + + socketpair (AF_UNIX, SOCK_STREAM, 0, kconf->passt_fds); + snprintf (fd_as_str, sizeof (fd_as_str), "%d", kconf->passt_fds[PASST_FD_CHILD]); + + char *const argv[] = { + (char *) "passt", + (char *) "-t", + (char *) "all", + (char *) "-u", + (char *) "all", + (char *) "-f", + (char *) "--fd", + fd_as_str, + NULL + }; + + ret = pipe (pipefd); + if (UNLIKELY (ret == -1)) + return ret; + + pid = fork (); + if (pid < 0) + { + close (pipefd[0]); + close (pipefd[1]); + return pid; + } + else if (pid == 0) + { + close (pipefd[0]); + + ret = dup2 (pipefd[1], STDERR_FILENO); + if (UNLIKELY (ret == -1)) + { + exit (EXIT_FAILURE); + } + + close (pipefd[1]); + execvp ("passt", argv); + } + else + { + /* We need to make sure passt has already started before continuing. A + simple way to do it is with a blocking read on its stdout. */ + char buffer[1]; + close (pipefd[1]); + ret = read (pipefd[0], buffer, 1); + if (UNLIKELY (ret < 0)) + return ret; + close (pipefd[0]); + } + + return 0; +} + /* libkrun_create_kvm_device: explicitly adds kvm device. */ static int libkrun_configure_container (void *cookie, enum handler_configure_phase phase, @@ -576,6 +652,10 @@ libkrun_configure_container (void *cookie, enum handler_configure_phase phase, if (phase != HANDLER_CONFIGURE_AFTER_MOUNTS) return 0; + ret = libkrun_start_passt (cookie); + if (UNLIKELY (ret < 0)) + return crun_make_error (err, errno, "start passt"); + /* Do nothing if /dev/kvm is already present in spec */ for (i = 0; i < def->linux->devices_len; i++) { @@ -846,6 +926,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co return 0; } +static int +libkrun_close_fds (void *cookie, libcrun_container_t *container, int preserve_fds) +{ + struct krun_config *kconf = (struct krun_config *) cookie; + int first_fd_to_close = preserve_fds + 3; + int high_passt_fd; + int low_passt_fd; + int ret; + int i; + + if (kconf->passt_fds[PASST_FD_CHILD] > kconf->passt_fds[PASST_FD_PARENT]) + { + high_passt_fd = kconf->passt_fds[PASST_FD_CHILD]; + low_passt_fd = kconf->passt_fds[PASST_FD_PARENT]; + } + else + { + high_passt_fd = kconf->passt_fds[PASST_FD_PARENT]; + low_passt_fd = kconf->passt_fds[PASST_FD_CHILD]; + } + + if (first_fd_to_close < high_passt_fd) + { + for (i = first_fd_to_close; i < high_passt_fd; i++) + { + if (i == low_passt_fd) + continue; + close (i); + } + + first_fd_to_close = high_passt_fd + 1; + } + + return mark_or_close_fds_ge_than (container, first_fd_to_close, true, NULL); +} + struct custom_handler_s handler_libkrun = { .name = "krun", .alias = NULL, @@ -855,6 +971,7 @@ struct custom_handler_s handler_libkrun = { .run_func = libkrun_exec, .configure_container = libkrun_configure_container, .modify_oci_configuration = libkrun_modify_oci_configuration, + .close_fds = libkrun_close_fds, }; #endif