Skip to content

Commit

Permalink
Merge pull request #2041 from cgwalters/auto-sepolicy
Browse files Browse the repository at this point in the history
 repo/commit: Add support for --selinux-policy-from-base
  • Loading branch information
openshift-merge-robot committed Mar 24, 2020
2 parents bdccbb1 + b3bbbd1 commit 7a95929
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 16 deletions.
1 change: 1 addition & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ ostree_repo_commit_modifier_new
OstreeRepoCommitModifierXattrCallback
ostree_repo_commit_modifier_set_xattr_callback
ostree_repo_commit_modifier_set_sepolicy
ostree_repo_commit_modifier_set_sepolicy_from_commit
ostree_repo_commit_modifier_set_devino_cache
ostree_repo_commit_modifier_ref
ostree_repo_commit_modifier_unref
Expand Down
2 changes: 1 addition & 1 deletion src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2020.2 {
global:
someostree_symbol_deleteme;
ostree_repo_commit_modifier_set_sepolicy_from_commit;
} LIBOSTREE_2020.1;

/* Stub section for the stable release *after* this development one; don't
Expand Down
58 changes: 57 additions & 1 deletion src/libostree/ostree-repo-commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -4227,9 +4227,11 @@ ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier)
if (modifier->xattr_destroy)
modifier->xattr_destroy (modifier->xattr_user_data);

g_clear_object (&modifier->sepolicy);
g_clear_pointer (&modifier->devino_cache, (GDestroyNotify)g_hash_table_unref);

g_clear_object (&modifier->sepolicy);
(void) glnx_tmpdir_delete (&modifier->sepolicy_tmpdir, NULL, NULL);

g_free (modifier);
return;
}
Expand Down Expand Up @@ -4279,6 +4281,60 @@ ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier
modifier->sepolicy = sepolicy ? g_object_ref (sepolicy) : NULL;
}

/**
* ostree_repo_commit_modifier_set_sepolicy_from_commit:
* @modifier: Commit modifier
* @repo: OSTree repo containing @rev
* @rev: Find SELinux policy from this base commit
* @cancellable:
* @error:
*
* In many cases, one wants to create a "derived" commit from base commit.
* SELinux policy labels are part of that base commit. This API allows
* one to easily set up SELinux labeling from a base commit.
*/
gboolean
ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier,
OstreeRepo *repo,
const char *rev,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("setting sepolicy from commit", error);
g_autofree char *commit = NULL;
g_autoptr(GFile) root = NULL;
if (!ostree_repo_read_commit (repo, rev, &root, &commit, cancellable, error))
return FALSE;
const char policypath[] = "usr/etc/selinux";
g_autoptr(GFile) policyroot = g_file_get_child (root, policypath);
if (!g_file_query_exists (policyroot, NULL))
return TRUE; /* No policy, nothing to do */

GLnxTmpDir tmpdir = {0,};
if (!glnx_mkdtemp ("ostree-commit-sepolicy-XXXXXX", 0700, &tmpdir, error))
return FALSE;
if (!glnx_shutil_mkdir_p_at (tmpdir.fd, "usr/etc", 0755, cancellable, error))
return FALSE;

OstreeRepoCheckoutAtOptions coopts = {0,};
coopts.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
coopts.subpath = glnx_strjoina ("/", policypath);

if (!ostree_repo_checkout_at (repo, &coopts, tmpdir.fd, policypath, commit, cancellable, error))
return glnx_prefix_error (error, "policy checkout");

g_autoptr(OstreeSePolicy) policy = ostree_sepolicy_new_at (tmpdir.fd, cancellable, error);
if (!policy)
return glnx_prefix_error (error, "reading policy");

ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
/* Transfer ownership */
modifier->sepolicy_tmpdir = tmpdir;
tmpdir.initialized = FALSE;

return TRUE;
}

