diff --git a/src/daemon/rpmostree-sysroot-upgrader.c b/src/daemon/rpmostree-sysroot-upgrader.c index 1949cad482..434db08e71 100644 --- a/src/daemon/rpmostree-sysroot-upgrader.c +++ b/src/daemon/rpmostree-sysroot-upgrader.c @@ -27,6 +27,7 @@ #include "rpmostree-sysroot-upgrader.h" #include "rpmostree-core.h" #include "rpmostree-rpm-util.h" +#include "rpmostree-postprocess.h" #include "ostree-repo.h" @@ -931,6 +932,16 @@ overlay_final_pkgset (RpmOstreeSysrootUpgrader *self, hif_context_set_repo_dir (hifctx, reposdir); } + /* load the sepolicy to use during import */ + { + glnx_unref_object OstreeSePolicy *sepolicy = NULL; + if (!rpmostree_prepare_rootfs_get_sepolicy (tmprootfs_dfd, ".", &sepolicy, + cancellable, error)) + goto out; + + rpmostree_context_set_sepolicy (ctx, sepolicy); + } + /* --- Downloading metadata --- */ if (!rpmostree_context_download_metadata (ctx, cancellable, error)) goto out; diff --git a/src/libpriv/rpmostree-core.c b/src/libpriv/rpmostree-core.c index 87fb402a03..22d154ef0e 100644 --- a/src/libpriv/rpmostree-core.c +++ b/src/libpriv/rpmostree-core.c @@ -49,6 +49,7 @@ struct _RpmOstreeContext { HifContext *hifctx; OstreeRepo *ostreerepo; char *dummy_instroot_path; + OstreeSePolicy *sepolicy; }; G_DEFINE_TYPE (RpmOstreeContext, rpmostree_context, G_TYPE_OBJECT) @@ -91,6 +92,8 @@ rpmostree_context_finalize (GObject *object) g_clear_object (&rctx->ostreerepo); + g_clear_object (&rctx->sepolicy); + G_OBJECT_CLASS (rpmostree_context_parent_class)->finalize (object); } @@ -254,11 +257,21 @@ rpmostree_context_new_unprivileged (int userroot_dfd, /* XXX: or put this in new_system() instead? */ void rpmostree_context_set_repo (RpmOstreeContext *self, - OstreeRepo *repo) + OstreeRepo *repo) { g_set_object (&self->ostreerepo, repo); } +/* I debated making this part of the treespec. Overall, I think it makes more + * sense to define it outside since the policy to use depends on the context in + * which the RpmOstreeContext is used, not something we can always guess on our + * own correctly. */ +void +rpmostree_context_set_sepolicy (RpmOstreeContext *self, + OstreeSePolicy *sepolicy) +{ + g_set_object (&self->sepolicy, sepolicy); +} HifContext * rpmostree_context_get_hif (RpmOstreeContext *self) @@ -1096,12 +1109,13 @@ rpmostree_context_download_rpms (RpmOstreeContext *ctx, } static gboolean -import_one_package (OstreeRepo *ostreerepo, - int tmpdir_dfd, - HifContext *hifctx, - HifPackage * pkg, - GCancellable *cancellable, - GError **error) +import_one_package (OstreeRepo *ostreerepo, + int tmpdir_dfd, + HifContext *hifctx, + HifPackage *pkg, + OstreeSePolicy *sepolicy, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; g_autofree char *ostree_commit = NULL; @@ -1123,8 +1137,8 @@ import_one_package (OstreeRepo *ostreerepo, if (!unpacker) goto out; - if (!rpmostree_unpacker_unpack_to_ostree (unpacker, ostreerepo, NULL, &ostree_commit, - cancellable, error)) + if (!rpmostree_unpacker_unpack_to_ostree (unpacker, ostreerepo, sepolicy, + &ostree_commit, cancellable, error)) { g_autofree char *nevra = hif_package_get_nevra (pkg); g_prefix_error (error, "Unpacking %s: ", nevra); @@ -1206,7 +1220,7 @@ rpmostree_context_download_import (RpmOstreeContext *self, { HifPackage *pkg = install->packages_to_download->pdata[i]; if (!import_one_package (self->ostreerepo, pkg_tempdir_dfd, hifctx, pkg, - cancellable, error)) + self->sepolicy, cancellable, error)) goto out; hif_state_assert_done (hifstate); } diff --git a/src/libpriv/rpmostree-core.h b/src/libpriv/rpmostree-core.h index af520a51c9..414a92e08c 100644 --- a/src/libpriv/rpmostree-core.h +++ b/src/libpriv/rpmostree-core.h @@ -60,7 +60,9 @@ gboolean rpmostree_context_setup (RpmOstreeContext *self, GError **error); void rpmostree_context_set_repo (RpmOstreeContext *self, - OstreeRepo *repo); + OstreeRepo *repo); +void rpmostree_context_set_sepolicy (RpmOstreeContext *self, + OstreeSePolicy *sepolicy); void rpmostree_hif_add_checksum_goal (GChecksum *checksum, HyGoal goal); char *rpmostree_context_get_state_sha512 (RpmOstreeContext *self); diff --git a/src/libpriv/rpmostree-postprocess.c b/src/libpriv/rpmostree-postprocess.c index 3fad9c4745..5059618574 100644 --- a/src/libpriv/rpmostree-postprocess.c +++ b/src/libpriv/rpmostree-postprocess.c @@ -706,7 +706,7 @@ workaround_selinux_cross_labeling_recurse (int dfd, return ret; } -static gboolean +gboolean rpmostree_prepare_rootfs_get_sepolicy (int dfd, const char *path, OstreeSePolicy **out_sepolicy, diff --git a/src/libpriv/rpmostree-postprocess.h b/src/libpriv/rpmostree-postprocess.h index 089b892fba..47866a8bcf 100644 --- a/src/libpriv/rpmostree-postprocess.h +++ b/src/libpriv/rpmostree-postprocess.h @@ -36,6 +36,13 @@ rpmostree_rootfs_postprocess_common (int rootfs_fd, GCancellable *cancellable, GError **error); +gboolean +rpmostree_prepare_rootfs_get_sepolicy (int dfd, + const char *path, + OstreeSePolicy **out_sepolicy, + GCancellable *cancellable, + GError **error); + gboolean rpmostree_prepare_rootfs_for_commit (GFile *rootfs, JsonObject *treefile, diff --git a/src/libpriv/rpmostree-unpacker.c b/src/libpriv/rpmostree-unpacker.c index 5487a6dfda..9cb1694c25 100644 --- a/src/libpriv/rpmostree-unpacker.c +++ b/src/libpriv/rpmostree-unpacker.c @@ -711,15 +711,34 @@ import_one_libarchive_entry_to_ostree (RpmOstreeUnpacker *self, cap_t_to_vfs (caps, &vfscap, &vfscap_size); vfsbytes = g_bytes_new (&vfscap, vfscap_size); - + g_variant_builder_add (&xattr_builder, "(@ay@ay)", g_variant_new_bytestring ("security.capability"), g_variant_new_from_bytes ((GVariantType*)"ay", vfsbytes, - FALSE)); + FALSE)); } } + // fetch the selinux label + if (sepolicy) + { + g_autofree char *label = NULL; + g_autoptr(GFileInfo) file_info = + _rpmostree_libarchive_to_file_info (entry); + g_autofree char *fullpath = g_strdup_printf ("/%s", pathname); + + if (!ostree_sepolicy_get_label (sepolicy, fullpath, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + &label, cancellable, error)) + goto out; + + if (label) + g_variant_builder_add (&xattr_builder, "(@ay@ay)", + g_variant_new_bytestring ("security.selinux"), + g_variant_new_bytestring (label)); + } + if (!pathname[0]) { parent = NULL; @@ -917,7 +936,7 @@ rpmostree_unpacker_unpack_to_ostree (RpmOstreeUnpacker *self, g_autoptr(GHashTable) rpmfi_overrides = NULL; g_autoptr(GHashTable) hardlinks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - g_autofree char *default_dir_checksum = NULL; + g_autofree char *default_dir_checksum = NULL; g_autoptr(GFile) root = NULL; glnx_unref_object OstreeMutableTree *mtree = NULL; g_autoptr(GBytes) header_bytes = NULL; @@ -928,17 +947,17 @@ rpmostree_unpacker_unpack_to_ostree (RpmOstreeUnpacker *self, rpmfi_overrides = build_rpmfi_overrides (self); - g_assert (sepolicy == NULL); - - /* Default directories are 0/0/0755, and right now we're ignoring - * SELinux. (This might be a problem for /etc, but in practice - * anything with nontrivial perms should be in the packages) - */ + /* Default directories are 0/0/0755. We're not ignoring SELinux, but we still + * need to create any parent dirs as they come since we don't have a proper + * rootfs tree. A better solution might be to just copy from e.g. the current + * deployment. In practice, this won't make a difference when we're overlaying + * over an existing rootfs. + * */ { glnx_unref_object GFileInfo *default_dir_perms = g_file_info_new (); g_file_info_set_attribute_uint32 (default_dir_perms, "unix::uid", 0); g_file_info_set_attribute_uint32 (default_dir_perms, "unix::gid", 0); g_file_info_set_attribute_uint32 (default_dir_perms, "unix::mode", 0755 | S_IFDIR); - + if (!write_directory_meta (repo, default_dir_perms, NULL, &default_dir_checksum, cancellable, error)) goto out; @@ -951,18 +970,23 @@ rpmostree_unpacker_unpack_to_ostree (RpmOstreeUnpacker *self, ostree_mutable_tree_set_metadata_checksum (mtree, default_dir_checksum); { g_autoptr(GBytes) metadata = NULL; - + if (!get_lead_sig_header_as_bytes (self, &metadata, cancellable, error)) goto out; g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.metadata", g_variant_new_from_bytes ((GVariantType*)"ay", metadata, TRUE)); } - + + if (sepolicy) + g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.sepolicy", + g_variant_new_string + (ostree_sepolicy_get_csum (sepolicy))); + while (TRUE) { struct archive_entry *entry; - + if (!next_archive_entry (self->archive, &entry, error)) goto out; if (entry == NULL)