Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sepolicy: Cache the value of is_selinux_enabled() to work around bug #815

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 68 additions & 112 deletions src/libostree/ostree-sepolicy.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ struct OstreeSePolicy {
int rootfs_dfd_owned;
GFile *path;

gboolean runtime_enabled;

#ifdef HAVE_SELINUX
GFile *selinux_policy_root;
struct selabel_handle *selinux_hnd;
Expand Down Expand Up @@ -198,33 +196,29 @@ get_policy_checksum (char **out_csum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;

const char *binary_policy_path = selinux_binary_policy_path ();
const char *binfile_prefix = glnx_basename (binary_policy_path);
g_autofree char *bindir_path = g_path_get_dirname (binary_policy_path);

glnx_fd_close int bindir_dfd = -1;

g_autofree char *best_policy = NULL;
int best_version = 0;

g_auto(GLnxDirFdIterator) dfd_iter = { 0,};

glnx_fd_close int bindir_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error))
goto out;
return FALSE;

g_auto(GLnxDirFdIterator) dfd_iter = { 0,};
if (!glnx_dirfd_iterator_init_at (bindir_dfd, ".", FALSE, &dfd_iter, error))
goto out;
return FALSE;

while (TRUE)
{
struct dirent *dent = NULL;

if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent,
cancellable, error))
goto out;

return FALSE;
if (dent == NULL)
break;

Expand Down Expand Up @@ -259,44 +253,54 @@ get_policy_checksum (char **out_csum,
}

if (!best_policy)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not find binary policy file");
goto out;
}
return glnx_throw (error, "Could not find binary policy file");

*out_csum = ot_checksum_file_at (bindir_dfd, best_policy, G_CHECKSUM_SHA256,
cancellable, error);
if (*out_csum == NULL)
goto out;
return FALSE;

ret = TRUE;
out:
return ret;
return TRUE;
}

#endif


/* Workaround for http://marc.info/?l=selinux&m=149323809332417&w=2 */
#ifdef HAVE_SELINUX
static gboolean
cached_is_selinux_enabled (void)
{
static gsize initialized;
static gboolean cached_enabled;
if (g_once_init_enter (&initialized))
{
cached_enabled = is_selinux_enabled () == 1;
g_once_init_leave (&initialized, 1);
}
return cached_enabled;
}
#endif

static gboolean
initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
#ifdef HAVE_SELINUX
gboolean ret = FALSE;
OstreeSePolicy *self = OSTREE_SEPOLICY (initable);
g_autoptr(GFile) path = NULL;
g_autoptr(GFile) etc_selinux_dir = NULL;
g_autoptr(GFile) policy_config_path = NULL;
g_autoptr(GFile) policy_root = NULL;
g_autoptr(GFileInputStream) filein = NULL;
g_autoptr(GDataInputStream) datain = NULL;
gboolean enabled = FALSE;
g_autofree char *policytype = NULL;
const char *selinux_prefix = "SELINUX=";
const char *selinuxtype_prefix = "SELINUXTYPE=";

/* First thing here, call is_selinux_enabled() to prime the cache. See the
* link above for more information why.
*/
(void) cached_is_selinux_enabled ();

/* TODO - use this below */
g_autoptr(GFile) path = NULL;
if (self->rootfs_dfd != -1)
path = ot_fdrel_to_gfile (self->rootfs_dfd, ".");
else if (self->path)
Expand All @@ -306,45 +310,44 @@ initable_init (GInitable *initable,
/* TODO - use this below */
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE,
&self->rootfs_dfd_owned, error))
goto out;
return FALSE;
self->rootfs_dfd = self->rootfs_dfd_owned;
#endif
}
else
g_assert_not_reached ();

etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux");
g_autoptr(GFile) etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux");
if (!g_file_query_exists (etc_selinux_dir, NULL))
{
g_object_unref (etc_selinux_dir);
etc_selinux_dir = g_file_resolve_relative_path (path, "usr/etc/selinux");
}
policy_config_path = g_file_get_child (etc_selinux_dir, "config");

