diff --git a/src/libcrun/container.c b/src/libcrun/container.c index f1b0fb0be1..1faf72705a 100644 --- a/src/libcrun/container.c +++ b/src/libcrun/container.c @@ -803,6 +803,197 @@ libcrun_configure_handler (struct container_entrypoint_s *args, libcrun_error_t return crun_make_error (err, EINVAL, "invalid handler specified `%s`", annotation); } +static int +get_yajl_result (yajl_gen gen, char **out, size_t *out_len) +{ + const unsigned char *buf = NULL; + size_t buf_len = 0; + int r; + + r = yajl_gen_get_buf (gen, &buf, &buf_len); + if (UNLIKELY (r != yajl_gen_status_ok)) + return r; + + *out_len = buf_len; + + *out = malloc (buf_len + 1); + if (*out == NULL) + OOM (); + memcpy (*out, buf, buf_len); + (*out)[buf_len] = '\0'; + + return yajl_gen_status_ok; +} + +static int +get_seccomp_receiver_fd_payload (libcrun_container_t *container, const char *status, pid_t own_pid, + char **seccomp_fd_payload, size_t *seccomp_fd_payload_len, libcrun_error_t *err) +{ + int r; + yajl_gen gen = NULL; + runtime_spec_schema_config_schema *def = container->container_def; + + gen = yajl_gen_alloc (NULL); + if (gen == NULL) + return crun_make_error (err, 0, "yajl_gen_alloc failed"); + + yajl_gen_config (gen, yajl_gen_beautify, 1); + yajl_gen_config (gen, yajl_gen_validate_utf8, 1); + + r = yajl_gen_map_open (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("ociVersion"), strlen ("ociVersion")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("0.2.0"), strlen ("0.2.0")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("fds"), strlen ("fds")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_array_open (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("seccompFd"), strlen ("seccompFd")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_array_close (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("pid"), strlen ("pid")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_integer (gen, own_pid); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + if (def && def->linux && def->linux->seccomp) + { + const char *metadata = def->linux->seccomp->listener_metadata; + + if (metadata) + { + r = yajl_gen_string (gen, YAJL_STR ("metadata"), strlen ("metadata")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR (metadata), strlen (metadata)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + } + } + + /* State. */ + r = yajl_gen_string (gen, YAJL_STR ("state"), strlen ("state")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_map_open (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("ociVersion"), strlen ("ociVersion")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("0.2.0"), strlen ("0.2.0")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + if (container->context && container->context->id) + { + r = yajl_gen_string (gen, YAJL_STR ("id"), strlen ("id")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR (container->context->id), strlen (container->context->id)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + } + + r = yajl_gen_string (gen, YAJL_STR ("status"), strlen ("status")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR (status), strlen (status)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR ("pid"), strlen ("pid")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_integer (gen, own_pid); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + if (container->context && container->context->bundle) + { + r = yajl_gen_string (gen, YAJL_STR ("bundle"), strlen ("bundle")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR (container->context->bundle), strlen (container->context->bundle)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + } + + if (def->annotations && def->annotations->len) + { + size_t i; + + r = yajl_gen_string (gen, YAJL_STR ("annotations"), strlen ("annotations")); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_map_open (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + for (i = 0; i < def->annotations->len; i++) + { + const char *key = def->annotations->keys[i]; + const char *val = def->annotations->values[i]; + + r = yajl_gen_string (gen, YAJL_STR (key), strlen (key)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = yajl_gen_string (gen, YAJL_STR (val), strlen (val)); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + } + r = yajl_gen_map_close (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + } + + r = yajl_gen_map_close (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + /* End state. */ + + r = yajl_gen_map_close (gen); + if (UNLIKELY (r != yajl_gen_status_ok)) + goto exit; + + r = get_yajl_result (gen, seccomp_fd_payload, seccomp_fd_payload_len); + +exit: + yajl_gen_free (gen); + + return yajl_error_to_crun_error (r, err); +} + /* Initialize the environment where the container process runs. It is used by the container init process. */ static int @@ -996,6 +1187,8 @@ container_init_setup (void *args, pid_t own_pid, char *notify_socket, int sync_s { char **seccomp_flags = NULL; size_t seccomp_flags_len = 0; + cleanup_free char *seccomp_fd_payload = NULL; + size_t seccomp_fd_payload_len = 0; if (def->linux && def->linux->seccomp) { @@ -1003,8 +1196,15 @@ container_init_setup (void *args, pid_t own_pid, char *notify_socket, int sync_s seccomp_flags_len = def->linux->seccomp->flags_len; } - ret = libcrun_apply_seccomp (entrypoint_args->seccomp_fd, entrypoint_args->seccomp_receiver_fd, seccomp_flags, - seccomp_flags_len, err); + if (entrypoint_args->seccomp_receiver_fd >= 0) + { + ret = get_seccomp_receiver_fd_payload (container, "creating", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len, err); + if (UNLIKELY (ret < 0)) + return ret; + } + + ret = libcrun_apply_seccomp (entrypoint_args->seccomp_fd, entrypoint_args->seccomp_receiver_fd, + seccomp_fd_payload, seccomp_fd_payload_len, seccomp_flags, seccomp_flags_len, err); if (UNLIKELY (ret < 0)) return ret; @@ -1138,6 +1338,8 @@ container_init (void *args, char *notify_socket, int sync_socket, libcrun_error_ { char **seccomp_flags = NULL; size_t seccomp_flags_len = 0; + cleanup_free char *seccomp_fd_payload = NULL; + size_t seccomp_fd_payload_len = 0; if (def->linux && def->linux->seccomp) { @@ -1145,7 +1347,15 @@ container_init (void *args, char *notify_socket, int sync_socket, libcrun_error_ seccomp_flags_len = def->linux->seccomp->flags_len; } - ret = libcrun_apply_seccomp (entrypoint_args->seccomp_fd, entrypoint_args->seccomp_receiver_fd, seccomp_flags, + if (entrypoint_args->seccomp_receiver_fd >= 0) + { + ret = get_seccomp_receiver_fd_payload (entrypoint_args->container, "creating", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len, err); + if (UNLIKELY (ret < 0)) + return ret; + } + + ret = libcrun_apply_seccomp (entrypoint_args->seccomp_fd, entrypoint_args->seccomp_receiver_fd, + seccomp_fd_payload, seccomp_fd_payload_len, seccomp_flags, seccomp_flags_len, err); if (UNLIKELY (ret < 0)) return ret; @@ -1809,6 +2019,7 @@ get_seccomp_receiver_fd (libcrun_container_t *container, int *fd, int *self_rece libcrun_error_t *err) { const char *tmp; + runtime_spec_schema_config_schema *def = container->container_def; *fd = -1; *self_receiver_fd = -1; @@ -1828,7 +2039,10 @@ get_seccomp_receiver_fd (libcrun_container_t *container, int *fd, int *self_rece *plugins = tmp; } - tmp = find_annotation (container, "run.oci.seccomp.receiver"); + if (def && def->linux && def->linux->seccomp && def->linux->seccomp->listener_path) + tmp = def->linux->seccomp->listener_path; + else + tmp = find_annotation (container, "run.oci.seccomp.receiver"); if (tmp == NULL) tmp = getenv ("RUN_OCI_SECCOMP_RECEIVER"); if (tmp) @@ -2866,7 +3080,18 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, runtime_spec if (! process->no_new_privileges) { - ret = libcrun_apply_seccomp (seccomp_fd, seccomp_receiver_fd, seccomp_flags, seccomp_flags_len, err); + cleanup_free char *seccomp_fd_payload = NULL; + size_t seccomp_fd_payload_len = 0; + + if (seccomp_receiver_fd >= 0) + { + ret = get_seccomp_receiver_fd_payload (container, "running", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len, err); + if (UNLIKELY (ret < 0)) + return ret; + } + + ret = libcrun_apply_seccomp (seccomp_fd, seccomp_receiver_fd, seccomp_fd_payload, + seccomp_fd_payload_len, seccomp_flags, seccomp_flags_len, err); if (UNLIKELY (ret < 0)) return ret; close_and_reset (&seccomp_fd); @@ -2891,9 +3116,20 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, runtime_spec if (process->no_new_privileges) { - ret = libcrun_apply_seccomp (seccomp_fd, seccomp_receiver_fd, seccomp_flags, seccomp_flags_len, err); + cleanup_free char *seccomp_fd_payload = NULL; + size_t seccomp_fd_payload_len = 0; + + if (seccomp_receiver_fd >= 0) + { + ret = get_seccomp_receiver_fd_payload (container, "running", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len, err); + if (UNLIKELY (ret < 0)) + return ret; + } + ret = libcrun_apply_seccomp (seccomp_fd, seccomp_receiver_fd, seccomp_fd_payload, + seccomp_fd_payload_len, seccomp_flags, seccomp_flags_len, err); if (UNLIKELY (ret < 0)) return ret; + close_and_reset (&seccomp_fd); close_and_reset (&seccomp_receiver_fd); } diff --git a/src/libcrun/seccomp.c b/src/libcrun/seccomp.c index db91ee61ec..6eea4388d0 100644 --- a/src/libcrun/seccomp.c +++ b/src/libcrun/seccomp.c @@ -168,7 +168,8 @@ cleanup_seccompp (void *p) #define cleanup_seccomp __attribute__ ((cleanup (cleanup_seccompp))) int -libcrun_apply_seccomp (int infd, int listener_receiver_fd, char **seccomp_flags, size_t seccomp_flags_len, +libcrun_apply_seccomp (int infd, int listener_receiver_fd, const char *receiver_fd_payload, + size_t receiver_fd_payload_len, char **seccomp_flags, size_t seccomp_flags_len, libcrun_error_t *err) { #ifdef HAVE_SECCOMP @@ -233,7 +234,8 @@ libcrun_apply_seccomp (int infd, int listener_receiver_fd, char **seccomp_flags, { int fd = ret; - ret = send_fd_to_socket (listener_receiver_fd, fd, err); + ret = send_fd_to_socket_with_payload (listener_receiver_fd, fd, + receiver_fd_payload, receiver_fd_payload_len, err); if (UNLIKELY (ret < 0)) return crun_error_wrap (err, "send listener fd `%d` to receiver", fd); } diff --git a/src/libcrun/seccomp.h b/src/libcrun/seccomp.h index 6314d44d20..7d8e43c6fa 100644 --- a/src/libcrun/seccomp.h +++ b/src/libcrun/seccomp.h @@ -32,6 +32,7 @@ enum }; int libcrun_generate_seccomp (libcrun_container_t *container, int outfd, unsigned int options, libcrun_error_t *err); -int libcrun_apply_seccomp (int infd, int listener_receiver_fd, char **flags, size_t flags_len, libcrun_error_t *err); +int libcrun_apply_seccomp (int infd, int listener_receiver_fd, const char *receiver_fd_payload, + size_t receiver_fd_payload_len, char **flags, size_t flags_len, libcrun_error_t *err); #endif diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c index 8983b6a796..f16cb9362a 100644 --- a/src/libcrun/utils.c +++ b/src/libcrun/utils.c @@ -922,18 +922,30 @@ open_unix_domain_socket (const char *path, int dgram, libcrun_error_t *err) int send_fd_to_socket (int server, int fd, libcrun_error_t *err) +{ + return send_fd_to_socket_with_payload (server, fd, NULL, 0, err); +} + +int +send_fd_to_socket_with_payload (int server, int fd, const char *payload, size_t payload_len, libcrun_error_t *err) { int ret; struct cmsghdr *cmsg = NULL; - struct iovec iov[1]; + struct iovec iov[2]; struct msghdr msg = {}; - char ctrl_buf[CMSG_SPACE (sizeof (int))] = {}; + char ctrl_buf[CMSG_SPACE (1 + sizeof (int))] = {}; char data[1]; data[0] = ' '; iov[0].iov_base = data; iov[0].iov_len = sizeof (data); + if (payload_len > 0) + { + iov[0].iov_base = (void *) payload; + iov[0].iov_len = payload_len; + } + msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; diff --git a/src/libcrun/utils.h b/src/libcrun/utils.h index b5d0594275..1499e33c54 100644 --- a/src/libcrun/utils.h +++ b/src/libcrun/utils.h @@ -207,6 +207,8 @@ int open_unix_domain_socket (const char *path, int dgram, libcrun_error_t *err); int send_fd_to_socket (int server, int fd, libcrun_error_t *err); +int send_fd_to_socket_with_payload (int server, int fd, const char *payload, size_t payload_len, libcrun_error_t *err); + int create_socket_pair (int *pair, libcrun_error_t *err); int receive_fd_from_socket (int from, libcrun_error_t *err);