mirror of
https://github.com/ostreedev/ostree.git
synced 2024-12-22 17:35:55 +03:00
libostree: Split off SELinux OstreeSePolicy class
It's better if this is independent from the OstreeSysroot; for example, a policy is active in a given deployment root at once, not for a sysroot globally. We can also collect SELinux-related API in one place. Unfortunately at the moment there can be only one instance of this class per process.
This commit is contained in:
parent
cc49096044
commit
3337334be5
@ -27,6 +27,7 @@ libostree_public_headers = \
|
|||||||
src/libostree/ostree-types.h \
|
src/libostree/ostree-types.h \
|
||||||
src/libostree/ostree-repo-file.h \
|
src/libostree/ostree-repo-file.h \
|
||||||
src/libostree/ostree-diff.h \
|
src/libostree/ostree-diff.h \
|
||||||
|
src/libostree/ostree-sepolicy.h \
|
||||||
src/libostree/ostree-sysroot.h \
|
src/libostree/ostree-sysroot.h \
|
||||||
src/libostree/ostree-deployment.h \
|
src/libostree/ostree-deployment.h \
|
||||||
src/libostree/ostree-bootconfig-parser.h \
|
src/libostree/ostree-bootconfig-parser.h \
|
||||||
|
@ -56,6 +56,7 @@ libostree_1_la_SOURCES = \
|
|||||||
src/libostree/ostree-repo-file.c \
|
src/libostree/ostree-repo-file.c \
|
||||||
src/libostree/ostree-repo-file-enumerator.c \
|
src/libostree/ostree-repo-file-enumerator.c \
|
||||||
src/libostree/ostree-repo-file-enumerator.h \
|
src/libostree/ostree-repo-file-enumerator.h \
|
||||||
|
src/libostree/ostree-sepolicy.c \
|
||||||
src/libostree/ostree-sysroot-private.h \
|
src/libostree/ostree-sysroot-private.h \
|
||||||
src/libostree/ostree-sysroot.c \
|
src/libostree/ostree-sysroot.c \
|
||||||
src/libostree/ostree-sysroot-cleanup.c \
|
src/libostree/ostree-sysroot-cleanup.c \
|
||||||
|
@ -1618,6 +1618,8 @@ struct OstreeRepoCommitModifier {
|
|||||||
OstreeRepoCommitModifierXattrCallback xattr_callback;
|
OstreeRepoCommitModifierXattrCallback xattr_callback;
|
||||||
GDestroyNotify xattr_destroy;
|
GDestroyNotify xattr_destroy;
|
||||||
gpointer xattr_user_data;
|
gpointer xattr_user_data;
|
||||||
|
|
||||||
|
OstreeSePolicy *sepolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
OstreeRepoCommitFilterResult
|
OstreeRepoCommitFilterResult
|
||||||
@ -1683,6 +1685,67 @@ apply_commit_filter (OstreeRepo *self,
|
|||||||
return _ostree_repo_commit_modifier_apply (self, modifier, relpath, file_info, out_modified_info);
|
return _ostree_repo_commit_modifier_apply (self, modifier, relpath, file_info, out_modified_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_modified_xattrs (OstreeRepo *self,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
|
const char *relpath,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GFile *path,
|
||||||
|
GVariant **out_xattrs,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_variant GVariant *ret_xattrs = NULL;
|
||||||
|
|
||||||
|
if (modifier && modifier->xattr_callback)
|
||||||
|
{
|
||||||
|
ret_xattrs = modifier->xattr_callback (self, relpath, file_info,
|
||||||
|
modifier->xattr_user_data);
|
||||||
|
}
|
||||||
|
else if (!(modifier && (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS) > 0))
|
||||||
|
{
|
||||||
|
if (!gs_file_get_all_xattrs (path, &ret_xattrs, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier->sepolicy)
|
||||||
|
{
|
||||||
|
gs_free char *label = NULL;
|
||||||
|
|
||||||
|
if (!ostree_sepolicy_get_label (modifier->sepolicy, relpath,
|
||||||
|
g_file_info_get_attribute_uint32 (file_info, "unix::mode"),
|
||||||
|
&label, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
GVariantBuilder *builder;
|
||||||
|
|
||||||
|
if (ret_xattrs)
|
||||||
|
builder = ot_util_variant_builder_from_variant (ret_xattrs,
|
||||||
|
G_VARIANT_TYPE ("a(ayay)"));
|
||||||
|
else
|
||||||
|
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ayay)"));
|
||||||
|
|
||||||
|
g_variant_builder_add_value (builder,
|
||||||
|
g_variant_new ("(@ay@ay)",
|
||||||
|
g_variant_new_bytestring ("security.selinux"),
|
||||||
|
g_variant_new_bytestring (label)));
|
||||||
|
if (ret_xattrs)
|
||||||
|
g_variant_unref (ret_xattrs);
|
||||||
|
|
||||||
|
ret_xattrs = g_variant_builder_end (builder);
|
||||||
|
g_variant_ref_sink (ret_xattrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
gs_transfer_out_value (out_xattrs, &ret_xattrs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
write_directory_to_mtree_internal (OstreeRepo *self,
|
write_directory_to_mtree_internal (OstreeRepo *self,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
@ -1751,16 +1814,10 @@ write_directory_to_mtree_internal (OstreeRepo *self,
|
|||||||
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
|
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
|
||||||
{
|
{
|
||||||
g_debug ("Adding: %s", gs_file_get_path_cached (dir));
|
g_debug ("Adding: %s", gs_file_get_path_cached (dir));
|
||||||
if (modifier && modifier->xattr_callback)
|
if (!get_modified_xattrs (self, modifier, relpath, child_info, dir,
|
||||||
{
|
&xattrs,
|
||||||
xattrs = modifier->xattr_callback (self, relpath, child_info,
|
cancellable, error))
|
||||||
modifier->xattr_user_data);
|
goto out;
|
||||||
}
|
|
||||||
else if (!(modifier && (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS) > 0))
|
|
||||||
{
|
|
||||||
if (!gs_file_get_all_xattrs (dir, &xattrs, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum,
|
if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
@ -1872,17 +1929,11 @@ write_directory_to_mtree_internal (OstreeRepo *self,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifier && modifier->xattr_callback)
|
if (!get_modified_xattrs (self, modifier,
|
||||||
{
|
child_relpath, child_info, child,
|
||||||
xattrs = modifier->xattr_callback (self, child_relpath, child_info,
|
&xattrs,
|
||||||
modifier->xattr_user_data);
|
cancellable, error))
|
||||||
}
|
goto out;
|
||||||
else if (!(modifier && (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS) > 0))
|
|
||||||
{
|
|
||||||
g_clear_pointer (&xattrs, (GDestroyNotify) g_variant_unref);
|
|
||||||
if (!gs_file_get_all_xattrs (child, &xattrs, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ostree_raw_file_to_content_stream (file_input,
|
if (!ostree_raw_file_to_content_stream (file_input,
|
||||||
modified_info, xattrs,
|
modified_info, xattrs,
|
||||||
@ -2082,6 +2133,8 @@ ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier)
|
|||||||
if (modifier->xattr_destroy)
|
if (modifier->xattr_destroy)
|
||||||
modifier->xattr_destroy (modifier->xattr_user_data);
|
modifier->xattr_destroy (modifier->xattr_user_data);
|
||||||
|
|
||||||
|
g_clear_object (&modifier->sepolicy);
|
||||||
|
|
||||||
g_free (modifier);
|
g_free (modifier);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2094,8 +2147,9 @@ ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier)
|
|||||||
* @user_data: Data for @callback:
|
* @user_data: Data for @callback:
|
||||||
*
|
*
|
||||||
* If set, this function should return extended attributes to use for
|
* If set, this function should return extended attributes to use for
|
||||||
* the given path. This is useful for things like SELinux, where a build
|
* the given path. This is useful for things like ACLs and SELinux,
|
||||||
* system can label the files as it's committing to the repository.
|
* where a build system can label the files as it's committing to the
|
||||||
|
* repository.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modifier,
|
ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modifier,
|
||||||
@ -2108,6 +2162,27 @@ ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modif
|
|||||||
modifier->xattr_user_data = user_data;
|
modifier->xattr_user_data = user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_repo_commit_modifier_set_sepolicy:
|
||||||
|
* @modifier: An #OstreeRepoCommitModifier
|
||||||
|
* @sepolicy: (allow-none): Policy to use for labeling
|
||||||
|
*
|
||||||
|
* If @policy is non-%NULL, use it to look up labels to use for
|
||||||
|
* "security.selinux" extended attributes.
|
||||||
|
*
|
||||||
|
* Note that any policy specified this way operates in addition to any
|
||||||
|
* extended attributes provided via
|
||||||
|
* ostree_repo_commit_modifier_set_xattr_callback(). However if both
|
||||||
|
* specify a value for "security.selinux", then the one from the
|
||||||
|
* policy wins.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier,
|
||||||
|
OstreeSePolicy *sepolicy)
|
||||||
|
{
|
||||||
|
g_clear_object (&modifier->sepolicy);
|
||||||
|
modifier->sepolicy = sepolicy ? g_object_ref (sepolicy) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
G_DEFINE_BOXED_TYPE(OstreeRepoCommitModifier, ostree_repo_commit_modifier,
|
G_DEFINE_BOXED_TYPE(OstreeRepoCommitModifier, ostree_repo_commit_modifier,
|
||||||
ostree_repo_commit_modifier_ref,
|
ostree_repo_commit_modifier_ref,
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "ostree-core.h"
|
#include "ostree-core.h"
|
||||||
#include "ostree-types.h"
|
#include "ostree-types.h"
|
||||||
#include "ostree-async-progress.h"
|
#include "ostree-async-progress.h"
|
||||||
|
#include "ostree-sepolicy.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -313,6 +314,9 @@ void ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier
|
|||||||
GDestroyNotify destroy,
|
GDestroyNotify destroy,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
void ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier,
|
||||||
|
OstreeSePolicy *sepolicy);
|
||||||
|
|
||||||
OstreeRepoCommitModifier *ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);
|
OstreeRepoCommitModifier *ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);
|
||||||
void ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
|
void ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
|
||||||
|
|
||||||
|
456
src/libostree/ostree-sepolicy.c
Normal file
456
src/libostree/ostree-sepolicy.c
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
#include <selinux/selinux.h>
|
||||||
|
#include <selinux/label.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "otutil.h"
|
||||||
|
#include "libgsystem.h"
|
||||||
|
|
||||||
|
#include "ostree-sepolicy.h"
|
||||||
|
#include "ostree-bootloader-uboot.h"
|
||||||
|
#include "ostree-bootloader-syslinux.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:libostree-sepolicy
|
||||||
|
* @title: SELinux policy management
|
||||||
|
* @short_description: Read SELinux policy and manage filesystem labels
|
||||||
|
*
|
||||||
|
* A #OstreeSePolicy object can load the SELinux policy from a given
|
||||||
|
* root and perform labeling.
|
||||||
|
*/
|
||||||
|
struct OstreeSePolicy {
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
GFile *path;
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
GFile *selinux_policy_root;
|
||||||
|
struct selabel_handle *selinux_hnd;
|
||||||
|
char *selinux_policy_name;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
} OstreeSePolicyClass;
|
||||||
|
|
||||||
|
static void initable_iface_init (GInitableIface *initable_iface);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
|
||||||
|
PROP_PATH
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (OstreeSePolicy, ostree_sepolicy, G_TYPE_OBJECT,
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
OstreeSePolicy *self = OSTREE_SEPOLICY (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->path);
|
||||||
|
g_clear_object (&self->selinux_policy_root);
|
||||||
|
g_clear_pointer (&self->selinux_policy_name, g_free);
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
if (self->selinux_hnd)
|
||||||
|
{
|
||||||
|
selabel_close (self->selinux_hnd);
|
||||||
|
self->selinux_hnd = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (ostree_sepolicy_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_set_property(GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
OstreeSePolicy *self = OSTREE_SEPOLICY (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_PATH:
|
||||||
|
/* Canonicalize */
|
||||||
|
self->path = g_file_new_for_path (gs_file_get_path_cached (g_value_get_object (value)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_get_property(GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
OstreeSePolicy *self = OSTREE_SEPOLICY (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_PATH:
|
||||||
|
g_value_set_object (value, self->path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
OstreeSePolicy *self = OSTREE_SEPOLICY (object);
|
||||||
|
|
||||||
|
g_assert (self->path != NULL);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (ostree_sepolicy_parent_class)->constructed (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_class_init (OstreeSePolicyClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->constructed = ostree_sepolicy_constructed;
|
||||||
|
object_class->get_property = ostree_sepolicy_get_property;
|
||||||
|
object_class->set_property = ostree_sepolicy_set_property;
|
||||||
|
object_class->finalize = ostree_sepolicy_finalize;
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class,
|
||||||
|
PROP_PATH,
|
||||||
|
g_param_spec_object ("path",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
G_TYPE_FILE,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
initable_init (GInitable *initable,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
OstreeSePolicy *self = OSTREE_SEPOLICY (initable);
|
||||||
|
gs_unref_object GFile *etc_selinux_dir = NULL;
|
||||||
|
gs_unref_object GFile *policy_config_path = NULL;
|
||||||
|
gs_unref_object GFile *policy_root = NULL;
|
||||||
|
gs_unref_object GFileInputStream *filein = NULL;
|
||||||
|
gs_unref_object GDataInputStream *datain = NULL;
|
||||||
|
gboolean enabled = FALSE;
|
||||||
|
char *policytype = NULL;
|
||||||
|
const char *selinux_prefix = "SELINUX=";
|
||||||
|
const char *selinuxtype_prefix = "SELINUXTYPE=";
|
||||||
|
|
||||||
|
etc_selinux_dir = g_file_resolve_relative_path (self->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 (self->path, "usr/etc/selinux");
|
||||||
|
}
|
||||||
|
policy_config_path = g_file_get_child (etc_selinux_dir, "config");
|
||||||
|
|
||||||
|
if (g_file_query_exists (policy_config_path, NULL))
|
||||||
|
{
|
||||||
|
filein = g_file_read (policy_config_path, cancellable, error);
|
||||||
|
if (!filein)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
datain = g_data_input_stream_new ((GInputStream*)filein);
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
gsize len;
|
||||||
|
GError *temp_error = NULL;
|
||||||
|
gs_free 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!line)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (g_str_has_prefix (line, selinuxtype_prefix))
|
||||||
|
{
|
||||||
|
policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix)));
|
||||||
|
policy_root = g_file_get_child (etc_selinux_dir, policytype);
|
||||||
|
}
|
||||||
|
else if (g_str_has_prefix (line, selinux_prefix))
|
||||||
|
{
|
||||||
|
const char *enabled_str = line + strlen (selinux_prefix);
|
||||||
|
if (g_ascii_strncasecmp (enabled_str, "enforcing", strlen ("enforcing")) == 0 ||
|
||||||
|
g_ascii_strncasecmp (enabled_str, "permissive", strlen ("permissive")) == 0)
|
||||||
|
enabled = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->selinux_policy_name = g_strdup (policytype);
|
||||||
|
self->selinux_policy_root = g_object_ref (etc_selinux_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ostree_sepolicy_init (OstreeSePolicy *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initable_iface_init (GInitableIface *initable_iface)
|
||||||
|
{
|
||||||
|
initable_iface->init = initable_init;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_sepolicy_new:
|
||||||
|
* @path: Path to a root directory
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): An accessor object for SELinux policy in root located at @path
|
||||||
|
*/
|
||||||
|
OstreeSePolicy*
|
||||||
|
ostree_sepolicy_new (GFile *path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_initable_new (OSTREE_TYPE_SEPOLICY, cancellable, error, "path", path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_sepolicy_get_path:
|
||||||
|
* @self:
|
||||||
|
*
|
||||||
|
* Returns: (transfer none): Path to rootfs
|
||||||
|
*/
|
||||||
|
GFile *
|
||||||
|
ostree_sepolicy_get_path (OstreeSePolicy *self)
|
||||||
|
{
|
||||||
|
return self->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
ostree_sepolicy_get_name (OstreeSePolicy *self)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
return self->selinux_policy_name;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_sepolicy_get_label:
|
||||||
|
* @self: Self
|
||||||
|
* @relpath: Path
|
||||||
|
* @unix_mode: Unix mode
|
||||||
|
* @out_label: (allow-none) (out) (transfer full): Return location for security context
|
||||||
|
* @cancellable: Cancellable
|
||||||
|
* @error: Error
|
||||||
|
*
|
||||||
|
* Store in @out_label the security context for the given @relpath and
|
||||||
|
* mode @unix_mode. If the policy does not specify a label, %NULL
|
||||||
|
* will be returned.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
ostree_sepolicy_get_label (OstreeSePolicy *self,
|
||||||
|
const char *relpath,
|
||||||
|
guint32 unix_mode,
|
||||||
|
char **out_label,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
int res;
|
||||||
|
char *con = NULL;
|
||||||
|
|
||||||
|
if (self->selinux_hnd)
|
||||||
|
{
|
||||||
|
res = selabel_lookup_raw (self->selinux_hnd, &con, relpath, unix_mode);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
int errsv = errno;
|
||||||
|
if (errsv != ENOENT)
|
||||||
|
{
|
||||||
|
ot_util_set_error_from_errno (error, errsv);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Ensure we consistently allocate with g_malloc */
|
||||||
|
*out_label = g_strdup (con);
|
||||||
|
freecon (con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_sepolicy_restorecon:
|
||||||
|
* @self: Self
|
||||||
|
* @path: Path string to use for policy lookup
|
||||||
|
* @info: (allow-none): File attributes
|
||||||
|
* @target: Physical path to target file
|
||||||
|
* @flags: Flags controlling behavior
|
||||||
|
* @out_new_label: (allow-none) (out): New label, or %NULL if unchanged
|
||||||
|
* @cancellable: Cancellable
|
||||||
|
* @error: Error
|
||||||
|
*
|
||||||
|
* Reset the security context of @target based on the SELinux policy.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
ostree_sepolicy_restorecon (OstreeSePolicy *self,
|
||||||
|
const char *path,
|
||||||
|
GFileInfo *info,
|
||||||
|
GFile *target,
|
||||||
|
OstreeSePolicyRestoreconFlags flags,
|
||||||
|
char **out_new_label,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_object GFileInfo *src_info = NULL;
|
||||||
|
gs_free char *label = NULL;
|
||||||
|
gboolean do_relabel = TRUE;
|
||||||
|
|
||||||
|
if (info != NULL)
|
||||||
|
src_info = g_object_ref (info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src_info = g_file_query_info (target, "unix::mode",
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
cancellable, error);
|
||||||
|
if (!src_info)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING)
|
||||||
|
{
|
||||||
|
char *existing_con = NULL;
|
||||||
|
if (lgetfilecon_raw (gs_file_get_path_cached (target), &existing_con) > 0
|
||||||
|
&& existing_con)
|
||||||
|
{
|
||||||
|
do_relabel = FALSE;
|
||||||
|
freecon (existing_con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_relabel)
|
||||||
|
{
|
||||||
|
if (!ostree_sepolicy_get_label (self, path,
|
||||||
|
g_file_info_get_attribute_uint32 (src_info, "unix::mode"),
|
||||||
|
&label,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int res = lsetfilecon (gs_file_get_path_cached (target), label);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
ot_util_set_error_from_errno (error, errno);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
gs_transfer_out_value (out_new_label, &label);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
66
src/libostree/ostree-sepolicy.h
Normal file
66
src/libostree/ostree-sepolicy.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ostree-types.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define OSTREE_TYPE_SEPOLICY ostree_sepolicy_get_type()
|
||||||
|
#define OSTREE_SEPOLICY(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_SEPOLICY, OstreeSePolicy))
|
||||||
|
#define OSTREE_IS_SEPOLICY(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SEPOLICY))
|
||||||
|
|
||||||
|
GType ostree_sepolicy_get_type (void);
|
||||||
|
|
||||||
|
OstreeSePolicy* ostree_sepolicy_new (GFile *path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
GFile * ostree_sepolicy_get_path (OstreeSePolicy *self);
|
||||||
|
|
||||||
|
const char *ostree_sepolicy_get_name (OstreeSePolicy *self);
|
||||||
|
|
||||||
|
gboolean ostree_sepolicy_get_label (OstreeSePolicy *self,
|
||||||
|
const char *relpath,
|
||||||
|
guint32 unix_mode,
|
||||||
|
char **out_label,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OSTREE_SEPOLICY_RESTORECON_FLAGS_NONE,
|
||||||
|
OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL = (1 << 0),
|
||||||
|
OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING = (1 << 1)
|
||||||
|
} OstreeSePolicyRestoreconFlags;
|
||||||
|
|
||||||
|
gboolean ostree_sepolicy_restorecon (OstreeSePolicy *self,
|
||||||
|
const char *path,
|
||||||
|
GFileInfo *info,
|
||||||
|
GFile *target,
|
||||||
|
OstreeSePolicyRestoreconFlags flags,
|
||||||
|
char **out_new_label,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Colin Walters <walters@verbum.org>
|
* Copyright (C) 2012,2014 Colin Walters <walters@verbum.org>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -16,17 +16,10 @@
|
|||||||
* License along with this library; if not, write to the
|
* License along with this library; if not, write to the
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*
|
|
||||||
* Author: Colin Walters <walters@verbum.org>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
#include <selinux/selinux.h>
|
|
||||||
#include <selinux/label.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ostree-sysroot-private.h"
|
#include "ostree-sysroot-private.h"
|
||||||
#include "ostree-core-private.h"
|
#include "ostree-core-private.h"
|
||||||
#include "otutil.h"
|
#include "otutil.h"
|
||||||
@ -243,74 +236,6 @@ checkout_deployment_tree (OstreeSysroot *sysroot,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
static gboolean
|
|
||||||
get_selinux_policy_root (GFile *deployment_etc,
|
|
||||||
GFile **out_policy_root,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_object GFile *etc_selinux_dir = NULL;
|
|
||||||
gs_unref_object GFile *policy_config_path = NULL;
|
|
||||||
gs_unref_object GFile *ret_policy_root = NULL;
|
|
||||||
gs_unref_object GFileInputStream *filein = NULL;
|
|
||||||
gs_unref_object GDataInputStream *datain = NULL;
|
|
||||||
gboolean enabled = FALSE;
|
|
||||||
char *policytype = NULL;
|
|
||||||
const char *selinux_prefix = "SELINUX=";
|
|
||||||
const char *selinuxtype_prefix = "SELINUXTYPE=";
|
|
||||||
|
|
||||||
etc_selinux_dir = g_file_get_child (deployment_etc, "selinux");
|
|
||||||
policy_config_path = g_file_get_child (etc_selinux_dir, "config");
|
|
||||||
|
|
||||||
if (g_file_query_exists (policy_config_path, NULL))
|
|
||||||
{
|
|
||||||
filein = g_file_read (policy_config_path, cancellable, error);
|
|
||||||
if (!filein)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
datain = g_data_input_stream_new ((GInputStream*)filein);
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
gsize len;
|
|
||||||
GError *temp_error = NULL;
|
|
||||||
gs_free 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!line)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (g_str_has_prefix (line, selinuxtype_prefix))
|
|
||||||
{
|
|
||||||
policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix)));
|
|
||||||
}
|
|
||||||
else if (g_str_has_prefix (line, selinux_prefix))
|
|
||||||
{
|
|
||||||
const char *enabled_str = line + strlen (selinux_prefix);
|
|
||||||
if (g_ascii_strncasecmp (enabled_str, "enforcing", strlen ("enforcing")) == 0 ||
|
|
||||||
g_ascii_strncasecmp (enabled_str, "permissive", strlen ("permissive")) == 0)
|
|
||||||
enabled = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled)
|
|
||||||
ret_policy_root = g_file_get_child (etc_selinux_dir, policytype);
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
gs_transfer_out_value (out_policy_root, &ret_policy_root);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
ptrarray_path_join (GPtrArray *path)
|
ptrarray_path_join (GPtrArray *path)
|
||||||
{
|
{
|
||||||
@ -336,69 +261,43 @@ ptrarray_path_join (GPtrArray *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
relabel_one_path (GFile *path,
|
relabel_one_path (OstreeSysroot *sysroot,
|
||||||
|
OstreeSePolicy *sepolicy,
|
||||||
|
GFile *path,
|
||||||
GFileInfo *info,
|
GFileInfo *info,
|
||||||
GPtrArray *path_parts,
|
GPtrArray *path_parts,
|
||||||
struct selabel_handle *hnd,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
guint32 mode;
|
|
||||||
gs_free char *relpath = NULL;
|
gs_free char *relpath = NULL;
|
||||||
char *con = NULL;
|
|
||||||
|
|
||||||
mode = g_file_info_get_attribute_uint32 (info, "unix::mode");
|
|
||||||
|
|
||||||
relpath = ptrarray_path_join (path_parts);
|
relpath = ptrarray_path_join (path_parts);
|
||||||
|
if (!ostree_sepolicy_restorecon (sepolicy, relpath,
|
||||||
if (selabel_lookup_raw (hnd, &con, relpath, mode) != 0)
|
info, path,
|
||||||
{
|
OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL,
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
NULL,
|
||||||
"selabel_lookup_raw(%s, %u): %s",
|
cancellable, error))
|
||||||
relpath, mode, strerror (errno));
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISLNK (mode))
|
|
||||||
{
|
|
||||||
if (lsetfilecon (gs_file_get_path_cached (path), con) != 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"lsetfilecon(%s): %s",
|
|
||||||
gs_file_get_path_cached (path), strerror (errno));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (setfilecon (gs_file_get_path_cached (path), con) != 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"setfilecon(%s): %s",
|
|
||||||
gs_file_get_path_cached (path), strerror (errno));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
if (con) freecon (con);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
relabel_recursively (GFile *dir,
|
relabel_recursively (OstreeSysroot *sysroot,
|
||||||
|
OstreeSePolicy *sepolicy,
|
||||||
|
GFile *dir,
|
||||||
GFileInfo *dir_info,
|
GFileInfo *dir_info,
|
||||||
GPtrArray *path_parts,
|
GPtrArray *path_parts,
|
||||||
struct selabel_handle *hnd,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
gs_unref_object GFileEnumerator *direnum = NULL;
|
gs_unref_object GFileEnumerator *direnum = NULL;
|
||||||
|
|
||||||
if (!relabel_one_path (dir, dir_info, path_parts, hnd,
|
if (!relabel_one_path (sysroot, sepolicy, dir, dir_info, path_parts,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -425,13 +324,13 @@ relabel_recursively (GFile *dir,
|
|||||||
ftype = g_file_info_get_file_type (file_info);
|
ftype = g_file_info_get_file_type (file_info);
|
||||||
if (ftype == G_FILE_TYPE_DIRECTORY)
|
if (ftype == G_FILE_TYPE_DIRECTORY)
|
||||||
{
|
{
|
||||||
if (!relabel_recursively (child, file_info, path_parts, hnd,
|
if (!relabel_recursively (sysroot, sepolicy, child, file_info, path_parts,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!relabel_one_path (child, file_info, path_parts, hnd,
|
if (!relabel_one_path (sysroot, sepolicy, child, file_info, path_parts,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -444,202 +343,116 @@ relabel_recursively (GFile *dir,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
gboolean have_policy;
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
struct selabel_handle *hnd;
|
|
||||||
#endif
|
|
||||||
} OstreeLabelingContext;
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
init_labeling_context (GFile *deployment_etc,
|
|
||||||
OstreeLabelingContext *secontext,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_object GFile *policy_root = NULL;
|
|
||||||
|
|
||||||
if (!get_selinux_policy_root (deployment_etc, &policy_root,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (policy_root)
|
|
||||||
{
|
|
||||||
secontext->have_policy = TRUE;
|
|
||||||
|
|
||||||
g_print ("ostadmin: Using SELinux policy '%s'\n", gs_file_get_basename_cached (policy_root));
|
|
||||||
|
|
||||||
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 (policy_root),
|
|
||||||
strerror (errno));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
secontext->hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0);
|
|
||||||
if (!secontext->hnd)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"selabel_open(SELABEL_CTX_FILE): %s",
|
|
||||||
strerror (errno));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
secontext->have_policy = FALSE;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
secontext->have_policy = FALSE;
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ostree_labeling_context_cleanup (OstreeLabelingContext *secontext)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
if (secontext->hnd)
|
|
||||||
selabel_close (secontext->hnd);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
selinux_relabel_dir (OstreeSysroot *sysroot,
|
selinux_relabel_dir (OstreeSysroot *sysroot,
|
||||||
OstreeLabelingContext *secontext,
|
OstreeSePolicy *sepolicy,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
const char *prefix,
|
const char *prefix,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
gs_unref_ptrarray GPtrArray *path_parts = g_ptr_array_new ();
|
gs_unref_ptrarray GPtrArray *path_parts = g_ptr_array_new ();
|
||||||
gs_unref_object GFileInfo *root_info = NULL;
|
gs_unref_object GFileInfo *root_info = NULL;
|
||||||
|
|
||||||
if (secontext->have_policy)
|
root_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
cancellable, error);
|
||||||
|
if (!root_info)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_ptr_array_add (path_parts, (char*)prefix);
|
||||||
|
if (!relabel_recursively (sysroot, sepolicy, dir, root_info, path_parts,
|
||||||
|
cancellable, error))
|
||||||
{
|
{
|
||||||
root_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
|
g_prefix_error (error, "Relabeling /%s: ", prefix);
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
goto out;
|
||||||
cancellable, error);
|
|
||||||
if (!root_info)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_ptr_array_add (path_parts, (char*)prefix);
|
|
||||||
if (!relabel_recursively (dir, root_info, path_parts, secontext->hnd,
|
|
||||||
cancellable, error))
|
|
||||||
{
|
|
||||||
g_prefix_error (error, "Relabeling /%s: ", prefix);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
static gboolean
|
static gboolean
|
||||||
selinux_relabel_file (OstreeLabelingContext *secontext,
|
selinux_relabel_file (OstreeSysroot *sysroot,
|
||||||
|
OstreeSePolicy *sepolicy,
|
||||||
GFile *path,
|
GFile *path,
|
||||||
const char *prefix,
|
const char *prefix,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_ptrarray GPtrArray *path_parts = g_ptr_array_new ();
|
||||||
|
gs_unref_object GFileInfo *file_info = g_file_query_info (path, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
cancellable, error);
|
||||||
|
if (!file_info)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (secontext->have_policy)
|
g_ptr_array_add (path_parts, (char*)prefix);
|
||||||
|
g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (path));
|
||||||
|
if (!relabel_one_path (sysroot, sepolicy, path, file_info, path_parts,
|
||||||
|
cancellable, error))
|
||||||
{
|
{
|
||||||
gs_unref_ptrarray GPtrArray *path_parts = g_ptr_array_new ();
|
g_prefix_error (error, "Relabeling /%s/%s: ", prefix,
|
||||||
gs_unref_object GFileInfo *file_info = g_file_query_info (path, OSTREE_GIO_FAST_QUERYINFO,
|
gs_file_get_basename_cached (path));
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
goto out;
|
||||||
cancellable, error);
|
|
||||||
if (!file_info)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_ptr_array_add (path_parts, (char*)prefix);
|
|
||||||
g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (path));
|
|
||||||
if (!relabel_one_path (path, file_info, path_parts, secontext->hnd,
|
|
||||||
cancellable, error))
|
|
||||||
{
|
|
||||||
g_prefix_error (error, "Relabeling /%s/%s: ", prefix,
|
|
||||||
gs_file_get_basename_cached (path));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
|
selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
|
||||||
OstreeLabelingContext *secontext,
|
OstreeSePolicy *sepolicy,
|
||||||
GFile *deployment_var_path,
|
GFile *deployment_var_path,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SELINUX
|
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
/* This is a bit of a hack; we should change the code at some
|
||||||
if (secontext->have_policy)
|
* point in the distant future to only create (and label) /var
|
||||||
{
|
* when doing a deployment.
|
||||||
/* This is a bit of a hack; we should change the code at some
|
*/
|
||||||
* point in the distant future to only create (and label) /var
|
gs_unref_object GFile *deployment_var_labeled =
|
||||||
* when doing a deployment.
|
g_file_get_child (deployment_var_path, ".ostree-selabeled");
|
||||||
*/
|
gs_unref_object GFile *deployment_var_labeled_tmp =
|
||||||
gs_unref_object GFile *deployment_var_labeled =
|
g_file_get_child (deployment_var_path, ".ostree-selabeled.tmp");
|
||||||
g_file_get_child (deployment_var_path, ".ostree-selabeled");
|
|
||||||
gs_unref_object GFile *deployment_var_labeled_tmp =
|
|
||||||
g_file_get_child (deployment_var_path, ".ostree-selabeled.tmp");
|
|
||||||
|
|
||||||
if (!g_file_query_exists (deployment_var_labeled, NULL))
|
if (!g_file_query_exists (deployment_var_labeled, NULL))
|
||||||
|
{
|
||||||
|
g_print ("ostadmin: Didn't find '%s', relabeling /var\n",
|
||||||
|
gs_file_get_path_cached (deployment_var_labeled));
|
||||||
|
|
||||||
|
if (!selinux_relabel_dir (sysroot, sepolicy,
|
||||||
|
deployment_var_path, "var",
|
||||||
|
cancellable, error))
|
||||||
{
|
{
|
||||||
g_print ("ostadmin: Didn't find '%s', relabeling /var\n",
|
g_prefix_error (error, "Relabeling /var: ");
|
||||||
gs_file_get_path_cached (deployment_var_labeled));
|
goto out;
|
||||||
|
|
||||||
if (!selinux_relabel_dir (sysroot, secontext,
|
|
||||||
deployment_var_path, "var",
|
|
||||||
cancellable, error))
|
|
||||||
{
|
|
||||||
g_prefix_error (error, "Relabeling /var: ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_file_replace_contents (deployment_var_labeled_tmp, "", 0, NULL, FALSE,
|
|
||||||
G_FILE_CREATE_REPLACE_DESTINATION, NULL,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!selinux_relabel_file (secontext, deployment_var_labeled_tmp, "var",
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!gs_file_rename (deployment_var_labeled_tmp, deployment_var_labeled,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!g_file_replace_contents (deployment_var_labeled_tmp, "", 0, NULL, FALSE,
|
||||||
|
G_FILE_CREATE_REPLACE_DESTINATION, NULL,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!selinux_relabel_file (sysroot, sepolicy,
|
||||||
|
deployment_var_labeled_tmp, "var",
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!gs_file_rename (deployment_var_labeled_tmp, deployment_var_labeled,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -647,6 +460,7 @@ merge_configuration (OstreeSysroot *sysroot,
|
|||||||
OstreeDeployment *previous_deployment,
|
OstreeDeployment *previous_deployment,
|
||||||
OstreeDeployment *deployment,
|
OstreeDeployment *deployment,
|
||||||
GFile *deployment_path,
|
GFile *deployment_path,
|
||||||
|
OstreeSePolicy **out_sepolicy,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
@ -655,6 +469,7 @@ merge_configuration (OstreeSysroot *sysroot,
|
|||||||
gs_unref_object GFile *source_etc_pristine_path = NULL;
|
gs_unref_object GFile *source_etc_pristine_path = NULL;
|
||||||
gs_unref_object GFile *deployment_usretc_path = NULL;
|
gs_unref_object GFile *deployment_usretc_path = NULL;
|
||||||
gs_unref_object GFile *deployment_etc_path = NULL;
|
gs_unref_object GFile *deployment_etc_path = NULL;
|
||||||
|
gs_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||||
gboolean etc_exists;
|
gboolean etc_exists;
|
||||||
gboolean usretc_exists;
|
gboolean usretc_exists;
|
||||||
|
|
||||||
@ -703,21 +518,26 @@ merge_configuration (OstreeSysroot *sysroot,
|
|||||||
|
|
||||||
if (usretc_exists)
|
if (usretc_exists)
|
||||||
{
|
{
|
||||||
__attribute__((cleanup(ostree_labeling_context_cleanup))) OstreeLabelingContext new_default_secontext = { 0, };
|
|
||||||
|
|
||||||
/* TODO - set out labels as we copy files */
|
/* TODO - set out labels as we copy files */
|
||||||
g_assert (!etc_exists);
|
g_assert (!etc_exists);
|
||||||
if (!gs_shutil_cp_a (deployment_usretc_path, deployment_etc_path,
|
if (!gs_shutil_cp_a (deployment_usretc_path, deployment_etc_path,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!init_labeling_context (deployment_etc_path, &new_default_secontext,
|
/* Here, we initialize SELinux policy from the /usr/etc inside
|
||||||
cancellable, error))
|
* the root - this is before we've finalized the configuration
|
||||||
|
* merge into /etc. */
|
||||||
|
sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error);
|
||||||
|
if (!sepolicy)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!selinux_relabel_dir (sysroot, &new_default_secontext, deployment_etc_path, "etc",
|
if (ostree_sepolicy_get_name (sepolicy) != NULL)
|
||||||
cancellable, error))
|
{
|
||||||
goto out;
|
g_print ("ostadmin: Using SELinux policy '%s'\n", ostree_sepolicy_get_name (sepolicy));
|
||||||
|
if (!selinux_relabel_dir (sysroot, sepolicy, deployment_etc_path, "etc",
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
g_print ("ostadmin: Created %s\n", gs_file_get_path_cached (deployment_etc_path));
|
g_print ("ostadmin: Created %s\n", gs_file_get_path_cached (deployment_etc_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,6 +553,7 @@ merge_configuration (OstreeSysroot *sysroot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
gs_transfer_out_value (out_sepolicy, &sepolicy);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1507,7 +1328,6 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
|||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
gint new_deployserial;
|
gint new_deployserial;
|
||||||
__attribute__((cleanup(ostree_labeling_context_cleanup))) OstreeLabelingContext secontext = { 0, };
|
|
||||||
gs_unref_object OstreeDeployment *new_deployment = NULL;
|
gs_unref_object OstreeDeployment *new_deployment = NULL;
|
||||||
gs_unref_object OstreeDeployment *merge_deployment = NULL;
|
gs_unref_object OstreeDeployment *merge_deployment = NULL;
|
||||||
gs_unref_object OstreeRepo *repo = NULL;
|
gs_unref_object OstreeRepo *repo = NULL;
|
||||||
@ -1518,6 +1338,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
|||||||
gs_unref_object GFile *tree_kernel_path = NULL;
|
gs_unref_object GFile *tree_kernel_path = NULL;
|
||||||
gs_unref_object GFile *tree_initramfs_path = NULL;
|
gs_unref_object GFile *tree_initramfs_path = NULL;
|
||||||
gs_unref_object GFile *new_deployment_path = NULL;
|
gs_unref_object GFile *new_deployment_path = NULL;
|
||||||
|
gs_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||||
gs_free char *new_bootcsum = NULL;
|
gs_free char *new_bootcsum = NULL;
|
||||||
gs_unref_object OstreeBootconfigParser *bootconfig = NULL;
|
gs_unref_object OstreeBootconfigParser *bootconfig = NULL;
|
||||||
|
|
||||||
@ -1590,6 +1411,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
|||||||
|
|
||||||
if (!merge_configuration (self, merge_deployment, new_deployment,
|
if (!merge_configuration (self, merge_deployment, new_deployment,
|
||||||
new_deployment_path,
|
new_deployment_path,
|
||||||
|
&sepolicy,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "During /etc merge: ");
|
g_prefix_error (error, "During /etc merge: ");
|
||||||
@ -1598,10 +1420,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
|||||||
|
|
||||||
deployment_etc = g_file_get_child (new_deployment_path, "etc");
|
deployment_etc = g_file_get_child (new_deployment_path, "etc");
|
||||||
|
|
||||||
if (!init_labeling_context (deployment_etc, &secontext, cancellable, error))
|
if (!selinux_relabel_var_if_needed (self, sepolicy, deployment_var,
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!selinux_relabel_var_if_needed (self, &secontext, deployment_var,
|
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct OstreeRepo OstreeRepo;
|
typedef struct OstreeRepo OstreeRepo;
|
||||||
|
typedef struct OstreeSePolicy OstreeSePolicy;
|
||||||
typedef struct OstreeSysroot OstreeSysroot;
|
typedef struct OstreeSysroot OstreeSysroot;
|
||||||
typedef struct OstreeMutableTree OstreeMutableTree;
|
typedef struct OstreeMutableTree OstreeMutableTree;
|
||||||
typedef struct OstreeRepoFile OstreeRepoFile;
|
typedef struct OstreeRepoFile OstreeRepoFile;
|
||||||
|
Loading…
Reference in New Issue
Block a user