From d2dcf5861e367784be3bb57e40a10e9298dc1f5c Mon Sep 17 00:00:00 2001 From: Joseph Marrero Date: Tue, 9 Apr 2024 09:15:38 -0400 Subject: [PATCH] Fixes RHEL-31951 Backport Backport https://github.com/coreos/rpm-ostree/security/advisories/GHSA-2m76-cwhg-7wv6 Resolves #RHEL-31951 --- 0001-cliwrap-rpm-mark-eval-E-as-safe.patch | 56 ------------- ...ee-ext-add-provisional-repair-entryp.patch | 64 -------------- 0001-unit-chmod-etc-g-shadow-to-0000.patch | 79 ++++++++++++++++++ ...sswd-create-etc-g-shadow-with-mode-0.patch | 83 +++++++++++++++++++ rpm-ostree.spec | 15 +++- 5 files changed, 176 insertions(+), 121 deletions(-) delete mode 100644 0001-cliwrap-rpm-mark-eval-E-as-safe.patch delete mode 100644 0001-main-Update-ostree-ext-add-provisional-repair-entryp.patch create mode 100644 0001-unit-chmod-etc-g-shadow-to-0000.patch create mode 100644 0002-passwd-create-etc-g-shadow-with-mode-0.patch diff --git a/0001-cliwrap-rpm-mark-eval-E-as-safe.patch b/0001-cliwrap-rpm-mark-eval-E-as-safe.patch deleted file mode 100644 index ae137d0..0000000 --- a/0001-cliwrap-rpm-mark-eval-E-as-safe.patch +++ /dev/null @@ -1,56 +0,0 @@ -From d02993e30078db2a04820065ccbf22bd56d0d064 Mon Sep 17 00:00:00 2001 -From: Jonathan Lebon -Date: Thu, 22 Feb 2024 14:44:50 -0500 -Subject: [PATCH] cliwrap/rpm: mark `--eval`/`-E` as safe - -This is sometimes used in scripts to query aspects of the host system. -E.g. this is used by Fedora's pkg-config: - -https://src.fedoraproject.org/rpms/pkgconf/blob/95c0bbee/f/pkg-config.in#_6 - -This in turn gets hit by kdump which runs dracut which has modules that -runs `pkgconf` to query some directory paths. ---- - rust/src/cliwrap/rpm.rs | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/rust/src/cliwrap/rpm.rs b/rust/src/cliwrap/rpm.rs -index c6ed5901..3332f76c 100644 ---- a/rust/src/cliwrap/rpm.rs -+++ b/rust/src/cliwrap/rpm.rs -@@ -19,6 +19,12 @@ fn new_rpm_app() -> Command { - .long("version") - .action(clap::ArgAction::Version), - ) -+ .arg( -+ Arg::new("eval") -+ .long("eval") -+ .short('E') -+ .action(clap::ArgAction::Set), -+ ) - .arg( - Arg::new("package") - .help("package") -@@ -130,6 +136,19 @@ mod tests { - Ok(()) - } - -+ #[test] -+ fn test_eval() -> Result<()> { -+ assert_eq!( -+ disposition(SystemHostType::OstreeHost, &["-E", "%{_target_cpu}"])?, -+ RunDisposition::Ok -+ ); -+ assert_eq!( -+ disposition(SystemHostType::OstreeHost, &["--eval=%{_target_cpu}}"])?, -+ RunDisposition::Ok -+ ); -+ Ok(()) -+ } -+ - #[test] - fn test_query_file() -> Result<()> { - assert_eq!( --- -2.43.2 - diff --git a/0001-main-Update-ostree-ext-add-provisional-repair-entryp.patch b/0001-main-Update-ostree-ext-add-provisional-repair-entryp.patch deleted file mode 100644 index bec3be8..0000000 --- a/0001-main-Update-ostree-ext-add-provisional-repair-entryp.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 53fb8c7cb7075e4ecda4564f3a17af84ad4a2e32 Mon Sep 17 00:00:00 2001 -From: Colin Walters -Date: Fri, 21 Jul 2023 15:21:00 -0400 -Subject: [PATCH] main: Update ostree-ext, add provisional-repair entrypoint - -This updates us to vendor the provisional-repair code. One can -now run `ostree provisional-repair` directly. - -(Yes, it's very confusing how in rpm-ostree, we vendor the ostree-ext - source, and then install a wrapper symlink which tells the main - (C) `ostree` binary to call back into us... but it's how the - `ostree container` stuff has been working for a long time) ---- - Cargo.lock | 4 ++-- - Makefile-rpm-ostree.am | 1 + - rust/src/main.rs | 4 +++- - 3 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/Cargo.lock b/Cargo.lock -index 5ae6366a..c6826a4d 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -1775,9 +1775,9 @@ dependencies = [ - - [[package]] - name = "ostree-ext" --version = "0.11.1" -+version = "0.11.3" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "a690495144c18cb333a67a2ec61dd008831710bbd37804cfa79ab93b51146a6f" -+checksum = "8511513a60fa0c20a84ba8d30255286687c848bec21d24cd3dd4d16ecf48123b" - dependencies = [ - "anyhow", - "async-compression 0.3.15", -diff --git a/Makefile-rpm-ostree.am b/Makefile-rpm-ostree.am -index 2ef84f83..be80a6d7 100644 ---- a/Makefile-rpm-ostree.am -+++ b/Makefile-rpm-ostree.am -@@ -132,6 +132,7 @@ install-rpmostree-hook: - install -m 0755 -t $(DESTDIR)$(bindir) rpm-ostree - install -d -m 0755 $(ostreeextdir) - ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-ima-sign -+ ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-provisional-repair - ln -Tsr -f $(DESTDIR)$(bindir)/rpm-ostree $(ostreeextdir)/ostree-container - INSTALL_EXEC_HOOKS += install-rpmostree-hook - -diff --git a/rust/src/main.rs b/rust/src/main.rs -index 9088c5f0..569cf094 100644 ---- a/rust/src/main.rs -+++ b/rust/src/main.rs -@@ -53,7 +53,9 @@ async fn dispatch_ostree_ext(args: Vec) -> Result { - /// Dispatch multicall binary to relevant logic, based on callname from `argv[0]`. - async fn dispatch_multicall(callname: String, args: Vec) -> Result { - match callname.as_str() { -- "ostree-container" | "ostree-ima-sign" => dispatch_ostree_ext(args).await, -+ "ostree-container" | "ostree-ima-sign" | "ostree-provisional-repair" => { -+ dispatch_ostree_ext(args).await -+ } - _ => inner_async_main(args).await, // implicitly includes "rpm-ostree" - } - } --- -2.40.1 - diff --git a/0001-unit-chmod-etc-g-shadow-to-0000.patch b/0001-unit-chmod-etc-g-shadow-to-0000.patch new file mode 100644 index 0000000..5066d5a --- /dev/null +++ b/0001-unit-chmod-etc-g-shadow-to-0000.patch @@ -0,0 +1,79 @@ +From 7d27c0a85af81d8f6dffc8bf1fa0ab13b77859c0 Mon Sep 17 00:00:00 2001 +From: jbtrystram +Date: Thu, 21 Mar 2024 17:27:21 +0100 +Subject: [PATCH 1/2] unit: chmod /etc/[g]shadow[-] to 0000 + +fdb879c introduced a regression where /etc/[g]shadow[-] files where +created with default permissions: 0644 + +This unit chmods /etc/shadow, /etc/gshadow and backup copies to 0000 +before interactive login is allowed on a system. + +This will fix the systems that were deployed with the above issue. + +We keep the stamp in /etc to account for the case where a deployment +with this unit is rolled back. If we used /var, the stamp would have +stayed but the fix would not be re-applied on the next update. +--- + Makefile-daemon.am | 1 + + packaging/rpm-ostree.spec.in | 5 +++++ + src/daemon/rpm-ostree-fix-shadow-mode.service | 19 +++++++++++++++++++ + 3 files changed, 25 insertions(+) + create mode 100644 src/daemon/rpm-ostree-fix-shadow-mode.service + +diff --git a/Makefile-daemon.am b/Makefile-daemon.am +index 4233d90d..f96f49a9 100644 +--- a/Makefile-daemon.am ++++ b/Makefile-daemon.am +@@ -60,6 +60,7 @@ systemdunit_service_file_names = \ + rpm-ostreed-automatic.service \ + rpm-ostree-bootstatus.service \ + rpm-ostree-countme.service \ ++ rpm-ostree-fix-shadow-mode.service \ + $(NULL) + + systemdunit_service_files = $(addprefix $(srcdir)/src/daemon/,$(systemdunit_service_file_names)) +diff --git a/packaging/rpm-ostree.spec.in b/packaging/rpm-ostree.spec.in +index 8aa9afaa..f734f676 100644 +--- a/packaging/rpm-ostree.spec.in ++++ b/packaging/rpm-ostree.spec.in +@@ -237,6 +237,11 @@ $PYTHON autofiles.py > files.devel \ + # Setup rpm-ostree-countme.timer according to presets + %post + %systemd_post rpm-ostree-countme.timer ++# Only enable on rpm-ostree based systems and manually force unit enablement to ++# explicitly ignore presets for this security fix ++if [ -e /run/ostree-booted ]; then ++ ln -snf /usr/lib/systemd/system/rpm-ostree-fix-shadow-mode.service /usr/lib/systemd/system/multi-user.target.wants/ ++fi + + %preun + %systemd_preun rpm-ostree-countme.timer +diff --git a/src/daemon/rpm-ostree-fix-shadow-mode.service b/src/daemon/rpm-ostree-fix-shadow-mode.service +new file mode 100644 +index 00000000..4aea7462 +--- /dev/null ++++ b/src/daemon/rpm-ostree-fix-shadow-mode.service +@@ -0,0 +1,19 @@ ++[Unit] ++# rpm-ostree v2023.6 introduced a permission issue on `/etc/[g]shadow[-]`. ++# This makes sure to fix permissions on systems that were deployed with the wrong permissions. ++Description=Update permissions for /etc/shadow ++Documentation=https://github.com/coreos/rpm-ostree-ghsa-2m76-cwhg-7wv6 ++ConditionPathExists=!/etc/.rpm-ostree-shadow-mode-fixed.stamp ++ConditionPathExists=/run/ostree-booted ++# Make sure this is started before any unprivileged (interactive) user has access to the system. ++Before=systemd-user-sessions.service ++ ++[Service] ++Type=oneshot ++ExecStart=chmod --verbose 0000 /etc/shadow /etc/gshadow ++ExecStart=-chmod --verbose 0000 /etc/shadow- /etc/gshadow- ++ExecStart=touch /etc/.rpm-ostree-shadow-mode-fixed.stamp ++RemainAfterExit=yes ++ ++[Install] ++WantedBy=multi-user.target +-- +2.44.0 + diff --git a/0002-passwd-create-etc-g-shadow-with-mode-0.patch b/0002-passwd-create-etc-g-shadow-with-mode-0.patch new file mode 100644 index 0000000..3156dce --- /dev/null +++ b/0002-passwd-create-etc-g-shadow-with-mode-0.patch @@ -0,0 +1,83 @@ +From 3b4c96c5c49a537fba2e0cda0c6ee6bd58cac625 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon +Date: Tue, 19 Mar 2024 15:20:43 -0400 +Subject: [PATCH 2/2] passwd: create `/etc/[g]shadow` with mode 0 + +Because of how our composes work, we need to manually inject +passwd-related things before installing packages. A somewhat recent +regression in that area made it so that the `/etc/shadow` and +`/etc/gshadow` files were created with default permissions (0644), which +meant they were world readable. + +Fix this by explicitly setting their modes to 0. Ideally, we would rely +on the canonical permissions set in the `setup` package here, but it's +tricky to fix that without reworking how we install `setup` and handle +`passwd` treefile options. + +Fixes fdb879c8 ("passwd: sync `etc/{,g}shadow` according to +`etc/{passwd,group}`"). + +Fixes #4401 +--- + rust/src/passwd.rs | 14 ++++++++++++++ + tests/compose/libbasic-test.sh | 5 +++++ + 2 files changed, 19 insertions(+) + +diff --git a/rust/src/passwd.rs b/rust/src/passwd.rs +index 79ee488f..8f0e5841 100644 +--- a/rust/src/passwd.rs ++++ b/rust/src/passwd.rs +@@ -421,6 +421,12 @@ fn write_data_from_treefile( + let db = rootfs.open(target_passwd_path).map(BufReader::new)?; + let shadow_name = target.shadow_file(); + let target_shadow_path = format!("{}{}", dest_path, shadow_name); ++ // Ideally these permissions come from `setup`, which is the package ++ // that owns these files: ++ // https://src.fedoraproject.org/rpms/setup/blob/c6f58b338bd3/f/setup.spec#_96 ++ // But at this point of the compose, the rootfs is completely empty; we ++ // haven't started unpacking things yet. So we need to hardcode it here. ++ let shadow_perms = cap_std::fs::Permissions::from_mode(0); + + match target { + PasswdKind::User => { +@@ -430,6 +436,10 @@ fn write_data_from_treefile( + for user in entries { + writeln!(target_shadow, "{}:*::0:99999:7:::", user.name)?; + } ++ target_shadow ++ .get_mut() ++ .as_file_mut() ++ .set_permissions(shadow_perms)?; + Ok(()) + }) + .with_context(|| format!("Writing {target_shadow_path}"))?; +@@ -441,6 +451,10 @@ fn write_data_from_treefile( + for group in entries { + writeln!(target_shadow, "{}:::", group.name)?; + } ++ target_shadow ++ .get_mut() ++ .as_file_mut() ++ .set_permissions(shadow_perms)?; + Ok(()) + }) + .with_context(|| format!("Writing {target_shadow_path}"))?; +diff --git a/tests/compose/libbasic-test.sh b/tests/compose/libbasic-test.sh +index 0a751760..3f7c6d8a 100644 +--- a/tests/compose/libbasic-test.sh ++++ b/tests/compose/libbasic-test.sh +@@ -22,6 +22,11 @@ validate_passwd group + ostree --repo=${repo} ls ${treeref} /usr/etc/passwd > passwd.txt + assert_file_has_content_literal passwd.txt '00644 ' + ++ostree --repo=${repo} ls ${treeref} /usr/etc/shadow > shadow.txt ++assert_file_has_content_literal shadow.txt '00000 ' ++ostree --repo=${repo} ls ${treeref} /usr/etc/gshadow > gshadow.txt ++assert_file_has_content_literal gshadow.txt '00000 ' ++ + ostree --repo=${repo} cat ${treeref} /usr/etc/default/useradd > useradd.txt + assert_file_has_content_literal useradd.txt HOME=/var/home + +-- +2.44.0 + diff --git a/rpm-ostree.spec b/rpm-ostree.spec index e109125..2e6872b 100644 --- a/rpm-ostree.spec +++ b/rpm-ostree.spec @@ -4,7 +4,7 @@ Summary: Hybrid image/package system Name: rpm-ostree Version: 2024.4 -Release: 3%{?dist} +Release: 4%{?dist} License: LGPLv2+ URL: https://github.com/coreos/rpm-ostree # This tarball is generated via "cd packaging && make -f Makefile.dist-packaging dist-snapshot" @@ -13,6 +13,8 @@ Source0: https://github.com/coreos/rpm-ostree/releases/download/v%{version}/rpm- # https://issues.redhat.com/browse/RHEL-29559 Patch0: 0001-Revert-compose-Inject-our-static-tmpfiles.d-dropins-.patch +Patch1: 0001-unit-chmod-etc-g-shadow-to-0000.patch +Patch2: 0002-passwd-create-etc-g-shadow-with-mode-0.patch ExclusiveArch: %{rust_arches} @@ -232,6 +234,13 @@ $PYTHON autofiles.py > files.devel \ '%{_datadir}/gtk-doc/html/*' \ '%{_datadir}/gir-1.0/*-1.0.gir' +%post +# Only enable on rpm-ostree based systems and manually force unit enablement to +# explicitly ignore presets for this security fix +if [ -e /run/ostree-booted ]; then + ln -snf /usr/lib/systemd/system/rpm-ostree-fix-shadow-mode.service /usr/lib/systemd/system/multi-user.target.wants/ +fi + %files -f files %doc COPYING.GPL COPYING.LGPL LICENSE README.md @@ -240,6 +249,10 @@ $PYTHON autofiles.py > files.devel \ %files devel -f files.devel %changelog +* Tue Apr 09 2024 Joseph Marrero - 2024.4-4 +- Backport https://github.com/coreos/rpm-ostree/security/advisories/GHSA-2m76-cwhg-7wv6 + Resolves: #RHEL-31951 + * Thu Mar 21 2024 Colin Walters - 2024.4-3 - Backport patch to fix https://issues.redhat.com/browse/RHEL-29559