From c588fc37e223075f7cfad8ba2fa2221180c47b2e 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 | 10 +++++++++- src/libcrun/custom-handler.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libcrun/container.c b/src/libcrun/container.c index 642ac453bf..aa7812efc2 100644 --- a/src/libcrun/container.c +++ b/src/libcrun/container.c @@ -1651,7 +1651,15 @@ 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->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->context->preserve_fds); + } + else + { + ret = mark_or_close_fds_ge_than (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..43d97b806c 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, int preserve_fds); }; struct custom_handler_manager_s; From b77f2997cd869f1c00b8213225dd38462adc8e34 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 b0bf276c7d..5d61bd4716 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 @@ -62,6 +63,9 @@ #define KRUN_FLAVOR_NITRO "aws-nitro" #define KRUN_FLAVOR_SEV "sev" +#define PASST_FD_PARENT 0 +#define PASST_FD_CHILD 1 + struct krun_config { void *handle; @@ -74,6 +78,7 @@ struct krun_config int32_t ctx_id_nitro; bool has_kvm; bool has_nitro; + int passt_fds[2]; }; /* libkrun handler. */ @@ -350,6 +355,7 @@ libkrun_exec (void *cookie, libcrun_container_t *container, const char *pathname int32_t (*krun_set_root) (uint32_t ctx_id, const char *root_path); int32_t (*krun_set_root_disk) (uint32_t ctx_id, const char *disk_path); int32_t (*krun_set_tee_config_file) (uint32_t ctx_id, const char *file_path); + 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; @@ -450,6 +456,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); @@ -464,6 +477,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, @@ -525,6 +601,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++) { @@ -781,6 +861,42 @@ libkrun_modify_oci_configuration (void *cookie arg_unused, libcrun_context_t *co return 0; } +static int +libkrun_close_fds (void *cookie, 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 (first_fd_to_close, true, NULL); +} + struct custom_handler_s handler_libkrun = { .name = "krun", .alias = NULL, @@ -790,6 +906,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