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 23, 2021
1 parent f6108d1 commit cd3b662
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 11 deletions.
249 changes: 243 additions & 6 deletions src/libcrun/container.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,198 @@ 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;
const char *const OCI_VERSION = "0.2.0";

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 (OCI_VERSION), strlen (OCI_VERSION));
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 (OCI_VERSION), strlen (OCI_VERSION));
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
Expand Down Expand Up @@ -996,15 +1188,24 @@ 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)
{
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)
{
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;

Expand Down Expand Up @@ -1138,14 +1339,24 @@ 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)
{
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;
Expand Down Expand Up @@ -1812,6 +2023,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 @@ -1831,7 +2043,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 @@ -2873,7 +3088,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);
Expand All @@ -2898,9 +3124,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);
}
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 @@ -221,6 +221,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 cd3b662

Please sign in to comment.