Skip to content

Commit

Permalink
container: use open fd to host /proc and /sys
Browse files Browse the repository at this point in the history
use an open fd to refer to the host /proc and /sys when setting up the
SELinux and the AppArmor labels.

Addresses CVE-2019-16884.

Signed-off-by: Giuseppe Scrivano <giuseppe@scrivano.org>
  • Loading branch information
giuseppe committed Sep 28, 2019
1 parent 423bc44 commit 4352407
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 44 deletions.
39 changes: 31 additions & 8 deletions src/libcrun/container.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ int unblock_signals (libcrun_error_t *err)
static int
container_entrypoint_init (void *args, const char *notify_socket,
int sync_socket, const char **exec_path,
int host_proc_fd,
int host_sys_fd,
libcrun_error_t *err)
{
struct container_entrypoint_s *entrypoint_args = args;
Expand Down Expand Up @@ -551,11 +553,11 @@ container_entrypoint_init (void *args, const char *notify_socket,
}
}

ret = libcrun_set_selinux_exec_label (container, err);
ret = libcrun_set_selinux_exec_label (container, host_proc_fd, err);
if (UNLIKELY (ret < 0))
return ret;

ret = libcrun_set_apparmor_profile (container, err);
ret = libcrun_set_apparmor_profile (container, host_proc_fd, host_sys_fd, err);
if (UNLIKELY (ret < 0))
return ret;