g_autoptr(GFile) policy_config_path = g_file_get_child (etc_selinux_dir, "config");
g_autoptr(GFile) policy_root = NULL;
if (g_file_query_exists (policy_config_path, NULL))
{
filein = g_file_read (policy_config_path, cancellable, error);
g_autoptr(GFileInputStream) filein = filein = g_file_read (policy_config_path, cancellable, error);

if (!filein)
goto out;
return FALSE;

datain = g_data_input_stream_new ((GInputStream*)filein);
g_autoptr(GDataInputStream) datain = g_data_input_stream_new ((GInputStream*)filein);

while (TRUE)
{
gsize len;
GError *temp_error = NULL;
g_autoptr(GError) temp_error = NULL;
g_autofree char *line = g_data_input_stream_read_line_utf8 (datain, &len,
cancellable, &temp_error);

if (temp_error)
{
g_propagate_error (error, temp_error);
goto out;
}
return g_propagate_error (error, g_steal_pointer (&temp_error)), FALSE;

if (!line)
break;

if (g_str_has_prefix (line, selinuxtype_prefix))
{
policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix)));
Expand All @@ -362,57 +365,32 @@ initable_init (GInitable *initable,

if (enabled)
{
self->runtime_enabled = is_selinux_enabled () == 1;
const char *policy_rootpath = gs_file_get_path_cached (policy_root);

g_setenv ("LIBSELINUX_DISABLE_PCRE_PRECOMPILED", "1", FALSE);
if (selinux_set_policy_root (gs_file_get_path_cached (policy_root)) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"selinux_set_policy_root(%s): %s",
gs_file_get_path_cached (etc_selinux_dir),
strerror (errno));
goto out;
}
if (selinux_set_policy_root (policy_rootpath) != 0)
return glnx_throw_errno_prefix (error, "selinux_set_policy_root(%s)", policy_rootpath);

self->selinux_hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0);
if (!self->selinux_hnd)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"With policy root '%s': selabel_open(SELABEL_CTX_FILE): %s",
gs_file_get_path_cached (etc_selinux_dir),
strerror (errno));
goto out;
}
return glnx_throw_errno_prefix (error, "With policy root '%s': selabel_open(SELABEL_CTX_FILE)",
policy_rootpath);

{
char *con = NULL;
if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"With policy root '%s': Failed to look up context of /: %s",
gs_file_get_path_cached (etc_selinux_dir),
strerror (errno));
goto out;
}
freecon (con);
}
char *con = NULL;
if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0)
return glnx_throw_errno_prefix (error, "With policy root '%s': Failed to look up context of /",
policy_rootpath);
freecon (con);

if (!get_policy_checksum (&self->selinux_policy_csum, cancellable, error))
{
g_prefix_error (error, "While calculating SELinux checksum: ");
goto out;
}
return g_prefix_error (error, "While calculating SELinux checksum: "), FALSE;

self->selinux_policy_name = g_steal_pointer (&policytype);
self->selinux_policy_root = g_object_ref (etc_selinux_dir);
}

ret = TRUE;
out:
return ret;
#else
return TRUE;
#endif
return TRUE;
}

static void
Expand Down Expand Up @@ -580,11 +558,7 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
GError **error)
{
#ifdef HAVE_SELINUX
gboolean ret = FALSE;
g_autoptr(GFileInfo) src_info = NULL;
g_autofree char *label = NULL;
gboolean do_relabel = TRUE;

if (info != NULL)
src_info = g_object_ref (info);
else
Expand All @@ -593,9 +567,10 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (!src_info)
goto out;
return FALSE;
}

gboolean do_relabel = TRUE;
if (flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING)
{
char *existing_con = NULL;
Expand All @@ -607,42 +582,31 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
}
}

g_autofree char *label = NULL;
if (do_relabel)
{
if (!ostree_sepolicy_get_label (self, path,
if (!ostree_sepolicy_get_label (self, path,
g_file_info_get_attribute_uint32 (src_info, "unix::mode"),
&label,
cancellable, error))
goto out;
return FALSE;

if (!label)
{
if (!(flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No label found for '%s'", path);
goto out;
}
return glnx_throw (error, "No label found for '%s'", path);
}
else
{
int res = lsetfilecon (gs_file_get_path_cached (target), label);
if (res != 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (lsetfilecon (gs_file_get_path_cached (target), label) < 0)
return glnx_throw_errno_prefix (error, "lsetfilecon");
}
}

ret = TRUE;
if (out_new_label)
*out_new_label = g_steal_pointer (&label);
out:
return ret;
#else
return TRUE;
#endif
return TRUE;
}

/**
Expand All @@ -660,7 +624,6 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
GError **error)
{
#ifdef HAVE_SELINUX
gboolean ret = FALSE;
g_autofree char *label = NULL;

/* setfscreatecon() will bomb out if the host has SELinux disabled,
Expand All @@ -669,24 +632,17 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
* request. To correctly handle the case of disabled host but
* enabled target will require nontrivial work.
*/
if (!self->runtime_enabled)
if (!cached_is_selinux_enabled ())
return TRUE;

if (!ostree_sepolicy_get_label (self, path, mode, &label, NULL, error))
goto out;
return FALSE;

if (setfscreatecon_raw (label) != 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno_prefix (error, "setfscreatecon");

ret = TRUE;
out:
return ret;
#else
return TRUE;
#endif
return TRUE;
}

/**
Expand Down