Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support mounting /sysroot (and /boot) read-only #1767

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile-switchroot.am
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ ostree_remount_SOURCES = \
src/switchroot/ostree-mount-util.h \
src/switchroot/ostree-remount.c \
$(NULL)
ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/switchroot
ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -Isrc/switchroot -I$(srcdir)/libglnx
ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la

if BUILDOPT_SYSTEMD
ostree_prepare_root_CPPFLAGS += -DHAVE_SYSTEMD=1
Expand Down
3 changes: 3 additions & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ ostree_sepolicy_get_type
OstreeSysroot
ostree_sysroot_new
ostree_sysroot_new_default
ostree_sysroot_initialize
ostree_sysroot_get_path
ostree_sysroot_load
ostree_sysroot_load_if_changed
Expand All @@ -508,6 +509,8 @@ ostree_sysroot_lock_async
ostree_sysroot_lock_finish
ostree_sysroot_unlock
ostree_sysroot_unload
ostree_sysroot_set_mount_namespace_in_use
ostree_sysroot_is_booted
ostree_sysroot_get_fd
ostree_sysroot_ensure_initialized
ostree_sysroot_get_bootversion
Expand Down
6 changes: 3 additions & 3 deletions src/boot/ostree-remount.service
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ DefaultDependencies=no
ConditionKernelCommandLine=ostree
OnFailure=emergency.target
Conflicts=umount.target
After=-.mount
# Run after core mounts
After=-.mount var.mount
After=systemd-remount-fs.service
# But we run *before* most other core bootup services that need write access to /etc and /var
Before=local-fs.target umount.target
# Other early boot units that need to write to /var
Before=systemd-random-seed.service plymouth-read-write.service systemd-journal-flush.service
# tmpfiles.d usually needs write access to a few places
Before=systemd-tmpfiles-setup.service

[Service]
Expand Down
3 changes: 3 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2019.7 {
ostree_sysroot_initialize;
ostree_sysroot_is_booted;
ostree_sysroot_set_mount_namespace_in_use;
} LIBOSTREE_2019.6;

/* Stub section for the stable release *after* this development one; don't
Expand Down
3 changes: 1 addition & 2 deletions src/libostree/ostree-impl-system-generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#ifdef HAVE_LIBMOUNT
#include <libmount.h>
#endif
#include <sys/statvfs.h>
#include <stdbool.h>
#include "otutil.h"

Expand Down Expand Up @@ -189,8 +190,6 @@ _ostree_impl_system_generator (const char *ostree_cmdline,
"[Unit]\n"
"Documentation=man:ostree(1)\n"
"ConditionKernelCommandLine=!systemd.volatile\n"
/* We need /sysroot mounted writable first */
"After=ostree-remount.service\n"
"Before=local-fs.target\n"
"\n"
"[Mount]\n"
Expand Down
8 changes: 7 additions & 1 deletion src/libostree/ostree-sysroot-cleanup.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot,
OstreeRepo *repo = ostree_sysroot_repo (sysroot);
const guint depth = 0; /* Historical default */

if (!_ostree_sysroot_ensure_writable (sysroot, error))
return FALSE;

/* Hold an exclusive lock by default across gathering refs and doing
* the prune.
*/
Expand Down Expand Up @@ -535,7 +538,10 @@ _ostree_sysroot_cleanup_internal (OstreeSysroot *self,
GError **error)
{
g_return_val_if_fail (OSTREE_IS_SYSROOT (self), FALSE);
g_return_val_if_fail (self->loaded, FALSE);
g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, FALSE);

if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

if (!cleanup_other_bootversions (self, cancellable, error))
return glnx_prefix_error (error, "Cleaning bootversions");
Expand Down
29 changes: 25 additions & 4 deletions src/libostree/ostree-sysroot-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
#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.
Expand Down Expand Up @@ -806,6 +809,9 @@ write_origin_file_internal (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (sysroot, error))
return FALSE;

GLNX_AUTO_PREFIX_ERROR ("Writing out origin file", error);
GKeyFile *origin =
new_origin ? new_origin : ostree_deployment_get_origin (deployment);
Expand Down Expand Up @@ -2217,7 +2223,10 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
g_assert (self->loaded);
g_assert (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED);

if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

/* Dealing with the staged deployment is quite tricky here. This function is
* primarily concerned with writing out "finalized" deployments which have
Expand Down Expand Up @@ -2374,7 +2383,6 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,

if (boot_was_ro_mount)
{
/* TODO: Use new mount namespace. https://github.com/ostreedev/ostree/issues/1265 */
if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
return glnx_throw_errno_prefix (error, "Remounting /boot read-write");
}
Expand Down Expand Up @@ -2408,8 +2416,10 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
/* 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 */
if (boot_was_ro_mount)
/* 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)
{
Expand Down Expand Up @@ -2716,6 +2726,9 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

g_autoptr(OstreeDeployment) deployment = NULL;
if (!sysroot_initialize_deployment (self, osname, revision, origin, override_kernel_argv,
&deployment, cancellable, error))
Expand Down Expand Up @@ -2817,6 +2830,9 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (self);
if (booted_deployment == NULL)
return glnx_throw (error, "Cannot stage a deployment when not currently booted into an OSTree system");
Expand Down Expand Up @@ -3043,6 +3059,9 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

/* For now; instead of this do a redeployment */
g_assert (!ostree_deployment_is_staged (deployment));

Expand Down Expand Up @@ -3090,6 +3109,8 @@ ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;

if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
Expand Down
13 changes: 12 additions & 1 deletion src/libostree/ostree-sysroot-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ typedef enum {
OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3,
} OstreeSysrootDebugFlags;

typedef enum {
OSTREE_SYSROOT_LOAD_STATE_NONE, /* ostree_sysroot_new() was called */
OSTREE_SYSROOT_LOAD_STATE_INIT, /* We've loaded basic sysroot state and have an fd */
OSTREE_SYSROOT_LOAD_STATE_LOADED, /* We've loaded all of the deployments */
} OstreeSysrootLoadState;

/**
* OstreeSysroot:
* Internal struct
Expand All @@ -51,7 +57,8 @@ struct OstreeSysroot {
int sysroot_fd;
GLnxLockFile lock;

gboolean loaded;
OstreeSysrootLoadState loadstate;
gboolean mount_namespace_in_use; /* TRUE if caller has told us they used CLONE_NEWNS */
gboolean root_is_ostree_booted; /* TRUE if sysroot is / and we are booted via ostree */
/* The device/inode for /, used to detect booted deployment */
dev_t root_device;
Expand Down Expand Up @@ -79,6 +86,10 @@ struct OstreeSysroot {
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"

gboolean
_ostree_sysroot_ensure_writable (OstreeSysroot *self,
GError **error);

void
_ostree_sysroot_emit_journal_msg (OstreeSysroot *self,
const char *msg);
Expand Down
Loading