diff --git a/.gitignore b/.gitignore index b0cca2b..699af01 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ /libostree-2025.5.tar.xz /libostree-2025.6.tar.xz /libostree-2025.7.tar.xz +/libostree-2026.1.tar.xz diff --git a/0001-state-overlay-Fix-ENODATA-handling-for-GLib-2.74.patch b/0001-state-overlay-Fix-ENODATA-handling-for-GLib-2.74.patch deleted file mode 100644 index 4fc9606..0000000 --- a/0001-state-overlay-Fix-ENODATA-handling-for-GLib-2.74.patch +++ /dev/null @@ -1,150 +0,0 @@ -From a56255cbc09f3ac01d67bcee8b355ceebc7f2d47 Mon Sep 17 00:00:00 2001 -From: Joseph Marrero Corchado -Date: Tue, 16 Dec 2025 14:30:47 -0500 -Subject: [PATCH] state-overlay: Fix ENODATA handling for GLib < 2.74 - -The state overlay feature fails on first boot with: - - error: lgetxattr(user.ostree.deploymentcsum): No data available - -This happens because `lgetxattrat_allow_noent()` checks for -`G_IO_ERROR_INVALID_DATA` to detect when an xattr doesn't exist. -However, GLib's `g_io_error_from_errno()` only maps `ENODATA` to -`G_IO_ERROR_INVALID_DATA` since GLib 2.74. Older versions (such as -GLib 2.68 shipped in CentOS Stream 9) return `G_IO_ERROR_FAILED` -instead, causing the check to fail and the error to propagate. - -This creates a chicken-and-egg problem: the code tries to read the -`user.ostree.deploymentcsum` xattr before it can set it, but the read -fails on fresh overlay directories where the xattr hasn't been set yet. - -Fix this by checking `errno == ENODATA` directly after the failed call, -which is portable across all GLib versions. Also rename the function -from `lgetxattrat_allow_noent` to `lgetxattrat_allow_nodata` to more -accurately reflect its purpose (ENODATA vs ENOENT). - -This bug has existed since the state overlay feature was introduced in -v2024.1 but was masked on systems with GLib >= 2.74 (e.g., Fedora, -CentOS Stream 10) where the mapping happens to exist. - -Assisted-by: Claude Code (Opus 4.5) - -Signed-off-by: Joseph Marrero Corchado ---- - src/ostree/ot-admin-builtin-state-overlay.c | 75 +++++++++++++++++---- - 1 file changed, 62 insertions(+), 13 deletions(-) - -diff --git a/src/ostree/ot-admin-builtin-state-overlay.c b/src/ostree/ot-admin-builtin-state-overlay.c -index 7bf386c4..3c763ae0 100644 ---- a/src/ostree/ot-admin-builtin-state-overlay.c -+++ b/src/ostree/ot-admin-builtin-state-overlay.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - #include "glnx-errors.h" - #include "glnx-fdio.h" -@@ -62,20 +63,68 @@ ensure_overlay_dirs (const char *overlay_dir, int *out_overlay_dfd, GCancellable - return TRUE; - } - --/* XXX: upstream to libglnx */ -+/* Based on glnx_lgetxattrat() from libglnx, modified to treat ENODATA -+ * (xattr not set) as success with *out_bytes = NULL. We check errno -+ * immediately after the lgetxattr syscall, before any GLib calls can -+ * clobber it. This avoids depending on GLib's g_io_error_from_errno() -+ * mapping, which only maps ENODATA to G_IO_ERROR_NOT_FOUND since GLib 2.74. -+ * -+ * This implementation handles the TOCTOU race condition where the xattr size -+ * may change between the size query and the data read by retrying with ERANGE. -+ * It also handles the case where the xattr is deleted between calls (ENODATA -+ * on second call). Zero-length xattrs are handled without allocating a buffer. -+ * -+ * TODO: Upstream to libglnx. */ - static gboolean --lgetxattrat_allow_noent (int dfd, const char *path, const char *attribute, GBytes **out_bytes, -- GError **error) -+lgetxattrat_allow_nodata (int dfd, const char *path, const char *attribute, GBytes **out_bytes, -+ GError **error) - { -- g_autoptr (GError) local_error = NULL; -- *out_bytes = glnx_lgetxattrat (dfd, path, attribute, &local_error); -- if (!*out_bytes) -+ char pathbuf[PATH_MAX]; -+ int n = snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, path); -+ if (n < 0 || n >= sizeof (pathbuf)) -+ return glnx_throw (error, "Path truncated for fd %d, path %s", dfd, path); -+ -+ ssize_t bytes_read; -+ ssize_t real_size; -+ g_autofree guint8 *buf = NULL; -+ -+again: -+ errno = 0; -+ bytes_read = TEMP_FAILURE_RETRY (lgetxattr (pathbuf, attribute, NULL, 0)); -+ if (bytes_read < 0) -+ { -+ if (errno == ENODATA) -+ { -+ *out_bytes = NULL; -+ return TRUE; /* xattr not set; that's fine */ -+ } -+ return glnx_throw_errno_prefix (error, "lgetxattr(%s)", attribute); -+ } -+ -+ if (bytes_read == 0) - { -- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA)) -- return TRUE; -- g_propagate_error (error, g_steal_pointer (&local_error)); -- return FALSE; -+ *out_bytes = g_bytes_new_static ("", 0); -+ return TRUE; - } -+ -+ buf = g_malloc (bytes_read); -+ real_size = TEMP_FAILURE_RETRY (lgetxattr (pathbuf, attribute, buf, bytes_read)); -+ if (real_size < 0) -+ { -+ if (errno == ERANGE) -+ { -+ g_clear_pointer (&buf, g_free); -+ goto again; -+ } -+ if (errno == ENODATA) -+ { -+ *out_bytes = NULL; -+ return TRUE; /* xattr was deleted between calls */ -+ } -+ return glnx_throw_errno_prefix (error, "lgetxattr(%s)", attribute); -+ } -+ -+ *out_bytes = g_bytes_new_take (g_steal_pointer (&buf), real_size); - return TRUE; - } - -@@ -83,7 +132,7 @@ static gboolean - is_opaque_dir (int dfd, const char *dname, gboolean *out_is_opaque, GError **error) - { - g_autoptr (GBytes) data = NULL; -- if (!lgetxattrat_allow_noent (dfd, dname, OVERLAYFS_DIR_XATTR_OPAQUE, &data, error)) -+ if (!lgetxattrat_allow_nodata (dfd, dname, OVERLAYFS_DIR_XATTR_OPAQUE, &data, error)) - return FALSE; - - if (!data) -@@ -203,8 +252,8 @@ get_overlay_deployment_checksum (int overlay_dfd, char **out_checksum, GCancella - GError **error) - { - g_autoptr (GBytes) bytes = NULL; -- if (!lgetxattrat_allow_noent (overlay_dfd, OSTREE_STATEOVERLAY_UPPER_DIR, -- OSTREE_STATEOVERLAY_XATTR_DEPLOYMENT_CSUM, &bytes, error)) -+ if (!lgetxattrat_allow_nodata (overlay_dfd, OSTREE_STATEOVERLAY_UPPER_DIR, -+ OSTREE_STATEOVERLAY_XATTR_DEPLOYMENT_CSUM, &bytes, error)) - return FALSE; - if (!bytes) - return TRUE; /* probably newly created */ --- -2.52.0 - diff --git a/ostree.spec b/ostree.spec index 38e59c9..113ccb7 100644 --- a/ostree.spec +++ b/ostree.spec @@ -7,14 +7,12 @@ Summary: Tool for managing bootable, immutable filesystem trees Name: ostree -Version: 2025.7 +Version: 2026.1 Release: 1%{?dist} Source0: https://github.com/ostreedev/%{name}/releases/download/v%{version}/libostree-%{version}.tar.xz Source1: ostree-readonly-sysroot-migration Source2: ostree-readonly-sysroot-migration.service -Patch0: 0001-state-overlay-Fix-ENODATA-handling-for-GLib-2.74.patch - License: LGPLv2+ URL: https://ostree.readthedocs.io/en/latest/ @@ -181,6 +179,11 @@ find %{buildroot} -name '*.la' -delete %endif %changelog +* Fri Apr 10 2026 Joseph Marrero - 2026.1-1 +- Rebase to 2026.1 + Release https://github.com/ostreedev/ostree/releases/tag/v2026.1 + Resolves: #RHEL-167078 + * Mon Jan 26 2026 Joseph Marrero - 2025.7-1 - Rebase to 2025.7 Backport https://github.com/ostreedev/ostree/pull/3555 diff --git a/sources b/sources index e79d622..6b741ec 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (libostree-2025.7.tar.xz) = bf10001f64b11c1aa5c7c4d5fee744b2ee1ea950adf1efd69f315d18e428967daba2ea4aa1120b9e2a0b8e56f7664601c396eb57ff833299bf86ed003ece60da +SHA512 (libostree-2026.1.tar.xz) = df5123a8455f5fda8b3d06c682d01fdf3603965e1990f66ccc3eef0bc6f59eddf1cde118a79d82218c95612d8ffa0af4befdfc613ac6c4480444f90edfd66df2