sysroot: _ostree_sysroot_invisible & _ostree_in_root_mount_namespace

This commit is contained in:
Misaki Kasumi 2024-12-19 15:04:55 +08:00
parent 3dc167e2ee
commit 300d21c1cb
4 changed files with 64 additions and 22 deletions

View File

@ -124,8 +124,7 @@ gboolean _ostree_sysroot_ensure_visible (OstreeSysroot *self, GError **error);
gboolean _ostree_sysroot_ensure_writable (OstreeSysroot *self, GError **error); gboolean _ostree_sysroot_ensure_writable (OstreeSysroot *self, GError **error);
gboolean gboolean
_ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GCancellable *cancellable, _ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GError **error);
GError **error);
void _ostree_sysroot_emit_journal_msg (OstreeSysroot *self, const char *msg); void _ostree_sysroot_emit_journal_msg (OstreeSysroot *self, const char *msg);

View File

@ -228,20 +228,22 @@ ostree_sysroot_new_default (void)
} }
static gboolean static gboolean
is_in_root_mount_namespace (GCancellable *cancellable, GError **error) _ostree_in_root_mount_namespace (gboolean *out_val, GError **error)
{ {
/* glnx_readlinkat_malloc does not use cancellable acually. */
g_autofree char *mntns_pid1 g_autofree char *mntns_pid1
= glnx_readlinkat_malloc (AT_FDCWD, "/proc/1/ns/mnt", cancellable, error); = glnx_readlinkat_malloc (AT_FDCWD, "/proc/1/ns/mnt", NULL, error);
if (!mntns_pid1) if (!mntns_pid1)
return glnx_prefix_error (error, "Reading /proc/1/ns/mnt"); return glnx_prefix_error (error, "Reading /proc/1/ns/mnt");
/* mount namespace is per-thread, not per-process */ /* mount namespace is per-thread, not per-process */
g_autofree char *cur_thread = g_strdup_printf ("/proc/%d/ns/mnt", gettid ()); g_autofree char *cur_thread = g_strdup_printf ("/proc/%d/ns/mnt", gettid ());
g_autofree char *mntns_cur g_autofree char *mntns_cur
= glnx_readlinkat_malloc (AT_FDCWD, cur_thread, cancellable, error); = glnx_readlinkat_malloc (AT_FDCWD, cur_thread, NULL, error);
if (!mntns_cur) if (!mntns_cur)
return glnx_prefix_error (error, "Reading %s", cur_thread); return glnx_prefix_error (error, "Reading %s", cur_thread);
return g_str_equal (mntns_pid1, mntns_cur); *out_val = g_str_equal (mntns_pid1, mntns_cur);
return TRUE;
} }
/** /**
@ -268,15 +270,14 @@ ostree_sysroot_set_mount_namespace_in_use (OstreeSysroot *self)
/* Must be before we're loaded, as otherwise we'd have to close/reopen all our /* Must be before we're loaded, as otherwise we'd have to close/reopen all our
fds, e.g. the repo */ fds, e.g. the repo */
g_return_if_fail (self->loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED); g_return_if_fail (self->loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED);
gboolean in_root;
g_autoptr (GError) local_error = NULL; g_autoptr (GError) local_error = NULL;
g_assert (!is_in_root_mount_namespace (NULL, &local_error)); g_assert (_ostree_in_root_mount_namespace (&in_root, &local_error) && !in_root);
g_assert (local_error == NULL);
self->mount_namespace_in_use = TRUE; self->mount_namespace_in_use = TRUE;
} }
gboolean gboolean
_ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GCancellable *cancellable, _ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GError **error)
GError **error)
{ {
/* Do nothing if we're not privileged */ /* Do nothing if we're not privileged */
if (!ot_util_process_privileged ()) if (!ot_util_process_privileged ())
@ -287,7 +288,9 @@ _ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GCancellable *cancel
return TRUE; return TRUE;
// If the mount namespaces are the same, we need to unshare(). // If the mount namespaces are the same, we need to unshare().
if (is_in_root_mount_namespace (cancellable, error)) gboolean in_root;
g_return_val_if_fail (_ostree_in_root_mount_namespace (&in_root, error), FALSE);
if (in_root)
{ {
if (unshare (CLONE_NEWNS) < 0) if (unshare (CLONE_NEWNS) < 0)
return glnx_throw_errno_prefix (error, "Failed to invoke unshare(CLONE_NEWNS)"); return glnx_throw_errno_prefix (error, "Failed to invoke unshare(CLONE_NEWNS)");
@ -296,8 +299,6 @@ _ostree_sysroot_enter_mount_namespace (OstreeSysroot *self, GCancellable *cancel
if (mount (NULL, "/", NULL, MS_PRIVATE | MS_REC | MS_SILENT, NULL) < 0) if (mount (NULL, "/", NULL, MS_PRIVATE | MS_REC | MS_SILENT, NULL) < 0)
return glnx_throw_errno_prefix (error, "Failed to set the mount propagation to private"); return glnx_throw_errno_prefix (error, "Failed to set the mount propagation to private");
} }
else
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
ostree_sysroot_set_mount_namespace_in_use (self); ostree_sysroot_set_mount_namespace_in_use (self);
@ -334,7 +335,7 @@ ostree_sysroot_initialize_with_mount_namespace (OstreeSysroot *self, GCancellabl
if (!ostree_sysroot_initialize (self, error)) if (!ostree_sysroot_initialize (self, error))
return FALSE; return FALSE;
return _ostree_sysroot_enter_mount_namespace (self, cancellable, error); return _ostree_sysroot_enter_mount_namespace (self, error);
} }
/** /**
@ -400,20 +401,33 @@ remount_writable (const char *path, gboolean *did_remount, GError **error)
} }
static gboolean static gboolean
is_sysroot_invisible (void) _ostree_sysroot_invisible (gboolean *out_val, GError **error)
{ {
struct stat stbuf; gboolean exists;
if (lstat (OTCORE_RUN_OSTREE_PRIVATE "/sysroot-ns", &stbuf) < 0) if (!ot_path_exists (OTCORE_RUN_OSTREE_PRIVATE "/sysroot-ns", &exists, error))
return FALSE; return FALSE;
if (lstat ("/sysroot/ostree", &stbuf) == 0) if (!exists)
{
*out_val = FALSE;
return TRUE;
}
if (!ot_path_exists ("/sysroot/ostree", &exists, error))
return FALSE; return FALSE;
if (exists)
{
*out_val = FALSE;
return TRUE;
}
*out_val = TRUE;
return TRUE; return TRUE;
} }
/* Unmount covering tmpfs to make /sysroot visible */ /* Make /sysroot visible */
gboolean gboolean
_ostree_sysroot_ensure_visible (OstreeSysroot *self, GError **error) _ostree_sysroot_ensure_visible (OstreeSysroot *self, GError **error)
{ {
@ -430,8 +444,10 @@ _ostree_sysroot_ensure_visible (OstreeSysroot *self, GError **error)
if (!self->root_is_ostree_booted) if (!self->root_is_ostree_booted)
return TRUE; return TRUE;
gboolean invisible;
g_return_val_if_fail (_ostree_sysroot_invisible (&invisible, error), FALSE);
/* Handle invisible sysroot */ /* Handle invisible sysroot */
if (is_sysroot_invisible ()) if (invisible)
{ {
glnx_autofd int sysroot_ns_fd = open (OTCORE_RUN_OSTREE_PRIVATE "/sysroot-ns", O_RDONLY); glnx_autofd int sysroot_ns_fd = open (OTCORE_RUN_OSTREE_PRIVATE "/sysroot-ns", O_RDONLY);
if (sysroot_ns_fd < 0) if (sysroot_ns_fd < 0)
@ -1158,9 +1174,11 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error)
return TRUE; return TRUE;
} }
if (is_sysroot_invisible ()) gboolean invisible;
g_return_val_if_fail (_ostree_sysroot_invisible (&invisible, error), FALSE);
if (invisible)
{ {
if (!_ostree_sysroot_enter_mount_namespace (self, NULL, error)) if (!_ostree_sysroot_enter_mount_namespace (self, error))
return FALSE; return FALSE;
if (!_ostree_sysroot_ensure_visible (self, error)) if (!_ostree_sysroot_ensure_visible (self, error))
return FALSE; return FALSE;

View File

@ -277,3 +277,26 @@ ot_get_dir_size (int dfd, const char *path, guint64 blocksize, guint64 *out_size
return TRUE; return TRUE;
} }
/* Check whether a path exists */
gboolean
ot_path_exists (const char *path, gboolean *out_val, GError **error)
{
g_autoptr (GError) local_error = NULL;
struct stat stbuf;
if (glnx_fstatat (AT_FDCWD, path, &stbuf, 0, &local_error))
{
*out_val = TRUE;
return TRUE;
}
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
*out_val = FALSE;
return TRUE;
}
g_propagate_error (error, local_error);
return FALSE;
}

View File

@ -78,4 +78,6 @@ gboolean ot_parse_file_by_line (const char *path, gboolean (*cb) (const char *,
gboolean ot_get_dir_size (int dfd, const char *path, guint64 blocksize, guint64 *out_size, gboolean ot_get_dir_size (int dfd, const char *path, guint64 blocksize, guint64 *out_size,
GCancellable *cancellable, GError **error); GCancellable *cancellable, GError **error);
gboolean ot_path_exists (const char *path, gboolean *out_val, GError **error);
G_END_DECLS G_END_DECLS