From 38eac0729318cae02b05d7f5673628028d075a58 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 9 Apr 2021 14:42:12 +0100 Subject: [PATCH] run: Create a shared XDG_RUNTIME_DIR for each app-ID Like $XDG_RUNTIME_DIR/app/$FLATPAK_ID, this is shared between all instances of the app, except for subsandboxed instances created by flatpak-spawn --sandbox or equivalent. Unlike $XDG_RUNTIME_DIR/app/$FLATPAK_ID, it does not exist at an equivalent path on the host and in the sandboxed app. Resolves: https://github.com/flatpak/flatpak/issues/4120 Signed-off-by: Simon McVittie --- app/flatpak-builtins-build.c | 2 +- common/flatpak-bwrap-private.h | 3 +- common/flatpak-bwrap.c | 66 +++++++++++++++++++++++++++---- common/flatpak-dir.c | 2 +- common/flatpak-instance-private.h | 4 ++ common/flatpak-instance.c | 41 +++++++++++++++++++ common/flatpak-run.c | 13 +++++- 7 files changed, 119 insertions(+), 12 deletions(-) diff --git a/app/flatpak-builtins-build.c b/app/flatpak-builtins-build.c index 4ae3bacf..0c4c5ce3 100644 --- a/app/flatpak-builtins-build.c +++ b/app/flatpak-builtins-build.c @@ -580,7 +580,7 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError NULL); } - flatpak_bwrap_populate_runtime_dir (bwrap); + flatpak_bwrap_populate_runtime_dir (bwrap, NULL); flatpak_bwrap_envp_to_args (bwrap); diff --git a/common/flatpak-bwrap-private.h b/common/flatpak-bwrap-private.h index 9d6b6311..207d23a0 100644 --- a/common/flatpak-bwrap-private.h +++ b/common/flatpak-bwrap-private.h @@ -85,7 +85,8 @@ gboolean flatpak_bwrap_bundle_args (FlatpakBwrap *bwrap, GError **error); void flatpak_bwrap_add_runtime_dir_member (FlatpakBwrap *bwrap, const char *name); -void flatpak_bwrap_populate_runtime_dir (FlatpakBwrap *bwrap); +void flatpak_bwrap_populate_runtime_dir (FlatpakBwrap *bwrap, + const char *shared_xdg_runtime_dir); void flatpak_bwrap_child_setup_cb (gpointer user_data); void flatpak_bwrap_child_setup (GArray *fd_array, diff --git a/common/flatpak-bwrap.c b/common/flatpak-bwrap.c index 0faed691..cda0dbfb 100644 --- a/common/flatpak-bwrap.c +++ b/common/flatpak-bwrap.c @@ -417,12 +417,51 @@ flatpak_bwrap_add_runtime_dir_member (FlatpakBwrap *bwrap, g_ptr_array_add (bwrap->runtime_dir_members, g_strdup (name)); } -void -flatpak_bwrap_populate_runtime_dir (FlatpakBwrap *bwrap) +static void +expect_symlink (const char *host_path, + const char *target) { - flatpak_bwrap_add_arg (bwrap, "--symlink"); - flatpak_bwrap_add_arg (bwrap, "../../../.flatpak-info"); - flatpak_bwrap_add_arg_printf (bwrap, "/run/user/%d/flatpak-info", getuid ()); + /* This shouldn't fail in practice, so there's not much point in + * translating the warning */ + if (symlink (target, host_path) < 0 && errno != EEXIST) + { + g_warning ("Unable to create symlink at %s: %s", + host_path, g_strerror (errno)); + } + else + { + g_autoptr(GError) local_error = NULL; + g_autofree char *got = glnx_readlinkat_malloc (AT_FDCWD, + host_path, + NULL, + &local_error); + + if (got == NULL) + g_warning ("%s is not a symlink to \"%s\" as expected: %s", + host_path, target, local_error->message); + else if (strcmp (got, target) != 0) + g_warning ("%s is a symlink to \"%s\", not \"%s\" as expected", + host_path, got, target); + } +} + +void +flatpak_bwrap_populate_runtime_dir (FlatpakBwrap *bwrap, + const char *shared_xdg_runtime_dir) +{ + if (shared_xdg_runtime_dir != NULL) + { + g_autofree char *host_path = g_build_filename (shared_xdg_runtime_dir, + "flatpak-info", NULL); + + expect_symlink (host_path, "../../../.flatpak-info"); + } + else + { + flatpak_bwrap_add_arg (bwrap, "--symlink"); + flatpak_bwrap_add_arg (bwrap, "../../../.flatpak-info"); + flatpak_bwrap_add_arg_printf (bwrap, "/run/user/%d/flatpak-info", getuid ()); + } if (bwrap->runtime_dir_members != NULL) { @@ -431,10 +470,21 @@ flatpak_bwrap_populate_runtime_dir (FlatpakBwrap *bwrap) for (i = 0; i < bwrap->runtime_dir_members->len; i++) { const char *member = g_ptr_array_index (bwrap->runtime_dir_members, i); + g_autofree char *target = g_strdup_printf ("../../flatpak/%s", member); - flatpak_bwrap_add_arg (bwrap, "--symlink"); - flatpak_bwrap_add_arg_printf (bwrap, "../../flatpak/%s", member); - flatpak_bwrap_add_arg_printf (bwrap, "/run/user/%d/%s", getuid (), member); + if (shared_xdg_runtime_dir != NULL) + { + g_autofree char *host_path = g_build_filename (shared_xdg_runtime_dir, + member, NULL); + + expect_symlink (host_path, target); + } + else + { + flatpak_bwrap_add_arg (bwrap, "--symlink"); + flatpak_bwrap_add_arg (bwrap, target); + flatpak_bwrap_add_arg_printf (bwrap, "/run/user/%d/%s", getuid (), member); + } } } } diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 5ec908ad..07f8730d 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -7857,7 +7857,7 @@ apply_extra_data (FlatpakDir *self, NULL, cancellable, error)) return FALSE; - flatpak_bwrap_populate_runtime_dir (bwrap); + flatpak_bwrap_populate_runtime_dir (bwrap, NULL); flatpak_bwrap_envp_to_args (bwrap); diff --git a/common/flatpak-instance-private.h b/common/flatpak-instance-private.h index 63c74dde..6fcd178b 100644 --- a/common/flatpak-instance-private.h +++ b/common/flatpak-instance-private.h @@ -52,5 +52,9 @@ gboolean flatpak_instance_ensure_per_app_tmp (const char *app_id, int per_app_dir_lock_fd, char **shared_tmp_out, GError **error); +gboolean flatpak_instance_ensure_per_app_xdg_runtime_dir (const char *app_id, + int per_app_dir_lock_fd, + char **shared_dir_out, + GError **error); #endif /* __FLATPAK_INSTANCE_PRIVATE_H__ */ diff --git a/common/flatpak-instance.c b/common/flatpak-instance.c index 64ae4597..234a4b8b 100644 --- a/common/flatpak-instance.c +++ b/common/flatpak-instance.c @@ -671,6 +671,47 @@ flatpak_instance_ensure_per_app_tmp (const char *app_id, return TRUE; } +/* + * @app_id: $FLATPAK_ID + * @per_app_dir_lock_fd: Used to prove that we have already taken out + * a per-app non-exclusive lock to stop this directory from being + * garbage-collected + * @shared_dir_out: (out) (not optional) (not nullable): Used to return + * the path to the shared $XDG_RUNTIME_DIR + * + * Create a per-app $XDG_RUNTIME_DIR. + */ +gboolean +flatpak_instance_ensure_per_app_xdg_runtime_dir (const char *app_id, + int per_app_dir_lock_fd, + char **shared_dir_out, + GError **error) +{ + g_autofree char *per_app_parent = NULL; + g_autofree char *shared_dir = NULL; + + g_return_val_if_fail (app_id != NULL, FALSE); + g_return_val_if_fail (shared_dir_out != NULL, FALSE); + g_return_val_if_fail (*shared_dir_out == NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* We don't actually do anything with this, we just pass it in here as + * proof that we already set up the directory that contains the lock + * file for per-app things, to force us to get the sequence right */ + g_return_val_if_fail (per_app_dir_lock_fd >= 0, FALSE); + + per_app_parent = flatpak_instance_get_apps_directory (); + shared_dir = g_build_filename (per_app_parent, app_id, "xdg-run", NULL); + + if (g_mkdir_with_parents (shared_dir, 0700) != 0) + return glnx_throw_errno_prefix (error, + _("Unable to create directory %s"), + shared_dir); + + *shared_dir_out = g_steal_pointer (&shared_dir); + return TRUE; +} + /* * @host_dir_out: (not optional): used to return the directory on the host * system representing this instance diff --git a/common/flatpak-run.c b/common/flatpak-run.c index f53e73ef..e6473107 100644 --- a/common/flatpak-run.c +++ b/common/flatpak-run.c @@ -3834,6 +3834,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref, g_autofree char *checksum = NULL; glnx_autofd int per_app_dir_lock_fd = -1; g_autofree char *per_app_dir_lock_path = NULL; + g_autofree char *shared_xdg_runtime_dir = NULL; int ld_so_fd = -1; g_autoptr(GFile) runtime_ld_so_conf = NULL; gboolean generate_ld_so_conf = TRUE; @@ -4261,6 +4262,16 @@ flatpak_run_app (FlatpakDecomposed *app_ref, &per_app_dir_lock_path, error)) return FALSE; + + if (!flatpak_instance_ensure_per_app_xdg_runtime_dir (app_id, + per_app_dir_lock_fd, + &shared_xdg_runtime_dir, + error)) + return FALSE; + + flatpak_bwrap_add_arg (bwrap, "--bind"); + flatpak_bwrap_add_arg (bwrap, shared_xdg_runtime_dir); + flatpak_bwrap_add_arg_printf (bwrap, "/run/user/%d", getuid ()); } if (!flatpak_run_add_dconf_args (bwrap, app_id, metakey, error)) @@ -4330,7 +4341,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref, flatpak_bwrap_add_args_data_fd (bwrap, "--pidns", pidns_fd, NULL); } - flatpak_bwrap_populate_runtime_dir (bwrap); + flatpak_bwrap_populate_runtime_dir (bwrap, shared_xdg_runtime_dir); if (custom_command) {