From beda4a034469d2838114b955eede97591809e915 Mon Sep 17 00:00:00 2001
From: chendexi <chendexi@kylinos.cn>
Date: Wed, 10 Apr 2024 16:45:48 +0800
Subject: [PATCH] fix-CVE-2024-2905

---
 Makefile-daemon.am                            |  1 +
 rust/src/passwd.rs                            | 14 ++++++++++++++
 src/daemon/rpm-ostree-fix-shadow-mode.service | 19 +++++++++++++++++++
 tests/compose/libbasic-test.sh                |  5 +++++
 4 files changed, 39 insertions(+)
 create mode 100644 src/daemon/rpm-ostree-fix-shadow-mode.service

diff --git a/Makefile-daemon.am b/Makefile-daemon.am
index 4233d90..da14e71 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/rust/src/passwd.rs b/rust/src/passwd.rs
index 100c29f..08b67f7 100644
--- a/rust/src/passwd.rs
+++ b/rust/src/passwd.rs
@@ -420,6 +420,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 => {
@@ -429,6 +435,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}"))?;
@@ -440,6 +450,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/src/daemon/rpm-ostree-fix-shadow-mode.service b/src/daemon/rpm-ostree-fix-shadow-mode.service
new file mode 100644
index 0000000..4aea746
--- /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
diff --git a/tests/compose/libbasic-test.sh b/tests/compose/libbasic-test.sh
index 78ad72b..df790e8 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.25.1

