diff --git a/SOURCES/0002-github-ostreedev-ostree-pr2261.patch b/SOURCES/0002-github-ostreedev-ostree-pr2261.patch new file mode 100644 index 0000000..52f9c4b --- /dev/null +++ b/SOURCES/0002-github-ostreedev-ostree-pr2261.patch @@ -0,0 +1,461 @@ +From 6ebb1c680835aa85714f34d897621b65ac6fef5d Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Sat, 9 Jan 2021 20:42:43 +0000 +Subject: [PATCH 1/3] main: Unconditionally set up mount namespace + +I was being very conservative initially here, but I think it's +really safe to just unconditionally set up the mount namespace. + +This avoids having to check twice for a read-only `/sysroot` +(once in the binary and once in the library). +--- + src/ostree/ot-main.c | 22 +++------------------- + 1 file changed, 3 insertions(+), 19 deletions(-) + +diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c +index bffa40c4d4..d153dcec5c 100644 +--- a/src/ostree/ot-main.c ++++ b/src/ostree/ot-main.c +@@ -122,26 +122,10 @@ maybe_setup_mount_namespace (gboolean *out_ns, + if (errno == ENOENT) + return TRUE; + +- glnx_autofd int sysroot_subdir_fd = glnx_opendirat_with_errno (AT_FDCWD, "/sysroot", TRUE); +- if (sysroot_subdir_fd < 0) +- { +- if (errno != ENOENT) +- return glnx_throw_errno_prefix (error, "opendirat"); +- /* No /sysroot - nothing to do */ +- return TRUE; +- } +- +- struct statvfs stvfs; +- if (fstatvfs (sysroot_subdir_fd, &stvfs) < 0) +- return glnx_throw_errno_prefix (error, "fstatvfs"); +- if (stvfs.f_flag & ST_RDONLY) +- { +- if (unshare (CLONE_NEWNS) < 0) +- return glnx_throw_errno_prefix (error, "preparing writable sysroot: unshare (CLONE_NEWNS)"); +- +- *out_ns = TRUE; +- } ++ if (unshare (CLONE_NEWNS) < 0) ++ return glnx_throw_errno_prefix (error, "setting up mount namespace: unshare(CLONE_NEWNS)"); + ++ *out_ns = TRUE; + return TRUE; + } + + +From efa2ecfa731b5d782987d9b495f397c502761eff Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Sat, 9 Jan 2021 20:40:55 +0000 +Subject: [PATCH 2/3] sysroot: Also maintain canonical boot_fd + +Just like we hold a fd for `/sysroot`, also do so for `/boot` +instead of opening and closing it in a few places. + +This is a preparatory cleanup for further work. +--- + src/libostree/ostree-sysroot-deploy.c | 32 ++++++++++++-------------- + src/libostree/ostree-sysroot-private.h | 4 ++++ + src/libostree/ostree-sysroot.c | 15 ++++++++++++ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c +index 7b7ba5e92f..aa6c0e6f6f 100644 +--- a/src/libostree/ostree-sysroot-deploy.c ++++ b/src/libostree/ostree-sysroot-deploy.c +@@ -1583,11 +1583,11 @@ full_system_sync (OstreeSysroot *self, + + out_stats->root_syncfs_msec = (end_msec - start_msec); + +- start_msec = g_get_monotonic_time () / 1000; +- glnx_autofd int boot_dfd = -1; +- if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error)) ++ if (!_ostree_sysroot_ensure_boot_fd (self, error)) + return FALSE; +- if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error)) ++ ++ start_msec = g_get_monotonic_time () / 1000; ++ if (!fsfreeze_thaw_cycle (self, self->boot_fd, cancellable, error)) + return FALSE; + end_msec = g_get_monotonic_time () / 1000; + out_stats->boot_syncfs_msec = (end_msec - start_msec); +@@ -1771,8 +1771,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, + cancellable, error)) + return FALSE; + +- glnx_autofd int boot_dfd = -1; +- if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error)) ++ if (!_ostree_sysroot_ensure_boot_fd (sysroot, error)) + return FALSE; + + const char *osname = ostree_deployment_get_osname (deployment); +@@ -1782,14 +1781,14 @@ install_deployment_kernel (OstreeSysroot *sysroot, + g_autofree char *bootconf_name = g_strdup_printf ("ostree-%d-%s.conf", + n_deployments - ostree_deployment_get_index (deployment), + osname); +- if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error)) ++ if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootcsumdir, 0775, cancellable, error)) + return FALSE; + + glnx_autofd int bootcsum_dfd = -1; +- if (!glnx_opendirat (boot_dfd, bootcsumdir, TRUE, &bootcsum_dfd, error)) ++ if (!glnx_opendirat (sysroot->boot_fd, bootcsumdir, TRUE, &bootcsum_dfd, error)) + return FALSE; + +- if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error)) ++ if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootconfdir, 0775, cancellable, error)) + return FALSE; + + /* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if +@@ -1880,18 +1879,18 @@ install_deployment_kernel (OstreeSysroot *sysroot, + { + overlay_initrds = g_ptr_array_new_with_free_func (g_free); + +- if (!glnx_shutil_mkdir_p_at (boot_dfd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS, ++ if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS, + 0755, cancellable, error)) + return FALSE; + } + +- if (!glnx_fstatat_allow_noent (boot_dfd, rel_destpath, NULL, 0, error)) ++ if (!glnx_fstatat_allow_noent (sysroot->boot_fd, rel_destpath, NULL, 0, error)) + return FALSE; + if (errno == ENOENT) + { + g_autofree char *srcpath = + g_strdup_printf (_OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR "/%s", checksum); +- if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, boot_dfd, rel_destpath, ++ if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, sysroot->boot_fd, rel_destpath, + cancellable, error)) + return FALSE; + } +@@ -2020,7 +2019,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, + ostree_bootconfig_parser_set (bootconfig, "options", options_key); + + glnx_autofd int bootconf_dfd = -1; +- if (!glnx_opendirat (boot_dfd, bootconfdir, TRUE, &bootconf_dfd, error)) ++ if (!glnx_opendirat (sysroot->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error)) + return FALSE; + + if (!ostree_bootconfig_parser_write_at (ostree_deployment_get_bootconfig (deployment), +@@ -2077,15 +2076,14 @@ swap_bootloader (OstreeSysroot *sysroot, + g_assert ((current_bootversion == 0 && new_bootversion == 1) || + (current_bootversion == 1 && new_bootversion == 0)); + +- glnx_autofd int boot_dfd = -1; +- if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error)) ++ if (!_ostree_sysroot_ensure_boot_fd (sysroot, error)) + return FALSE; + + /* The symlink was already written, and we used syncfs() to ensure + * its data is in place. Renaming now should give us atomic semantics; + * see https://bugzilla.gnome.org/show_bug.cgi?id=755595 + */ +- if (!glnx_renameat (boot_dfd, "loader.tmp", boot_dfd, "loader", error)) ++ if (!glnx_renameat (sysroot->boot_fd, "loader.tmp", sysroot->boot_fd, "loader", error)) + return FALSE; + + /* Now we explicitly fsync this directory, even though it +@@ -2097,7 +2095,7 @@ swap_bootloader (OstreeSysroot *sysroot, + * for whatever reason, and we wouldn't want to confuse the + * admin by going back to the previous session. + */ +- if (fsync (boot_dfd) != 0) ++ if (fsync (sysroot->boot_fd) != 0) + return glnx_throw_errno_prefix (error, "fsync(boot)"); + + /* TODO: In the future also execute this automatically via a systemd unit +diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h +index 318b0b199e..641f053384 100644 +--- a/src/libostree/ostree-sysroot-private.h ++++ b/src/libostree/ostree-sysroot-private.h +@@ -56,6 +56,7 @@ struct OstreeSysroot { + + GFile *path; + int sysroot_fd; ++ int boot_fd; + GLnxLockFile lock; + + OstreeSysrootLoadState loadstate; +@@ -160,6 +161,9 @@ char * _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const ch + + char *_ostree_sysroot_join_lines (GPtrArray *lines); + ++gboolean ++_ostree_sysroot_ensure_boot_fd (OstreeSysroot *self, GError **error); ++ + gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot, + OstreeBootloader **out_bootloader, + GCancellable *cancellable, +diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c +index e0813b5544..776572cc8d 100644 +--- a/src/libostree/ostree-sysroot.c ++++ b/src/libostree/ostree-sysroot.c +@@ -197,6 +197,7 @@ ostree_sysroot_init (OstreeSysroot *self) + keys, G_N_ELEMENTS (keys)); + + self->sysroot_fd = -1; ++ self->boot_fd = -1; + } + + /** +@@ -277,6 +278,19 @@ ensure_sysroot_fd (OstreeSysroot *self, + &self->sysroot_fd, error)) + return FALSE; + } ++ ++ return TRUE; ++} ++ ++gboolean ++_ostree_sysroot_ensure_boot_fd (OstreeSysroot *self, GError **error) ++{ ++ if (self->boot_fd == -1) ++ { ++ if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, ++ &self->boot_fd, error)) ++ return FALSE; ++ } + return TRUE; + } + +@@ -379,6 +393,7 @@ void + ostree_sysroot_unload (OstreeSysroot *self) + { + glnx_close_fd (&self->sysroot_fd); ++ glnx_close_fd (&self->boot_fd); + } + + /** + +From 518e5dc0eaad99ab44f905b7ccadda476338f5f8 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Sat, 9 Jan 2021 18:34:27 +0000 +Subject: [PATCH 3/3] sysroot: Handle ro /boot but rw /sysroot + +The recent change in https://github.com/coreos/fedora-coreos-config/pull/659 +broke some of our tests that do `mount -o remount,rw /sysroot` but +leave `/boot` read-only. + +We had code for having `/boot` read-only before `/sysroot` but +in practice we had a file descriptor for `/sysroot` that we opened +before the remount that would happen later on. + +Clean things up here so that in the library, we also remount +`/boot` at the same time we remount `/sysroot` if either are readonly. + +Delete the legacy code for remounting `/boot` rw if we're not in +a mount namespace. I am fairly confident most users are either +using the `ostree` CLI, or they're using the mount namespace. +--- + src/libostree/ostree-sysroot-deploy.c | 87 +-------------------------- + src/libostree/ostree-sysroot.c | 47 +++++++++++---- + src/libotutil/otutil.h | 6 ++ + 3 files changed, 44 insertions(+), 96 deletions(-) + +diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c +index aa6c0e6f6f..326e0b7cf5 100644 +--- a/src/libostree/ostree-sysroot-deploy.c ++++ b/src/libostree/ostree-sysroot-deploy.c +@@ -57,9 +57,6 @@ + #define OSTREE_DEPLOYMENT_FINALIZING_ID SD_ID128_MAKE(e8,64,6c,d6,3d,ff,46,25,b7,79,09,a8,e7,a4,09,94) + #endif + +-static gboolean +-is_ro_mount (const char *path); +- + /* + * Like symlinkat() but overwrites (atomically) an existing + * symlink. +@@ -2226,57 +2223,6 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self, + return TRUE; + } + +-/* Detect whether or not @path refers to a read-only mountpoint. This is +- * currently just used to handle a potentially read-only /boot by transiently +- * remounting it read-write. In the future we might also do this for e.g. +- * /sysroot. +- */ +-static gboolean +-is_ro_mount (const char *path) +-{ +-#ifdef HAVE_LIBMOUNT +- /* Dragging in all of this crud is apparently necessary just to determine +- * whether something is a mount point. +- * +- * Systemd has a totally different implementation in +- * src/basic/mount-util.c. +- */ +- struct libmnt_table *tb = mnt_new_table_from_file ("/proc/self/mountinfo"); +- struct libmnt_fs *fs; +- struct libmnt_cache *cache; +- gboolean is_mount = FALSE; +- struct statvfs stvfsbuf; +- +- if (!tb) +- return FALSE; +- +- /* to canonicalize all necessary paths */ +- cache = mnt_new_cache (); +- mnt_table_set_cache (tb, cache); +- +- fs = mnt_table_find_target(tb, path, MNT_ITER_BACKWARD); +- is_mount = fs && mnt_fs_get_target (fs); +-#ifdef HAVE_MNT_UNREF_CACHE +- mnt_unref_table (tb); +- mnt_unref_cache (cache); +-#else +- mnt_free_table (tb); +- mnt_free_cache (cache); +-#endif +- +- if (!is_mount) +- return FALSE; +- +- /* We *could* parse the options, but it seems more reliable to +- * introspect the actual mount at runtime. +- */ +- if (statvfs (path, &stvfsbuf) == 0) +- return (stvfsbuf.f_flag & ST_RDONLY) != 0; +- +-#endif +- return FALSE; +-} +- + /** + * ostree_sysroot_write_deployments: + * @self: Sysroot +@@ -2579,18 +2525,6 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, + } + else + { +- gboolean boot_was_ro_mount = FALSE; +- if (self->booted_deployment) +- boot_was_ro_mount = is_ro_mount ("/boot"); +- +- g_debug ("boot is ro: %s", boot_was_ro_mount ? "yes" : "no"); +- +- if (boot_was_ro_mount) +- { +- if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) +- return glnx_throw_errno_prefix (error, "Remounting /boot read-write"); +- } +- + OstreeRepo *repo = ostree_sysroot_repo (self); + + bootloader_config = ostree_repo_get_bootloader (repo); +@@ -2617,25 +2551,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, + + bootloader_is_atomic = bootloader != NULL && _ostree_bootloader_is_atomic (bootloader); + +- /* Note equivalent of try/finally here */ +- gboolean success = write_deployments_bootswap (self, new_deployments, opts, bootloader, +- &syncstats, cancellable, error); +- /* Below here don't set GError until the if (!success) check. +- * Note we only bother remounting if a mount namespace isn't in use. +- * */ +- if (boot_was_ro_mount && !self->mount_namespace_in_use) +- { +- if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_RDONLY | MS_SILENT, NULL) < 0) +- { +- /* Only make this a warning because we don't want to +- * completely bomb out if some other process happened to +- * jump in and open a file there. See above TODO +- * around doing this in a new mount namespace. +- */ +- g_printerr ("warning: Failed to remount /boot read-only: %s\n", strerror (errno)); +- } +- } +- if (!success) ++ if (!write_deployments_bootswap (self, new_deployments, opts, bootloader, ++ &syncstats, cancellable, error)) + return FALSE; + } + +diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c +index 776572cc8d..9f54e6667c 100644 +--- a/src/libostree/ostree-sysroot.c ++++ b/src/libostree/ostree-sysroot.c +@@ -294,6 +294,31 @@ _ostree_sysroot_ensure_boot_fd (OstreeSysroot *self, GError **error) + return TRUE; + } + ++static gboolean ++remount_writable (const char *path, gboolean *did_remount, GError **error) ++{ ++ *did_remount = FALSE; ++ struct statvfs stvfsbuf; ++ if (statvfs (path, &stvfsbuf) < 0) ++ { ++ if (errno != ENOENT) ++ return glnx_throw_errno_prefix (error, "statvfs(%s)", path); ++ else ++ return TRUE; ++ } ++ ++ if ((stvfsbuf.f_flag & ST_RDONLY) != 0) ++ { ++ /* OK, let's remount writable. */ ++ if (mount (path, path, NULL, MS_REMOUNT | MS_RELATIME, "") < 0) ++ return glnx_throw_errno_prefix (error, "Remounting %s read-write", path); ++ *did_remount = TRUE; ++ g_debug ("remounted %s writable", path); ++ } ++ ++ return TRUE; ++} ++ + /* Remount /sysroot read-write if necessary */ + gboolean + _ostree_sysroot_ensure_writable (OstreeSysroot *self, +@@ -313,19 +338,19 @@ _ostree_sysroot_ensure_writable (OstreeSysroot *self, + if (!self->root_is_ostree_booted) + return TRUE; + +- /* Check if /sysroot is a read-only mountpoint */ +- struct statvfs stvfsbuf; +- if (statvfs ("/sysroot", &stvfsbuf) < 0) +- return glnx_throw_errno_prefix (error, "fstatvfs(/sysroot)"); +- if ((stvfsbuf.f_flag & ST_RDONLY) == 0) +- return TRUE; ++ /* In these cases we also require /boot */ ++ if (!_ostree_sysroot_ensure_boot_fd (self, error)) ++ return FALSE; + +- /* OK, let's remount writable. */ +- if (mount ("/sysroot", "/sysroot", NULL, MS_REMOUNT | MS_RELATIME, "") < 0) +- return glnx_throw_errno_prefix (error, "Remounting /sysroot read-write"); ++ gboolean did_remount_sysroot = FALSE; ++ if (!remount_writable ("/sysroot", &did_remount_sysroot, error)) ++ return FALSE; ++ gboolean did_remount_boot = FALSE; ++ if (!remount_writable ("/boot", &did_remount_boot, error)) ++ return FALSE; + +- /* Reopen our fd */ +- glnx_close_fd (&self->sysroot_fd); ++ /* Now close and reopen our file descriptors */ ++ ostree_sysroot_unload (self); + if (!ensure_sysroot_fd (self, error)) + return FALSE; + +diff --git a/src/libotutil/otutil.h b/src/libotutil/otutil.h +index 7db7270da0..4cc5cd9f17 100644 +--- a/src/libotutil/otutil.h ++++ b/src/libotutil/otutil.h +@@ -34,6 +34,12 @@ + #define OT_VARIANT_BUILDER_INITIALIZER {{{0,}}} + #endif + ++static inline const char * ++ot_booltostr (int b) ++{ ++ return b ? "true" : "false"; ++} ++ + #define ot_gobject_refz(o) (o ? g_object_ref (o) : o) + + #define ot_transfer_out_value(outp, srcp) G_STMT_START { \ diff --git a/SPECS/ostree.spec b/SPECS/ostree.spec index 21ecd1f..fd9df84 100644 --- a/SPECS/ostree.spec +++ b/SPECS/ostree.spec @@ -8,13 +8,14 @@ Summary: Tool for managing bootable, immutable filesystem trees Name: ostree Version: 2020.7 -Release: 4%{?dist} +Release: 5%{?dist} Source0: https://github.com/ostreedev/%{name}/releases/download/v%{version}/libostree-%{version}.tar.xz License: LGPLv2+ URL: https://ostree.readthedocs.io/en/latest/ Patch0: 0001-ostree-prepare-root-print-st_dev-and-st_ino-as-64-bi.patch Patch1: 0001-gcc11.patch +Patch2: 0002-github-ostreedev-ostree-pr2261.patch BuildRequires: git # We always run autogen.sh @@ -165,6 +166,10 @@ find %{buildroot} -name '*.la' -delete %endif %changelog +* Fri Jun 04 2021 Luca BRUNO - 2020.7-5 +- Backport https://github.com/ostreedev/ostree/pull/2261 + Resolves: rhbz#1969452 + * Wed Feb 24 2021 Colin Walters - 2020.7-4 - Bump release to satisfy vercmp