/**
* ostree_repo_commit_modifier_set_devino_cache:
* @modifier: Modifier
Expand Down
1 change: 1 addition & 0 deletions src/libostree/ostree-repo-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ struct OstreeRepoCommitModifier {
GDestroyNotify xattr_destroy;
gpointer xattr_user_data;

GLnxTmpDir sepolicy_tmpdir;
OstreeSePolicy *sepolicy;
GHashTable *devino_cache;
};
Expand Down
7 changes: 7 additions & 0 deletions src/libostree/ostree-repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,13 @@ _OSTREE_PUBLIC
void ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier,
OstreeSePolicy *sepolicy);

_OSTREE_PUBLIC
gboolean ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier,
OstreeRepo *repo,
const char *commit,
GCancellable *cancellable,
GError **error);

_OSTREE_PUBLIC
void ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier,
OstreeRepoDevInoCache *cache);
Expand Down
51 changes: 37 additions & 14 deletions src/ostree/ot-builtin-commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static gboolean opt_tar_autocreate_parents;
static char *opt_tar_pathname_filter;
static gboolean opt_no_xattrs;
static char *opt_selinux_policy;
static gboolean opt_selinux_policy_from_base;
static gboolean opt_canonical_permissions;
static gboolean opt_consume;
static gboolean opt_devino_canonical;
Expand Down Expand Up @@ -107,6 +108,7 @@ static GOptionEntry options[] = {
{ "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL },
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL },
{ "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" },
{ "selinux-policy-from-base", 'P', 0, G_OPTION_ARG_NONE, &opt_selinux_policy_from_base, "Set SELinux labels based on first --tree argument", NULL },
{ "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL },
{ "devino-canonical", 'I', 0, G_OPTION_ARG_NONE, &opt_devino_canonical, "Assume hardlinked objects are unmodified. Implies --link-checkout-speedup", NULL },
{ "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
Expand Down Expand Up @@ -550,32 +552,25 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES;
if (opt_disable_fsync)
ostree_repo_set_disable_fsync (repo, TRUE);
if (opt_selinux_policy && opt_selinux_policy_from_base)
{
glnx_throw (error, "Cannot specify both --selinux-policy and --selinux-policy-from-base");
goto out;
}

if (flags != 0
|| opt_owner_uid >= 0
|| opt_owner_gid >= 0
|| opt_statoverride_file != NULL
|| opt_skiplist_file != NULL
|| opt_no_xattrs
|| opt_selinux_policy)
|| opt_selinux_policy
|| opt_selinux_policy_from_base)
{
filter_data.mode_adds = mode_adds;
filter_data.skip_list = skip_list;
modifier = ostree_repo_commit_modifier_new (flags, commit_filter,
&filter_data, NULL);
if (opt_selinux_policy)
{
glnx_autofd int rootfs_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error))
{
g_prefix_error (error, "selinux-policy: ");
goto out;
}
policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
if (!policy)
goto out;
ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
}
}

if (opt_editor)
Expand Down Expand Up @@ -621,6 +616,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
g_assert (opt_trees && *opt_trees);
for (tree_iter = (const char *const*)opt_trees; *tree_iter; tree_iter++)
{
const gboolean first = (tree_iter == (const char *const*)opt_trees);
tree = *tree_iter;

eq = strchr (tree, '=');
Expand All @@ -637,12 +633,33 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
g_clear_object (&object_to_commit);
if (strcmp (tree_type, "dir") == 0)
{
if (first && opt_selinux_policy_from_base)
{
opt_selinux_policy = g_strdup (tree);
opt_selinux_policy_from_base = FALSE;
}
if (first && opt_selinux_policy)
{
g_assert (modifier);
glnx_autofd int rootfs_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error))
goto out;
policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
if (!policy)
goto out;
ostree_repo_commit_modifier_set_sepolicy (modifier, policy);
}
if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier,
cancellable, error))
goto out;
}
else if (strcmp (tree_type, "tar") == 0)
{
if (first && opt_selinux_policy_from_base)
{
glnx_throw (error, "Cannot use --selinux-policy-from-base with tar");
goto out;
}
if (!opt_tar_pathname_filter)
{
if (strcmp (tree, "-") == 0)
Expand Down Expand Up @@ -707,6 +724,12 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
}
else if (strcmp (tree_type, "ref") == 0)
{
if (first && opt_selinux_policy_from_base)
{
g_assert (modifier);
if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, tree, cancellable, error))
goto out;
}
if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error))
goto out;

Expand Down
17 changes: 17 additions & 0 deletions tests/kola/destructive/itest-label-selinux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set -xeuo pipefail

. ${KOLA_EXT_DATA}/libinsttest.sh
require_writable_sysroot
prepare_tmpdir /var/tmp

date
cd /ostree/repo/tmp
Expand Down Expand Up @@ -87,3 +88,19 @@ rm co -rf
ostree refs --delete testbranch
echo "ok checkout selinux and skip-list"
date

mkdir -p usr/{bin,lib,etc}
echo 'somebinary' > usr/bin/somebinary
ls -Z usr/bin/somebinary > lsz.txt
assert_not_file_has_content lsz.txt ':bin_t:'
rm -f lsz.txt
echo 'somelib' > usr/lib/somelib.so
echo 'someconf' > usr/etc/some.conf
ostree commit -b newbase --selinux-policy-from-base --tree=ref=${host_refspec} --tree=dir=$(pwd)
ostree ls -X newbase /usr/bin/somebinary > newls.txt
assert_file_has_content newls.txt ':bin_t:'
ostree ls -X newbase /usr/lib/somelib.so > newls.txt
assert_file_has_content newls.txt ':lib_t:'
ostree ls -X newbase /usr/etc/some.conf > newls.txt
assert_file_has_content newls.txt ':etc_t:'
echo "ok commit --selinux-policy-from-base"

0 comments on commit 7a95929

Please sign in to comment.