diff --git a/docs/treefile.md b/docs/treefile.md index 854e4257e0..8a8979410b 100644 --- a/docs/treefile.md +++ b/docs/treefile.md @@ -138,6 +138,10 @@ It supports the following parameters: to the UNIX epoch time to be used as the build timestamp. Currently only fully supports the `bdb` backend. Somewhat experimental. + * `selinux-label-version`: integer, optional: When set to `1`, this will + turn on an ostree flag which labels files in `/usr/etc` as if they were in + `/etc`. This is important to aid in having a "transient" `/etc`. + * `cliwrap`: boolean, optional. Defaults to `false`. If enabled, rpm-ostree will replace binaries such as `/usr/bin/rpm` with wrappers that intercept unsafe operations, or adjust functionality. diff --git a/rpmostree-cxxrs.cxx b/rpmostree-cxxrs.cxx index 8b354e096a..4dd46f6923 100644 --- a/rpmostree-cxxrs.cxx +++ b/rpmostree-cxxrs.cxx @@ -1748,6 +1748,7 @@ struct Treefile final : public ::rust::Opaque bool get_documentation () const noexcept; bool get_recommends () const noexcept; bool get_selinux () const noexcept; + ::std::uint32_t get_selinux_label_version () const noexcept; ::rust::String get_gpg_key () const noexcept; ::rust::String get_automatic_version_suffix () const noexcept; bool get_container () const noexcept; @@ -2588,6 +2589,9 @@ extern "C" bool rpmostreecxx$cxxbridge1$Treefile$get_selinux (::rpmostreecxx::Treefile const &self) noexcept; + ::std::uint32_t rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version ( + ::rpmostreecxx::Treefile const &self) noexcept; + void rpmostreecxx$cxxbridge1$Treefile$get_gpg_key (::rpmostreecxx::Treefile const &self, ::rust::String *return$) noexcept; @@ -5133,6 +5137,12 @@ Treefile::get_selinux () const noexcept return rpmostreecxx$cxxbridge1$Treefile$get_selinux (*this); } +::std::uint32_t +Treefile::get_selinux_label_version () const noexcept +{ + return rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version (*this); +} + ::rust::String Treefile::get_gpg_key () const noexcept { diff --git a/rpmostree-cxxrs.h b/rpmostree-cxxrs.h index 8736d14131..ce564475a4 100644 --- a/rpmostree-cxxrs.h +++ b/rpmostree-cxxrs.h @@ -1530,6 +1530,7 @@ struct Treefile final : public ::rust::Opaque bool get_documentation () const noexcept; bool get_recommends () const noexcept; bool get_selinux () const noexcept; + ::std::uint32_t get_selinux_label_version () const noexcept; ::rust::String get_gpg_key () const noexcept; ::rust::String get_automatic_version_suffix () const noexcept; bool get_container () const noexcept; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 459131e082..b18cd89122 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -607,6 +607,7 @@ pub mod ffi { fn get_documentation(&self) -> bool; fn get_recommends(&self) -> bool; fn get_selinux(&self) -> bool; + fn get_selinux_label_version(&self) -> u32; fn get_gpg_key(&self) -> String; fn get_automatic_version_suffix(&self) -> String; fn get_container(&self) -> bool; diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index e292fedf90..7528b9b0d3 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -416,6 +416,7 @@ fn treefile_merge(dest: &mut TreeComposeConfig, src: &mut TreeComposeConfig) { basearch, rojig, selinux, + selinux_label_version, ima, gpg_key, include, @@ -1332,6 +1333,10 @@ impl Treefile { self.parsed.base.selinux.unwrap_or(true) } + pub(crate) fn get_selinux_label_version(&self) -> u32 { + self.parsed.base.selinux_label_version.unwrap_or_default() + } + pub(crate) fn get_gpg_key(&self) -> String { self.parsed.base.gpg_key.clone().unwrap_or_default() } @@ -1480,6 +1485,10 @@ impl Treefile { { bail!(r#"Treefile repo var "basearch" invalid; it is automatically filled in"#); } + match config.selinux_label_version.unwrap_or_default() { + 0 | 1 => {} + o => anyhow::bail!("Invalid selinux-label-version: {o}"), + } Ok(()) } @@ -2473,6 +2482,8 @@ pub(crate) struct BaseComposeConfigFields { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) selinux: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) selinux_label_version: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) ima: Option, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) gpg_key: Option, diff --git a/src/app/rpmostree-compose-builtin-tree.cxx b/src/app/rpmostree-compose-builtin-tree.cxx index 2574db4d8d..41c87dd340 100644 --- a/src/app/rpmostree-compose-builtin-tree.cxx +++ b/src/app/rpmostree-compose-builtin-tree.cxx @@ -1135,7 +1135,6 @@ static gboolean impl_commit_tree (RpmOstreeTreeComposeContext *self, GCancellable *cancellable, GError **error) { auto gpgkey = (*self->treefile_rs)->get_gpg_key (); - auto selinux = (*self->treefile_rs)->get_selinux (); /* pick up any initramfs regeneration args to shove into the metadata */ JsonNode *initramfs_args = json_object_get_member (self->treefile, "initramfs-args"); @@ -1211,8 +1210,19 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self, GCancellable *cancellable, if (!gpgkey.empty ()) gpgkey_c = gpgkey.c_str (); auto container = (*self->treefile_rs)->get_container (); + RpmOstreeSELinuxMode selinux_mode; + { + auto selinux = (*self->treefile_rs)->get_selinux (); + auto selinux_label_version = (*self->treefile_rs)->get_selinux_label_version (); + if (selinux && selinux_label_version == 1) + selinux_mode = RPMOSTREE_SELINUX_MODE_V1; + else if (selinux) + selinux_mode = RPMOSTREE_SELINUX_MODE_V0; + else + selinux_mode = RPMOSTREE_SELINUX_MODE_DISABLED; + } if (!rpmostree_compose_commit (self->rootfs_dfd, self->build_repo, parent_revision, metadata, - detached_metadata, gpgkey_c, container, selinux, + detached_metadata, gpgkey_c, container, selinux_mode, self->devino_cache, &new_revision, cancellable, error)) return glnx_prefix_error (error, "Writing commit"); g_assert (new_revision != NULL); diff --git a/src/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index 761ff20b9e..0b0b33d4ce 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -761,16 +761,19 @@ on_progress_timeout (gpointer datap) gboolean rpmostree_compose_commit (int rootfs_fd, OstreeRepo *repo, const char *parent_revision, GVariant *src_metadata, GVariant *detached_metadata, - const char *gpg_keyid, gboolean container, gboolean enable_selinux, + const char *gpg_keyid, gboolean container, RpmOstreeSELinuxMode selinux, OstreeRepoDevInoCache *devino_cache, char **out_new_revision, GCancellable *cancellable, GError **error) { + int label_modifier_flags = 0; g_autoptr (OstreeSePolicy) sepolicy = NULL; - if (enable_selinux) + if (selinux != RPMOSTREE_SELINUX_MODE_DISABLED) { sepolicy = ostree_sepolicy_new_at (rootfs_fd, cancellable, error); if (!sepolicy) return FALSE; + if (selinux == RPMOSTREE_SELINUX_MODE_V1) + label_modifier_flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SELINUX_LABEL_V1; } g_autoptr (OstreeMutableTree) mtree = ostree_mutable_tree_new (); @@ -783,7 +786,7 @@ rpmostree_compose_commit (int rootfs_fd, OstreeRepo *repo, const char *parent_re */ auto modifier_flags = static_cast ( OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED - | OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME); + | OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME | label_modifier_flags); /* If changing this, also look at changing rpmostree-unpacker.c */ g_autoptr (OstreeRepoCommitModifier) commit_modifier = ostree_repo_commit_modifier_new (modifier_flags, NULL, NULL, NULL); @@ -794,7 +797,7 @@ rpmostree_compose_commit (int rootfs_fd, OstreeRepo *repo, const char *parent_re if (sepolicy && ostree_sepolicy_get_name (sepolicy) != NULL) ostree_repo_commit_modifier_set_sepolicy (commit_modifier, sepolicy); - else if (enable_selinux) + else if (selinux != RPMOSTREE_SELINUX_MODE_DISABLED) return glnx_throw (error, "SELinux enabled, but no policy found"); if (devino_cache) diff --git a/src/libpriv/rpmostree-postprocess.h b/src/libpriv/rpmostree-postprocess.h index 54f47e185c..d26d0911c8 100644 --- a/src/libpriv/rpmostree-postprocess.h +++ b/src/libpriv/rpmostree-postprocess.h @@ -34,12 +34,19 @@ gboolean rpmostree_prepare_rootfs_get_sepolicy (int dfd, OstreeSePolicy **out_se gboolean rpmostree_rootfs_fixup_selinux_store_root (int rootfs_dfd, GCancellable *cancellable, GError **error); +typedef enum +{ + RPMOSTREE_SELINUX_MODE_DISABLED, + RPMOSTREE_SELINUX_MODE_V0, // Enabled + RPMOSTREE_SELINUX_MODE_V1, // Label /usr/etc as /etc +} RpmOstreeSELinuxMode; + gboolean rpmostree_compose_commit (int rootfs_dfd, OstreeRepo *repo, const char *parent, GVariant *metadata, GVariant *detached_metadata, const char *gpg_keyid, gboolean container, - gboolean enable_selinux, OstreeRepoDevInoCache *devino_cache, - char **out_new_revision, GCancellable *cancellable, - GError **error); + RpmOstreeSELinuxMode selinux, + OstreeRepoDevInoCache *devino_cache, char **out_new_revision, + GCancellable *cancellable, GError **error); G_END_DECLS diff --git a/tests/compose/test-misc-tweaks.sh b/tests/compose/test-misc-tweaks.sh index 2ea96450ec..3630e31995 100755 --- a/tests/compose/test-misc-tweaks.sh +++ b/tests/compose/test-misc-tweaks.sh @@ -40,6 +40,7 @@ documentation: true EOF cat > config/other.yaml <<'EOF' recommends: true +selinux-label-version: 1 readonly-executables: true container-cmd: - /usr/bin/bash @@ -135,6 +136,10 @@ export treefile=${new_treefile} runcompose echo "ok compose" +ostree --repo=${repo} ls -X ${treeref} /usr/etc/sysctl.conf > ls.txt +assert_file_has_content ls.txt ':system_conf_t:' +echo "ok selinux-label-version" + # Tests for docs ostree --repo=${repo} ls -R ${treeref} /usr/share/man > manpages.txt assert_file_has_content manpages.txt man5/ostree.repo.5