From ee68159264f3adeaab0cec0053cfdfab941670d0 Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Fri, 27 Oct 2023 10:12:57 +0800 Subject: [PATCH 1/3] Add `sysusers` option in treefile Default is `false`, if `true`: - turns off nss-altfiles support - disables the passwd / group files migration to /usr/lib Xref to https://github.com/coreos/fedora-coreos-tracker/issues/155#issuecomment-1781289749 --- docs/treefile.md | 4 ++++ rpmostree-cxxrs.cxx | 10 ++++++++++ rpmostree-cxxrs.h | 1 + rust/src/lib.rs | 1 + rust/src/treefile.rs | 7 +++++++ src/libpriv/rpmostree-postprocess.cxx | 19 ++++++++++++------- 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/docs/treefile.md b/docs/treefile.md index 8a8979410b..302eae1d4d 100644 --- a/docs/treefile.md +++ b/docs/treefile.md @@ -36,6 +36,10 @@ It supports the following parameters: * `selinux`: boolean, optional: Defaults to `true`. If `false`, then no SELinux labeling will be performed on the server side. + * `sysusers`: boolean, optional: Defaults to `false`. + If `true`, this turns off `altfiles` and disables the `passwd` / `group` + files migration to `/usr/lib`. + * `ima`: boolean, optional: Defaults to `false`. Propagate any IMA signatures in input RPMs into the final OSTree commit. diff --git a/rpmostree-cxxrs.cxx b/rpmostree-cxxrs.cxx index 4dd46f6923..1e4bb1baa1 100644 --- a/rpmostree-cxxrs.cxx +++ b/rpmostree-cxxrs.cxx @@ -1749,6 +1749,7 @@ struct Treefile final : public ::rust::Opaque bool get_recommends () const noexcept; bool get_selinux () const noexcept; ::std::uint32_t get_selinux_label_version () const noexcept; + bool get_sysusers () const noexcept; ::rust::String get_gpg_key () const noexcept; ::rust::String get_automatic_version_suffix () const noexcept; bool get_container () const noexcept; @@ -2592,6 +2593,9 @@ extern "C" ::std::uint32_t rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version ( ::rpmostreecxx::Treefile const &self) noexcept; + bool + rpmostreecxx$cxxbridge1$Treefile$get_sysusers (::rpmostreecxx::Treefile const &self) noexcept; + void rpmostreecxx$cxxbridge1$Treefile$get_gpg_key (::rpmostreecxx::Treefile const &self, ::rust::String *return$) noexcept; @@ -5143,6 +5147,12 @@ Treefile::get_selinux_label_version () const noexcept return rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version (*this); } +bool +Treefile::get_sysusers () const noexcept +{ + return rpmostreecxx$cxxbridge1$Treefile$get_sysusers (*this); +} + ::rust::String Treefile::get_gpg_key () const noexcept { diff --git a/rpmostree-cxxrs.h b/rpmostree-cxxrs.h index ce564475a4..ab3af95e94 100644 --- a/rpmostree-cxxrs.h +++ b/rpmostree-cxxrs.h @@ -1531,6 +1531,7 @@ struct Treefile final : public ::rust::Opaque bool get_recommends () const noexcept; bool get_selinux () const noexcept; ::std::uint32_t get_selinux_label_version () const noexcept; + bool get_sysusers () 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 b18cd89122..55b552e110 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -608,6 +608,7 @@ pub mod ffi { fn get_recommends(&self) -> bool; fn get_selinux(&self) -> bool; fn get_selinux_label_version(&self) -> u32; + fn get_sysusers(&self) -> bool; 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 7528b9b0d3..9113acce5b 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -417,6 +417,7 @@ fn treefile_merge(dest: &mut TreeComposeConfig, src: &mut TreeComposeConfig) { rojig, selinux, selinux_label_version, + sysusers, ima, gpg_key, include, @@ -1337,6 +1338,10 @@ impl Treefile { self.parsed.base.selinux_label_version.unwrap_or_default() } + pub(crate) fn get_sysusers(&self) -> bool { + self.parsed.base.sysusers.unwrap_or(false) + } + pub(crate) fn get_gpg_key(&self) -> String { self.parsed.base.gpg_key.clone().unwrap_or_default() } @@ -2484,6 +2489,8 @@ pub(crate) struct BaseComposeConfigFields { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) selinux_label_version: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) sysusers: 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/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index 0b0b33d4ce..383921772c 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -406,16 +406,21 @@ postprocess_final (int rootfs_dfd, rpmostreecxx::Treefile &treefile, gboolean un auto container = treefile.get_container (); - g_print ("Migrating /usr/etc/passwd to /usr/lib/\n"); - ROSCXX_TRY (migrate_passwd_except_root (rootfs_dfd), error); + bool sysusers = treefile.get_sysusers (); - rust::Vec preserve_groups_set = treefile.get_etc_group_members (); + if (!sysusers) + { + g_print ("Migrating /usr/etc/passwd to /usr/lib/\n"); + ROSCXX_TRY (migrate_passwd_except_root (rootfs_dfd), error); + + rust::Vec preserve_groups_set = treefile.get_etc_group_members (); - g_print ("Migrating /usr/etc/group to /usr/lib/\n"); - ROSCXX_TRY (migrate_group_except_root (rootfs_dfd, preserve_groups_set), error); + g_print ("Migrating /usr/etc/group to /usr/lib/\n"); + ROSCXX_TRY (migrate_group_except_root (rootfs_dfd, preserve_groups_set), error); - /* NSS configuration to look at the new files */ - ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd), error); + /* NSS configuration to look at the new files */ + ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd), error); + } if (selinux) { From a9c572aa950e633d6b3dd4bcc05011ebf6b67efe Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Tue, 31 Oct 2023 11:34:49 +0800 Subject: [PATCH 2/3] passwd.rs: add condition when adding `passwd/group` content --- rust/src/passwd.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rust/src/passwd.rs b/rust/src/passwd.rs index 100c29fe33..d35ce326da 100644 --- a/rust/src/passwd.rs +++ b/rust/src/passwd.rs @@ -614,6 +614,7 @@ fn complete_pwgrp(rootfs: &Dir) -> Result<()> { /// This is a pre-commit validation hook which ensures that the upcoming /// users/groups entries are somehow sane. See treefile `check-passwd` and /// `check-groups` fields for a description of available validation knobs. +#[context("Validate users/groups refer to treefile check-passwd/check-groups configuration")] pub fn check_passwd_group_entries( ffi_repo: &crate::ffi::OstreeRepo, rootfs_dfd: i32, @@ -630,8 +631,12 @@ pub fn check_passwd_group_entries( // Parse entries in the upcoming commit content. let mut new_entities = PasswdEntries::default(); - new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?; - new_entities.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?; + new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/etc/passwd")?; + new_entities.add_group_content(rootfs.as_raw_fd(), "usr/etc/group")?; + if has_usrlib_passwd(&rootfs)? { + new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?; + new_entities.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?; + } // Fetch entries from treefile and previous commit, according to config. // These are used as ground-truth by the validation steps below. @@ -679,9 +684,11 @@ impl PasswdDB { pub(crate) fn populate_new(rootfs: &Dir) -> Result { let mut db = Self::default(); db.add_passwd_content(rootfs.as_raw_fd(), "usr/etc/passwd")?; - db.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?; db.add_group_content(rootfs.as_raw_fd(), "usr/etc/group")?; - db.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?; + if has_usrlib_passwd(&rootfs)? { + db.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?; + db.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?; + } Ok(db) } From 6cbfed7664c82654d24658c5988d19d3abc6cd4a Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Wed, 1 Nov 2023 16:46:52 +0800 Subject: [PATCH 3/3] sysusers: Delete `altfiles` for `passwd:` and `group:` entries --- rpmostree-cxxrs.cxx | 8 ++-- rpmostree-cxxrs.h | 2 +- rust/src/composepost.rs | 56 +++++++++++++++++++++++---- rust/src/lib.rs | 2 +- src/libpriv/rpmostree-postprocess.cxx | 7 ++-- 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/rpmostree-cxxrs.cxx b/rpmostree-cxxrs.cxx index 1e4bb1baa1..4bb77068ee 100644 --- a/rpmostree-cxxrs.cxx +++ b/rpmostree-cxxrs.cxx @@ -2165,7 +2165,8 @@ extern "C" ::rpmostreecxx::Treefile &treefile) noexcept; ::rust::repr::PtrLen - rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd) noexcept; + rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd, + bool sysusers) noexcept; ::rust::repr::PtrLen rpmostreecxx$cxxbridge1$compose_postprocess ( ::std::int32_t rootfs_dfd, ::rpmostreecxx::Treefile &treefile, ::rust::Str next_version, @@ -3945,9 +3946,10 @@ compose_prepare_rootfs (::std::int32_t src_rootfs_dfd, ::std::int32_t dest_rootf } void -composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd) +composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd, bool sysusers) { - ::rust::repr::PtrLen error$ = rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (rootfs_dfd); + ::rust::repr::PtrLen error$ + = rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (rootfs_dfd, sysusers); if (error$.ptr) { throw ::rust::impl< ::rust::Error>::error (error$); diff --git a/rpmostree-cxxrs.h b/rpmostree-cxxrs.h index ab3af95e94..090d6ed811 100644 --- a/rpmostree-cxxrs.h +++ b/rpmostree-cxxrs.h @@ -1837,7 +1837,7 @@ void configure_build_repo_from_target (::rpmostreecxx::OstreeRepo const &build_r void compose_prepare_rootfs (::std::int32_t src_rootfs_dfd, ::std::int32_t dest_rootfs_dfd, ::rpmostreecxx::Treefile &treefile); -void composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd); +void composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd, bool sysusers); void compose_postprocess (::std::int32_t rootfs_dfd, ::rpmostreecxx::Treefile &treefile, ::rust::Str next_version, bool unified_core); diff --git a/rust/src/composepost.rs b/rust/src/composepost.rs index cd8e6dab01..d7b33af163 100644 --- a/rust/src/composepost.rs +++ b/rust/src/composepost.rs @@ -640,7 +640,36 @@ fn strip_any_prefix<'a, 'b>(s: &'a str, prefixes: &[&'b str]) -> Option<(&'b str .find_map(|&p| s.strip_prefix(p).map(|r| (p, r))) } +#[context("Delete altfiles for passwd and group entries")] +fn del_altfiles(buf: &str) -> Result { + let mut r = String::with_capacity(buf.len()); + for line in buf.lines() { + let parts = if let Some(p) = strip_any_prefix(line, &["passwd:", "group:"]) { + p + } else { + r.push_str(line); + r.push('\n'); + continue; + }; + let (prefix, rest) = parts; + r.push_str(prefix); + + for elt in rest.split_whitespace() { + if elt == "altfiles" { + // skip altfiles + continue; + } else { + r.push(' '); + r.push_str(elt); + } + } + r.push('\n'); + } + Ok(r) +} + /// Inject `altfiles` after `files` for `passwd:` and `group:` entries. +#[allow(dead_code)] fn add_altfiles(buf: &str) -> Result { let mut r = String::with_capacity(buf.len()); for line in buf.lines() { @@ -677,20 +706,33 @@ fn add_altfiles(buf: &str) -> Result { Ok(r) } -/// Add `altfiles` entries to `nsswitch.conf`. +/// Add or delete `altfiles` entries to `nsswitch.conf`. /// -/// rpm-ostree currently depends on `altfiles` -#[context("Adding altfiles to /etc/nsswitch.conf")] -pub fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> CxxResult<()> { +/// rpm-ostree currently depends on `altfiles`, should remove it when +/// transfer to systemd-sysusers. +#[context("Adding / deleting altfiles to /etc/nsswitch.conf")] +pub fn composepost_nsswitch_altfiles(rootfs_dfd: i32, sysusers: bool) -> CxxResult<()> { let rootfs_dfd = unsafe { &crate::ffiutil::ffi_dirfd(rootfs_dfd)? }; let path = "usr/etc/nsswitch.conf"; if let Some(meta) = rootfs_dfd.symlink_metadata_optional(path)? { // If it's a symlink, then something else e.g. authselect must own it. + // Do nothing if disable systemd-sysusers. if meta.is_symlink() { - return Ok(()); + if !sysusers { + return Ok(()); + } } - let nsswitch = rootfs_dfd.read_to_string(path)?; - let nsswitch = add_altfiles(&nsswitch)?; + // Delete the symlink, create and update the config. + let target = "usr/etc/authselect/nsswitch.conf"; + let nsswitch = rootfs_dfd + .read_to_string(target) + .with_context(|| format!("Reading target {}", target))?; + rootfs_dfd + .remove_file(path) + .with_context(|| format!("Removing {}", path))?; + rootfs_dfd.create(path)?; + + let nsswitch = del_altfiles(&nsswitch)?; rootfs_dfd.atomic_write(path, nsswitch.as_bytes())?; } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 55b552e110..b735513fd6 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -282,7 +282,7 @@ pub mod ffi { dest_rootfs_dfd: i32, treefile: &mut Treefile, ) -> Result<()>; - fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>; + fn composepost_nsswitch_altfiles(rootfs_dfd: i32, sysusers: bool) -> Result<()>; fn compose_postprocess( rootfs_dfd: i32, treefile: &mut Treefile, diff --git a/src/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index 383921772c..716bc35abb 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -417,11 +417,12 @@ postprocess_final (int rootfs_dfd, rpmostreecxx::Treefile &treefile, gboolean un g_print ("Migrating /usr/etc/group to /usr/lib/\n"); ROSCXX_TRY (migrate_group_except_root (rootfs_dfd, preserve_groups_set), error); - - /* NSS configuration to look at the new files */ - ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd), error); } + /* NSS configuration to look at the new files. */ + /* Should remove altfiles if we transfer to systemd-sysusers. */ + ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd, sysusers), error); + if (selinux) { if (!postprocess_selinux_policy_store_location (rootfs_dfd, cancellable, error))