From 81748857bd6c067807d8872f9cd03f4ec61cccfd Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Thu, 1 Feb 2018 22:10:47 +0000 Subject: [PATCH] bin/checkout: add --selinux-policy switch This was already supported by the underlying API. Expose it so that we can test it. Closes: #1442 Approved by: cgwalters --- src/ostree/ot-builtin-checkout.c | 39 +++++++++++++++++-- tests/installed/itest-label-selinux.sh | 53 ++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index 533cfd7d..db5507e7 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -46,6 +46,8 @@ static gboolean opt_disable_fsync; static gboolean opt_require_hardlinks; static gboolean opt_force_copy; static gboolean opt_bareuseronly_dirs; +static char *opt_selinux_policy; +static char *opt_selinux_prefix; static gboolean parse_fsync_cb (const char *option_name, @@ -57,7 +59,7 @@ parse_fsync_cb (const char *option_name, if (!ot_parse_boolean (value, &val, error)) return FALSE; - + opt_disable_fsync = !val; return TRUE; @@ -83,6 +85,8 @@ static GOptionEntry options[] = { { "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL }, { "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL }, { "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL }, + { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /); implies --force-copy", "PATH" }, + { "selinux-prefix", 0, 0, G_OPTION_ARG_STRING, &opt_selinux_prefix, "When setting SELinux labels, prefix all paths by PREFIX", "PREFIX" }, { NULL } }; @@ -102,10 +106,15 @@ process_one_checkout (OstreeRepo *repo, * convenient infrastructure for testing C APIs with data. */ if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || - opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_union_identical) + opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_union_identical || + opt_selinux_policy || opt_selinux_prefix) { OstreeRepoCheckoutAtOptions options = { 0, }; + /* do this early so option checking also catches force copy conflicts */ + if (opt_selinux_policy) + opt_force_copy = TRUE; + if (opt_user_mode) options.mode = OSTREE_REPO_CHECKOUT_MODE_USER; /* Can't union these */ @@ -132,6 +141,11 @@ process_one_checkout (OstreeRepo *repo, glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy"); goto out; } + if (opt_selinux_prefix && !opt_selinux_policy) + { + glnx_throw (error, "Cannot specify --selinux-prefix without --selinux-policy"); + goto out; + } else if (opt_union) options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; else if (opt_union_add) @@ -150,6 +164,23 @@ process_one_checkout (OstreeRepo *repo, options.process_whiteouts = TRUE; if (subpath) options.subpath = subpath; + + g_autoptr(OstreeSePolicy) policy = 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; + options.sepolicy = policy; + options.sepolicy_prefix = opt_selinux_prefix; + } + options.no_copy_fallback = opt_require_hardlinks; options.force_copy = opt_force_copy; options.bareuseronly_dirs = opt_bareuseronly_dirs; @@ -201,7 +232,7 @@ process_one_checkout (OstreeRepo *repo, cancellable, error)) goto out; } - + ret = TRUE; out: return ret; @@ -234,7 +265,7 @@ process_many_checkouts (OstreeRepo *repo, if (!instream) goto out; } - + datastream = g_data_input_stream_new (instream); while ((revision = g_data_input_stream_read_upto (datastream, "", 1, &len, diff --git a/tests/installed/itest-label-selinux.sh b/tests/installed/itest-label-selinux.sh index 1218a8bc..d6244b3a 100755 --- a/tests/installed/itest-label-selinux.sh +++ b/tests/installed/itest-label-selinux.sh @@ -20,11 +20,56 @@ oldcon=$(getfattr --only-values -m security.selinux ${testbin}) chcon --reference co/usr/bin/bash ${testbin} newcon=$(getfattr --only-values -m security.selinux ${testbin}) assert_not_streq "${oldcon}" "${newcon}" -ostree --repo=/ostree/repo commit -b testbranch --link-checkout-speedup \ +ostree commit -b testbranch --link-checkout-speedup \ --selinux-policy co --tree=dir=co -ostree --repo=/ostree/repo ls -X testbranch /usr/bin/foo-a-generic-binary > ls.txt +ostree ls -X testbranch /usr/bin/foo-a-generic-binary > ls.txt assert_file_has_content ls.txt ${oldcon} -ostree --repo=/ostree/repo fsck +ostree fsck -ostree --repo=/ostree/repo refs --delete testbranch +ostree refs --delete testbranch rm co -rf +echo "ok commit with sepolicy" + +# Now let's check that selinux policy labels can be applied on checkout + +rm rootfs -rf +if ostree checkout -H \ + --selinux-policy / ${host_refspec} co; then + assert_not_reached "checked out with -H and --selinux-policy" +fi +# recommit just two binaries into a new branch with selinux labels stripped +mkdir -p rootfs/usr/bin +oldcon=$(getfattr --only-values -m security.selinux /usr/bin/bash) +cp /usr/bin/{true,bash} rootfs/usr/bin +newcon=$(getfattr --only-values -m security.selinux rootfs/usr/bin/bash) +assert_not_streq "${oldcon}" "${newcon}" +echo "ok checkout with sepolicy setup" + +ostree commit -b testbranch rootfs +ostree checkout testbranch --selinux-policy / co +newcon=$(getfattr --only-values -m security.selinux co/usr/bin/bash) +assert_streq "${oldcon}" "${newcon}" +rm co -rf +echo "ok checkout with sepolicy" +ostree checkout testbranch --selinux-policy / --subpath /usr/bin co +newcon=$(getfattr --only-values -m security.selinux co/bash) +assert_streq "${oldcon}" "${newcon}" +rm co -rf +echo "ok checkout with sepolicy and subpath" + +# now commit tree with mismatched leading dirs +mkdir -p rootfs/subdir +mv rootfs/{usr,subdir} +ostree commit -b testbranch rootfs +ostree checkout testbranch --selinux-policy / co +newcon=$(getfattr --only-values -m security.selinux co/subdir/usr/bin/bash) +assert_not_streq "${oldcon}" "${newcon}" +rm co -rf +ostree checkout testbranch --selinux-policy / \ + --subpath subdir --selinux-prefix / co +newcon=$(getfattr --only-values -m security.selinux co/usr/bin/bash) +assert_streq "${oldcon}" "${newcon}" + +ostree refs --delete testbranch +rm co -rf +echo "ok checkout with sepolicy and selinux-prefix"