Skip to content

Commit

Permalink
seccomp: support notify listener
Browse files Browse the repository at this point in the history
The OCI runtime specs[1] recently gained the support for seccomp
notifications.

[1] opencontainers/runtime-spec#1074

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Mar 16, 2021
1 parent 8bac72a commit f554dc2
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 13 deletions.
156 changes: 148 additions & 8 deletions src/libcrun/container.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,10 +749,95 @@ libcrun_configure_handler (struct container_entrypoint_s *args, libcrun_error_t
return crun_make_error (err, EINVAL, "invalid handler specified `%s`", annotation);
}

static void
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)
{
yajl_gen gen = NULL;
runtime_spec_schema_config_schema *def = container->container_def;

gen = yajl_gen_alloc (NULL);
if (gen == NULL)
OOM ();

yajl_gen_config (gen, yajl_gen_beautify, 1);
yajl_gen_config (gen, yajl_gen_validate_utf8, 1);

yajl_gen_map_open (gen);
yajl_gen_string (gen, YAJL_STR ("ociVersion"), strlen ("ociVersion"));
yajl_gen_string (gen, YAJL_STR ("0.2.0"), strlen ("0.2.0"));

yajl_gen_string (gen, YAJL_STR ("fds"), strlen ("fds"));
yajl_gen_array_open (gen);
yajl_gen_string (gen, YAJL_STR ("seccompFd"), strlen ("seccompFd"));
yajl_gen_array_close (gen);

yajl_gen_string (gen, YAJL_STR ("pid"), strlen ("pid"));
yajl_gen_integer (gen, own_pid);

if (def && def->linux && def->linux->seccomp)
{
const char *metadata = def->linux->seccomp->listener_metadata;

if (metadata)
{
yajl_gen_string (gen, YAJL_STR ("metadata"), strlen ("metadata"));
yajl_gen_string (gen, YAJL_STR (metadata), strlen (metadata));
}
}

/* State. */
yajl_gen_string (gen, YAJL_STR ("state"), strlen ("state"));
yajl_gen_map_open (gen);
yajl_gen_string (gen, YAJL_STR ("ociVersion"), strlen ("ociVersion"));
yajl_gen_string (gen, YAJL_STR ("0.2.0"), strlen ("0.2.0"));

if (container->context && container->context->id)
{
yajl_gen_string (gen, YAJL_STR ("id"), strlen ("id"));
yajl_gen_string (gen, YAJL_STR (container->context->id), strlen (container->context->id));
}

yajl_gen_string (gen, YAJL_STR ("status"), strlen ("status"));
yajl_gen_string (gen, YAJL_STR (status), strlen (status));

yajl_gen_string (gen, YAJL_STR ("pid"), strlen ("pid"));
yajl_gen_integer (gen, own_pid);

if (container->context && container->context->bundle)
{
yajl_gen_string (gen, YAJL_STR ("bundle"), strlen ("bundle"));
yajl_gen_string (gen, YAJL_STR (container->context->bundle), strlen (container->context->bundle));
}

if (def->annotations && def->annotations->len)
{
size_t i;

yajl_gen_string (gen, YAJL_STR ("annotations"), strlen ("annotations"));
yajl_gen_map_open (gen);
for (i = 0; i < def->annotations->len; i++)
{
const char *key = def->annotations->keys[i];
const char *val = def->annotations->values[i];
yajl_gen_string (gen, YAJL_STR (key), strlen (key));
yajl_gen_string (gen, YAJL_STR (val), strlen (val));
}
yajl_gen_map_close (gen);
}

yajl_gen_map_close (gen);
/* End state. */

yajl_gen_map_close (gen);

if (yajl_gen_get_buf (gen, (const unsigned char **) seccomp_fd_payload, seccomp_fd_payload_len) != yajl_gen_status_ok)
yajl_gen_free (gen);
}