Expand Down Expand Up @@ -609,11 +611,22 @@ container_entrypoint (void *args, const char *notify_socket,
int ret;
oci_container *def = entrypoint_args->container->container_def;
cleanup_free const char *exec_path = NULL;
cleanup_close int host_proc_fd = -1;
cleanup_close int host_sys_fd = -1;

entrypoint_args->sync_socket = sync_socket;

crun_set_output_handler (log_write_to_sync_socket, args, false);

ret = container_entrypoint_init (args, notify_socket, sync_socket, &exec_path, err);
host_proc_fd = open ("/proc", O_PATH | O_DIRECTORY);
if (UNLIKELY (host_proc_fd < 0))
return crun_make_error (err, errno, "open host /proc directory");

host_sys_fd = open ("/sys", O_PATH | O_DIRECTORY);
if (UNLIKELY (host_sys_fd < 0))
return crun_make_error (err, errno, "open host /sys directory");

ret = container_entrypoint_init (args, notify_socket, sync_socket, &exec_path, host_proc_fd, host_sys_fd, err);
if (UNLIKELY (ret < 0))
{
/* If it fails to write the error using the sync socket, then fallback
Expand Down Expand Up @@ -659,7 +672,7 @@ container_entrypoint (void *args, const char *notify_socket,

crun_set_output_handler (log_write_to_stderr, NULL, false);

ret = close_fds_ge_than (entrypoint_args->context->preserve_fds + 3, err);
ret = close_fds_ge_than (host_proc_fd, entrypoint_args->context->preserve_fds + 3, err);
if (UNLIKELY (ret < 0))
crun_error_write_warning_and_release (entrypoint_args->context->output_handler_arg, &err);

Expand Down Expand Up @@ -1898,6 +1911,8 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, oci_containe
int container_ret_status[2];
cleanup_close int pipefd0 = -1;
cleanup_close int pipefd1 = -1;
cleanup_close int host_proc_fd = -1;
cleanup_close int host_sys_fd = -1;
char b;

memset (&status, 0, sizeof (status));
Expand Down Expand Up @@ -1947,6 +1962,14 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, oci_containe
pipefd0 = container_ret_status[0];
pipefd1 = container_ret_status[1];

host_proc_fd = open ("/proc", O_PATH | O_DIRECTORY);
if (UNLIKELY (host_proc_fd < 0))
return crun_make_error (err, errno, "open host /proc directory");

host_sys_fd = open ("/sys", O_PATH | O_DIRECTORY);
if (UNLIKELY (host_sys_fd < 0))
return crun_make_error (err, errno, "open host /sys directory");

pid = libcrun_join_process (container, status.pid, &status, context->detach, process->terminal ? &terminal_fd : NULL, err);
if (UNLIKELY (pid < 0))
return pid;
Expand Down Expand Up @@ -1979,13 +2002,13 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, oci_containe

if (process->selinux_label)
{
if (UNLIKELY (set_selinux_exec_label (process->selinux_label, err) < 0))
if (UNLIKELY (set_selinux_exec_label (host_proc_fd, process->selinux_label, err) < 0))
libcrun_fail_with_error ((*err)->status, "%s", (*err)->msg);
}

if (process->apparmor_profile)
if (process->apparmor_profile)
{
if (UNLIKELY (set_apparmor_profile (process->apparmor_profile, err) < 0))
if (UNLIKELY (set_apparmor_profile (host_proc_fd, host_sys_fd, process->apparmor_profile, err) < 0))
libcrun_fail_with_error ((*err)->status, "%s", (*err)->msg);
}

Expand Down Expand Up @@ -2034,7 +2057,7 @@ libcrun_container_exec (libcrun_context_t *context, const char *id, oci_containe
libcrun_fail_with_error ((*err)->status, "%s", (*err)->msg);
}

ret = close_fds_ge_than (context->preserve_fds + 3, err);
ret = close_fds_ge_than (host_proc_fd, context->preserve_fds + 3, err);
if (UNLIKELY (ret < 0))
libcrun_fail_with_error ((*err)->status, "%s", (*err)->msg);

Expand Down
8 changes: 4 additions & 4 deletions src/libcrun/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,7 @@ read_caps (unsigned long caps[2], char **values, size_t len, libcrun_error_t *er
}

int
libcrun_set_selinux_exec_label (libcrun_container_t *container, libcrun_error_t *err)
libcrun_set_selinux_exec_label (libcrun_container_t *container, int host_proc_fd, libcrun_error_t *err)
{
char *label;

Expand All @@ -1601,11 +1601,11 @@ libcrun_set_selinux_exec_label (libcrun_container_t *container, libcrun_error_t
label = container->container_def->process->selinux_label;
if (label == NULL)
return 0;
return set_selinux_exec_label (label, err);
return set_selinux_exec_label (host_proc_fd, label, err);
}

int
libcrun_set_apparmor_profile(libcrun_container_t *container, libcrun_error_t *err)
libcrun_set_apparmor_profile (libcrun_container_t *container, int host_proc_fd, int host_sys_fd, libcrun_error_t *err)
{
char *profile;

Expand All @@ -1615,7 +1615,7 @@ libcrun_set_apparmor_profile(libcrun_container_t *container, libcrun_error_t *er
profile = container->container_def->process->apparmor_profile;
if (profile == NULL)
return 0;
return set_apparmor_profile (profile, err);
return set_apparmor_profile (host_proc_fd, host_sys_fd, profile, err);
}

int
Expand Down
4 changes: 2 additions & 2 deletions src/libcrun/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ int libcrun_do_pivot_root (libcrun_container_t *container, bool no_pivot, const
int libcrun_set_usernamespace (libcrun_container_t *container, pid_t pid, libcrun_error_t *err);
int libcrun_set_caps (oci_container_process_capabilities *capabilities, uid_t uid, gid_t gid, int no_new_privileges, libcrun_error_t *err);
int libcrun_set_rlimits (oci_container_process_rlimits_element **rlimits, size_t len, libcrun_error_t *err);
int libcrun_set_selinux_exec_label (libcrun_container_t *container, libcrun_error_t *err);
int libcrun_set_apparmor_profile (libcrun_container_t *container, libcrun_error_t *err);
int libcrun_set_selinux_exec_label (libcrun_container_t *container, int host_root_fd, libcrun_error_t *err);
int libcrun_set_apparmor_profile (libcrun_container_t *container, int host_proc_fd, int host_sys_fd, libcrun_error_t *err);
int libcrun_set_hostname (libcrun_container_t *container, libcrun_error_t *err);
int libcrun_set_oom (libcrun_container_t *container, libcrun_error_t *err);
int libcrun_set_sysctl (libcrun_container_t *container, libcrun_error_t *err);
Expand Down
64 changes: 39 additions & 25 deletions src/libcrun/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,41 +405,30 @@ add_selinux_mount_label (char **ret, const char *data, const char *label, libcru
}

int
set_selinux_exec_label (const char *label, libcrun_error_t *err)
set_selinux_exec_label (int host_proc_fd, const char *label, libcrun_error_t *err)
{
(void) host_proc_fd;
#ifdef HAVE_SELINUX
if (is_selinux_enabled () > 0)
if (UNLIKELY (setexeccon (label) < 0))
{
crun_make_error (err, errno, "error setting SELinux exec label");
return -1;
}
#endif
return 0;
}
{
int ret;

int
set_apparmor_profile (const char *profile, libcrun_error_t *err)
{
#ifdef HAVE_APPARMOR
if (is_apparmor_enabled () == 1)
if (UNLIKELY (aa_change_onexec (profile) < 0))
{
crun_make_error (err, errno, "error setting apparmor profile");
return -1;
}
ret = write_file_at (host_proc_fd, "thread-self/attr/exec", label, strlen (label), err);
if (UNLIKELY (ret < 0))
return ret;
}
#endif
return 0;
}

int
is_apparmor_enabled(void)
static int
is_apparmor_enabled (int host_sys_fd)
{
int size;
cleanup_close int fd;
char buf[2];

fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
fd = openat (host_sys_fd, "sys/module/apparmor/parameters/enabled", O_RDONLY);
if (fd == -1) {
return 0;
}
Expand All @@ -450,6 +439,24 @@ is_apparmor_enabled(void)
return 0;
}

int
set_apparmor_profile (int host_proc_fd, int host_sys_fd, const char *profile, libcrun_error_t *err)
{
(void) host_sys_fd;
(void) host_proc_fd;
#ifdef HAVE_APPARMOR
if (is_apparmor_enabled (host_sys_fd) == 1)
{
int ret;

ret = write_file_at (host_proc_fd, "thread-self/attr/exec", profile, strlen (profile), err);
if (UNLIKELY (ret < 0))
return ret;
}
#endif
return 0;
}

int
read_all_fd (int fd, const char *description, char **out, size_t *len, libcrun_error_t *err)
{
Expand Down Expand Up @@ -963,16 +970,23 @@ run_process_with_stdin_timeout_envp (char *path,
}

int
close_fds_ge_than (int n, libcrun_error_t *err)
close_fds_ge_than (int proc_fd, int n, libcrun_error_t *err)
{
int fd;
cleanup_dir DIR *dir = NULL;
int ret;
struct dirent *next;

dir = opendir ("/proc/self/fd");
fd = openat (proc_fd, "self/fd", O_DIRECTORY | O_RDONLY);
if (UNLIKELY (fd < 0))
return crun_make_error (err, errno, "open /proc/self/fd");

dir = fdopendir (fd);
if (UNLIKELY (dir == NULL))
return crun_make_error (err, errno, "cannot fdopendir /proc/self/fd");
{
close (fd);
return crun_make_error (err, errno, "cannot fdopendir /proc/self/fd");
}

fd = dirfd (dir);
for (next = readdir (dir); next; next = readdir (dir))
Expand Down
8 changes: 3 additions & 5 deletions src/libcrun/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,11 @@ int create_file_if_missing (const char *file, libcrun_error_t *err);

int check_running_in_user_namespace (libcrun_error_t *err);

int set_selinux_exec_label (const char *label, libcrun_error_t *err);
int set_selinux_exec_label (int host_root_fd, const char *label, libcrun_error_t *err);

int add_selinux_mount_label (char **ret, const char *data, const char *label, libcrun_error_t *err);

int set_apparmor_profile (const char *profile, libcrun_error_t *err);

int is_apparmor_enabled(void);
int set_apparmor_profile (int host_proc_fd, int host_sys_fd, const char *profile, libcrun_error_t *err);

int read_all_fd (int fd, const char *description, char **out, size_t *len, libcrun_error_t *err);

Expand Down Expand Up @@ -117,7 +115,7 @@ size_t format_default_id_mapping (char **ret, uid_t container_id, uid_t host_id,

int run_process_with_stdin_timeout_envp (char *path, char **args, const char *cwd, int timeout, char **envp, char *stdin, size_t stdin_len, libcrun_error_t *err);

int close_fds_ge_than (int n, libcrun_error_t *err);
int close_fds_ge_than (int proc_fd, int n, libcrun_error_t *err);

void get_current_timestamp (char *out);

Expand Down

0 comments on commit 4352407

Please sign in to comment.