/* Initialize the environment where the container process runs.
It is used by the container init process. */
static int
container_init_setup (void *args, char *notify_socket, int sync_socket, const char **exec_path, libcrun_error_t *err)
container_init_setup (void *args, pid_t own_pid, char *notify_socket, int sync_socket, const char **exec_path, libcrun_error_t *err)
{
struct container_entrypoint_s *entrypoint_args = args;
libcrun_container_t *container = entrypoint_args->container;
Expand Down Expand Up @@ -942,15 +1027,20 @@ container_init_setup (void *args, char *notify_socket, int sync_socket, const ch
{
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)
{
seccomp_flags = def->linux->seccomp->flags;
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)
get_seccomp_receiver_fd_payload (container, "creating", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len);

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;

Expand Down Expand Up @@ -1015,12 +1105,22 @@ container_init (void *args, char *notify_socket, int sync_socket, libcrun_error_
runtime_spec_schema_config_schema *def = entrypoint_args->container->container_def;
cleanup_free const char *exec_path = NULL;
cleanup_free char *notify_socket_cleanup = notify_socket;
pid_t own_pid = 0;

entrypoint_args->sync_socket = sync_socket;

crun_set_output_handler (log_write_to_sync_socket, args, false);

ret = container_init_setup (args, notify_socket, sync_socket, &exec_path, err);
/* sync receive own pid. */
ret = TEMP_FAILURE_RETRY (read (sync_socket, &own_pid, sizeof (own_pid)));
if (UNLIKELY (ret != sizeof (own_pid)))
{
if (ret >= 0)
errno = 0;
return crun_make_error (err, errno, "read from sync socket");
}

ret = container_init_setup (args, own_pid, notify_socket, sync_socket, &exec_path, err);
if (UNLIKELY (ret < 0))
{
/* If it fails to write the error using the sync socket, then fallback
Expand Down Expand Up @@ -1074,14 +1174,20 @@ 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)
{
seccomp_flags = def->linux->seccomp->flags;
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)
get_seccomp_receiver_fd_payload (entrypoint_args->container, "creating", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len);

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;
Expand Down Expand Up @@ -1745,6 +1851,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;
Expand All @@ -1764,7 +1871,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)
Expand Down Expand Up @@ -1935,6 +2045,16 @@ libcrun_container_run_internal (libcrun_container_t *container, libcrun_context_
return cleanup_watch (context, pid, sync_socket, terminal_fd, err);
}

/* sync send own pid. */
ret = TEMP_FAILURE_RETRY (write (sync_socket, &pid, sizeof (pid)));
if (UNLIKELY (ret != sizeof (pid)))
{
if (ret >= 0)
errno = 0;
crun_make_error (err, errno, "write to sync socket");
return cleanup_watch (context, pid, sync_socket, terminal_fd, err);
}

/* sync 1. */
ret = sync_socket_send_sync (sync_socket, true, err);
if (UNLIKELY (ret < 0))
Expand Down Expand Up @@ -2709,10 +2829,13 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, runtime_spec
runtime_spec_schema_config_schema_process_capabilities *capabilities = NULL;
char **seccomp_flags = NULL;
size_t seccomp_flags_len = 0;
pid_t own_pid = 0;

TEMP_FAILURE_RETRY (close (pipefd0));
pipefd0 = -1;

TEMP_FAILURE_RETRY (read (pipefd1, &own_pid, sizeof (own_pid)));

cwd = process->cwd ? process->cwd : "/";
if (chdir (cwd) < 0)
libcrun_fail_with_error (errno, "chdir");
Expand Down Expand Up @@ -2789,7 +2912,14 @@ 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)
get_seccomp_receiver_fd_payload (container, "running", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len);

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);
Expand All @@ -2814,9 +2944,17 @@ 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)
get_seccomp_receiver_fd_payload (container, "running", own_pid, &seccomp_fd_payload, &seccomp_fd_payload_len);

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);
}
Expand All @@ -2836,6 +2974,8 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, runtime_spec
TEMP_FAILURE_RETRY (close (pipefd1));
pipefd1 = -1;

TEMP_FAILURE_RETRY (write (pipefd0, &pid, sizeof (pid)));

if (seccomp_fd >= 0)
close_and_reset (&seccomp_fd);

Expand Down
6 changes: 4 additions & 2 deletions src/libcrun/seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/libcrun/seccomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
16 changes: 14 additions & 2 deletions src/libcrun/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/libcrun/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f554dc2

Please sign in to comment.