diff --git a/app/flatpak-builtins-build.c b/app/flatpak-builtins-build.c index 8d3397bd..e94523bb 100644 --- a/app/flatpak-builtins-build.c +++ b/app/flatpak-builtins-build.c @@ -516,7 +516,13 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError /* Never set up an a11y bus for builds */ run_flags |= FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY; - if (!flatpak_run_setup_base_argv (bwrap, runtime_files, app_id_dir, arch, + glnx_autofd int usr_fd = -1; + usr_fd = open (flatpak_file_get_path_cached (runtime_files), + O_PATH | O_CLOEXEC | O_NOFOLLOW); + if (usr_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open runtime files"); + + if (!flatpak_run_setup_base_argv (bwrap, usr_fd, app_id_dir, arch, run_flags, error)) return FALSE; diff --git a/app/flatpak-builtins-run.c b/app/flatpak-builtins-run.c index 9b80cb25..b5166ec2 100644 --- a/app/flatpak-builtins-run.c +++ b/app/flatpak-builtins-run.c @@ -113,6 +113,8 @@ flatpak_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** g_autoptr(GError) local_error = NULL; g_autoptr(GPtrArray) dirs = NULL; FlatpakRunFlags flags = 0; + glnx_autofd int app_fd = -1; + glnx_autofd int usr_fd = -1; run_environ = g_get_environ (); @@ -313,14 +315,45 @@ flatpak_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** if (!opt_clear_env) flags |= FLATPAK_RUN_FLAG_CLEAR_ENV; + if (opt_app_path != NULL) + { + if (g_strcmp0 (opt_app_path, "") == 0) + { + app_fd = FLATPAK_RUN_APP_DEPLOY_APP_EMPTY; + } + else + { + app_fd = open (opt_app_path, O_PATH | O_CLOEXEC | O_NOFOLLOW); + + if (app_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open app-path"); + } + } + else + { + app_fd = FLATPAK_RUN_APP_DEPLOY_APP_ORIGINAL; + } + + if (opt_usr_path != NULL) + { + usr_fd = open (opt_usr_path, O_PATH | O_CLOEXEC | O_NOFOLLOW); + + if (usr_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open usr-path"); + } + else + { + usr_fd = FLATPAK_RUN_APP_DEPLOY_USR_ORIGINAL; + } + if (!flatpak_run_app (app_deploy ? app_ref : runtime_ref, app_deploy, - opt_app_path, + app_fd, arg_context, opt_runtime, opt_runtime_version, opt_runtime_commit, - opt_usr_path, + usr_fd, opt_parent_pid, flags, opt_cwd, diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index be6ec15f..5c11e991 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -9316,7 +9316,13 @@ apply_extra_data (FlatpakDir *self, * Disable /proc entirely in this context. */ run_flags |= FLATPAK_RUN_FLAG_NO_PROC; - if (!flatpak_run_setup_base_argv (bwrap, runtime_files, NULL, runtime_arch, + glnx_autofd int usr_fd = -1; + usr_fd = open (flatpak_file_get_path_cached (runtime_files), + O_PATH | O_CLOEXEC | O_NOFOLLOW); + if (usr_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open runtime files"); + + if (!flatpak_run_setup_base_argv (bwrap, usr_fd, NULL, runtime_arch, run_flags, error)) return FALSE; diff --git a/common/flatpak-installation.c b/common/flatpak-installation.c index 7d75c413..f0fd88e4 100644 --- a/common/flatpak-installation.c +++ b/common/flatpak-installation.c @@ -700,9 +700,10 @@ flatpak_installation_launch_full (FlatpakInstallation *self, if (!flatpak_run_app (app_ref, app_deploy, + FLATPAK_RUN_APP_DEPLOY_APP_ORIGINAL, NULL, - NULL, NULL, NULL, NULL, NULL, + FLATPAK_RUN_APP_DEPLOY_USR_ORIGINAL, 0, run_flags, NULL, diff --git a/common/flatpak-run-private.h b/common/flatpak-run-private.h index d46996de..2e6fbfad 100644 --- a/common/flatpak-run-private.h +++ b/common/flatpak-run-private.h @@ -30,6 +30,11 @@ #include "flatpak-utils-private.h" #include "flatpak-exports-private.h" +#define FLATPAK_RUN_APP_DEPLOY_APP_ORIGINAL (-2) +#define FLATPAK_RUN_APP_DEPLOY_APP_EMPTY (-3) + +#define FLATPAK_RUN_APP_DEPLOY_USR_ORIGINAL (-2) + gboolean flatpak_run_in_transient_unit (const char *app_id, const char *instance_id, GError **error); @@ -76,7 +81,7 @@ gboolean flatpak_ensure_data_dir (GFile *app_id_dir, GError **error); gboolean flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, - GFile *runtime_files, + int runtime_fd, GFile *app_id_dir, const char *arch, FlatpakRunFlags flags, @@ -109,12 +114,12 @@ gboolean flatpak_run_add_app_info_args (FlatpakBwrap *bwrap, gboolean flatpak_run_app (FlatpakDecomposed *app_ref, FlatpakDeploy *app_deploy, - const char *custom_app_path, + int custom_app_fd, FlatpakContext *extra_context, const char *custom_runtime, const char *custom_runtime_version, const char *custom_runtime_commit, - const char *custom_usr_path, + int custom_usr_fd, int parent_pid, FlatpakRunFlags flags, const char *cwd, diff --git a/common/flatpak-run.c b/common/flatpak-run.c index cba9e1a6..f6523577 100644 --- a/common/flatpak-run.c +++ b/common/flatpak-run.c @@ -1661,40 +1661,56 @@ flatpak_run_add_app_info_args (FlatpakBwrap *bwrap, static void add_tzdata_args (FlatpakBwrap *bwrap, - GFile *runtime_files) + int runtime_fd) { - g_autofree char *raw_timezone = flatpak_get_timezone (); - g_autofree char *timezone_content = g_strdup_printf ("%s\n", raw_timezone); - g_autofree char *localtime_content = g_strconcat ("../usr/share/zoneinfo/", raw_timezone, NULL); - g_autoptr(GFile) runtime_zoneinfo = NULL; + g_autofree char *raw_timezone = NULL; + g_autofree char *timezone_content = NULL; + g_autofree char *localtime_content = NULL; + const char *tzdir; + glnx_autofd int tzdir_fd = -1; + glnx_autofd int zoneinfo_fd = -1; + g_autoptr(GError) error = NULL; - if (runtime_files) - runtime_zoneinfo = g_file_resolve_relative_path (runtime_files, "share/zoneinfo"); + raw_timezone = flatpak_get_timezone (); + timezone_content = g_strdup_printf ("%s\n", raw_timezone); + localtime_content = g_strconcat ("../usr/share/zoneinfo/", raw_timezone, NULL); - /* Check for runtime /usr/share/zoneinfo */ - if (runtime_zoneinfo != NULL && g_file_query_exists (runtime_zoneinfo, NULL)) + tzdir = flatpak_get_tzdir (); + + tzdir_fd = glnx_chaseat (AT_FDCWD, tzdir, GLNX_CHASE_MUST_BE_DIRECTORY, NULL); + + zoneinfo_fd = glnx_chaseat (runtime_fd, "share/zoneinfo", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_DIRECTORY, + NULL); + + /* Check for host /usr/share/zoneinfo */ + if (tzdir_fd >= 0 && zoneinfo_fd >= 0) { - const char *tzdir = flatpak_get_tzdir (); + /* Here we assume the host timezone file exist in the host data */ + flatpak_bwrap_add_args (bwrap, + "--ro-bind", tzdir, "/usr/share/zoneinfo", + "--symlink", localtime_content, "/etc/localtime", + NULL); + } + else + { + g_autofree char *runtime_zoneinfo = NULL; + glnx_autofd int runtime_zoneinfo_fd = -1; - /* Check for host /usr/share/zoneinfo */ - if (g_file_test (tzdir, G_FILE_TEST_IS_DIR)) + runtime_zoneinfo = g_strconcat ("share/zoneinfo/", raw_timezone, NULL); + + /* Check for runtime /usr/share/zoneinfo */ + runtime_zoneinfo_fd = glnx_chaseat (runtime_fd, runtime_zoneinfo, + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + NULL); + if (runtime_zoneinfo_fd >= 0) { - /* Here we assume the host timezone file exist in the host data */ flatpak_bwrap_add_args (bwrap, - "--ro-bind", tzdir, "/usr/share/zoneinfo", "--symlink", localtime_content, "/etc/localtime", NULL); } - else - { - g_autoptr(GFile) runtime_tzfile = g_file_resolve_relative_path (runtime_zoneinfo, raw_timezone); - - /* Check if host timezone file exist in the runtime tzdata */ - if (g_file_query_exists (runtime_tzfile, NULL)) - flatpak_bwrap_add_args (bwrap, - "--symlink", localtime_content, "/etc/localtime", - NULL); - } } flatpak_bwrap_add_args_data (bwrap, "timezone", @@ -2178,24 +2194,41 @@ setup_seccomp (FlatpakBwrap *bwrap, static void flatpak_run_setup_usr_links (FlatpakBwrap *bwrap, - GFile *runtime_files, + int runtime_fd, const char *sysroot) { int i; - if (runtime_files == NULL) + g_return_if_fail (runtime_fd >= -1); + + if (runtime_fd < 0) return; for (i = 0; flatpak_abs_usrmerged_dirs[i] != NULL; i++) { const char *subdir = flatpak_abs_usrmerged_dirs[i]; - g_autoptr(GFile) runtime_subdir = NULL; + glnx_autofd int runtime_subdir_fd = -1; + g_autoptr(GError) local_error = NULL; g_assert (subdir[0] == '/'); - /* Skip the '/' when using as a subdirectory of the runtime */ - runtime_subdir = g_file_get_child (runtime_files, subdir + 1); - if (g_file_query_exists (runtime_subdir, NULL)) + /* Skip the '/' when using as a subdirectory of the runtime */ + runtime_subdir_fd = glnx_chaseat (runtime_fd, subdir + 1, + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_NOFOLLOW, + &local_error); + + if (runtime_subdir_fd < 0 && + !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_warning ("Checking for usrmerged dir %s failed: %s", + subdir, local_error->message); + } + else if (runtime_subdir_fd < 0) + { + g_info ("%s does not exist in runtime", subdir); + } + else { g_autofree char *link = g_strconcat ("usr", subdir, NULL); g_autofree char *create = NULL; @@ -2209,11 +2242,6 @@ flatpak_run_setup_usr_links (FlatpakBwrap *bwrap, "--symlink", link, create, NULL); } - else - { - g_info ("%s does not exist", - flatpak_file_get_path_cached (runtime_subdir)); - } } } @@ -2229,7 +2257,7 @@ static const char *const sysfs_dirs[] = gboolean flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, - GFile *runtime_files, + int runtime_fd, GFile *app_id_dir, const char *arch, FlatpakRunFlags flags, @@ -2242,12 +2270,13 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, struct group *g; gulong pers; gid_t gid = getgid (); - g_autoptr(GFile) etc = NULL; gboolean parent_expose_pids = (flags & FLATPAK_RUN_FLAG_PARENT_EXPOSE_PIDS) != 0; gboolean parent_share_pids = (flags & FLATPAK_RUN_FLAG_PARENT_SHARE_PIDS) != 0; gboolean bwrap_unprivileged = flatpak_bwrap_is_unprivileged (); gsize i; + g_return_val_if_fail (runtime_fd >= 0, FALSE); + /* Disable recursive userns for all flatpak processes, as we need this * to guarantee that the sandbox can't restructure the filesystem. * Allowing to change e.g. /.flatpak-info would allow sandbox escape @@ -2355,22 +2384,25 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, else if (g_file_test ("/var/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) flatpak_bwrap_add_args (bwrap, "--ro-bind", "/var/lib/dbus/machine-id", "/etc/machine-id", NULL); - if (runtime_files) - etc = g_file_get_child (runtime_files, "etc"); - if (etc != NULL && - (flags & FLATPAK_RUN_FLAG_WRITABLE_ETC) == 0 && - g_file_query_exists (etc, NULL)) + if ((flags & FLATPAK_RUN_FLAG_WRITABLE_ETC) == 0) { g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; struct dirent *dent; gboolean inited; + g_autoptr(GError) local_error = NULL; - inited = glnx_dirfd_iterator_init_at (AT_FDCWD, flatpak_file_get_path_cached (etc), FALSE, &dfd_iter, NULL); + inited = glnx_dirfd_iterator_init_at (runtime_fd, "etc", FALSE, &dfd_iter, &local_error); + if (!inited && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } while (inited) { - g_autofree char *src = NULL; g_autofree char *dest = NULL; + glnx_autofd int src_fd = -1; + struct stat statbuf; if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, NULL) || dent == NULL) break; @@ -2387,9 +2419,19 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, strcmp (dent->d_name, "pkcs11") == 0) continue; - src = g_build_filename (flatpak_file_get_path_cached (etc), dent->d_name, NULL); dest = g_build_filename ("/etc", dent->d_name, NULL); - if (dent->d_type == DT_LNK) + + src_fd = glnx_chaseat (dfd_iter.fd, dent->d_name, + GLNX_CHASE_NOFOLLOW | + GLNX_CHASE_RESOLVE_BENEATH, + error); + if (src_fd < 0) + return FALSE; + + if (!glnx_fstat (src_fd, &statbuf, error)) + return FALSE; + + if (S_ISLNK (statbuf.st_mode)) { g_autofree char *target = NULL; @@ -2400,9 +2442,12 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, flatpak_bwrap_add_args (bwrap, "--symlink", target, dest, NULL); } - else + else if (src_fd >= 0) { - flatpak_bwrap_add_args (bwrap, "--ro-bind", src, dest, NULL); + flatpak_bwrap_add_args_data_fd (bwrap, + "--ro-bind-fd", + g_steal_fd (&src_fd), + dest); } } } @@ -2423,9 +2468,9 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap, NULL); } - flatpak_run_setup_usr_links (bwrap, runtime_files, NULL); + flatpak_run_setup_usr_links (bwrap, runtime_fd, NULL); - add_tzdata_args (bwrap, runtime_files); + add_tzdata_args (bwrap, runtime_fd); pers = PER_LINUX; @@ -2696,7 +2741,7 @@ regenerate_ld_cache (GPtrArray *base_argv_array, GArray *base_fd_array, GFile *app_id_dir, const char *checksum, - GFile *runtime_files, + int runtime_fd, gboolean generate_ld_so_conf, GCancellable *cancellable, GError **error) @@ -2736,7 +2781,7 @@ regenerate_ld_cache (GPtrArray *base_argv_array, flatpak_bwrap_append_args (bwrap, base_argv_array); - flatpak_run_setup_usr_links (bwrap, runtime_files, NULL); + flatpak_run_setup_usr_links (bwrap, runtime_fd, NULL); if (generate_ld_so_conf) { @@ -2951,6 +2996,42 @@ open_namespace_fd_if_needed (const char *path, return -1; } +static char * +get_path_for_fd (int fd, + GError **error) +{ + g_autofree char *proc_path = NULL; + g_autofree char *path = NULL; + + proc_path = g_strdup_printf ("/proc/self/fd/%d", fd); + path = glnx_readlinkat_malloc (AT_FDCWD, proc_path, NULL, error); + if (path == NULL) + return NULL; + + /* All normal paths start with /, but some weird things + don't, such as socket:[27345] or anon_inode:[eventfd]. + We don't support any of these */ + if (path[0] != '/') + { + return glnx_null_throw (error, "%s resolves to non-absolute path %s", + proc_path, path); + } + + /* File descriptors to actually deleted files have " (deleted)" + appended to them. This also happens to some fake fd types + like shmem which are "/ (deleted)". All such + files are considered invalid. Unfortunately this also + matches files with filenames that actually end in " (deleted)", + but there is not much to do about this. */ + if (g_str_has_suffix (path, " (deleted)")) + { + return glnx_null_throw (error, "%s resolves to deleted path %s", + proc_path, path); + } + + return g_steal_pointer (&path); +} + FlatpakContextShares flatpak_run_compute_allowed_shares (FlatpakContext *context) { @@ -2982,12 +3063,12 @@ flatpak_run_compute_allowed_features (FlatpakContext *context) gboolean flatpak_run_app (FlatpakDecomposed *app_ref, FlatpakDeploy *app_deploy, - const char *custom_app_path, + int custom_app_fd, FlatpakContext *extra_context, const char *custom_runtime, const char *custom_runtime_version, const char *custom_runtime_commit, - const char *custom_usr_path, + int custom_runtime_fd, int parent_pid, FlatpakRunFlags flags, const char *cwd, @@ -3003,11 +3084,6 @@ flatpak_run_app (FlatpakDecomposed *app_ref, g_autoptr(FlatpakDeploy) runtime_deploy = NULL; g_autoptr(GBytes) runtime_deploy_data = NULL; g_autoptr(GBytes) app_deploy_data = NULL; - g_autoptr(GFile) app_files = NULL; - g_autoptr(GFile) original_app_files = NULL; - g_autoptr(GFile) runtime_files = NULL; - g_autoptr(GFile) original_runtime_files = NULL; - g_autoptr(GFile) bin_ldconfig = NULL; g_autoptr(GFile) app_id_dir = NULL; g_autoptr(GFile) real_app_id_dir = NULL; g_autofree char *default_runtime_pref = NULL; @@ -3041,24 +3117,45 @@ flatpak_run_app (FlatpakDecomposed *app_ref, 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; gboolean use_ld_so_cache = TRUE; gboolean sandboxed = (flags & FLATPAK_RUN_FLAG_SANDBOX) != 0; gboolean parent_expose_pids = (flags & FLATPAK_RUN_FLAG_PARENT_EXPOSE_PIDS) != 0; gboolean parent_share_pids = (flags & FLATPAK_RUN_FLAG_PARENT_SHARE_PIDS) != 0; - const char *app_target_path = "/app"; - const char *runtime_target_path = "/usr"; - struct stat s; FlatpakContextShares shares; FlatpakContextDevices devices; FlatpakContextSockets sockets; FlatpakContextFeatures features; + glnx_autofd int original_runtime_fd = -1; + g_autoptr(GFile) original_runtime_files = NULL; + g_autoptr(GFile) custom_runtime_files = NULL; + /* borrows from either original_runtime_fd or custom_runtime_fd */ + int runtime_fd = -1; + /* borrows from either original_runtime_files or custom_runtime_files */ + GFile *runtime_files = NULL; + const char *original_runtime_target_path = NULL; + glnx_autofd int original_app_fd = -1; + g_autoptr(GFile) original_app_files = NULL; + g_autoptr(GFile) custom_app_files = NULL; + /* borrows from either original_app_fd or custom_app_fd */ + int app_fd = -1; + /* borrows from either original_app_files or custom_app_files */ + GFile *app_files = NULL; + const char *original_app_target_path = NULL; g_assert (run_environ != NULL); g_return_val_if_fail (app_ref != NULL, FALSE); + g_return_val_if_fail (custom_app_fd == FLATPAK_RUN_APP_DEPLOY_APP_ORIGINAL || + custom_app_fd == FLATPAK_RUN_APP_DEPLOY_APP_EMPTY || + custom_app_fd >= 0, + FALSE); + + g_return_val_if_fail (custom_runtime_fd == FLATPAK_RUN_APP_DEPLOY_USR_ORIGINAL || + custom_runtime_fd >= 0, + FALSE); + /* This check exists to stop accidental usage of `sudo flatpak run` and is not to prevent running as root. */ @@ -3190,38 +3287,53 @@ flatpak_run_app (FlatpakDecomposed *app_ref, features = flatpak_run_compute_allowed_features (app_context); original_runtime_files = flatpak_deploy_get_files (runtime_deploy); + original_runtime_fd = open (flatpak_file_get_path_cached (original_runtime_files), + O_PATH | O_CLOEXEC); + if (original_runtime_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open original runtime"); - if (custom_usr_path != NULL) + if (custom_runtime_fd >= 0) { - runtime_files = g_file_new_for_path (custom_usr_path); - /* Mount the original runtime below here instead of /usr */ - runtime_target_path = "/run/parent/usr"; + g_autofree char *path = NULL; + + path = get_path_for_fd (custom_runtime_fd, &my_error); + if (path == NULL) + { + return flatpak_fail_error (error, FLATPAK_ERROR, + "Cannot convert custom usr fd to path: %s", + my_error->message); + } + + custom_runtime_files = g_file_new_for_path (path); + + original_runtime_target_path = "/run/parent/usr"; + runtime_fd = custom_runtime_fd; + runtime_files = custom_runtime_files; + } + else if (custom_app_fd == FLATPAK_RUN_APP_DEPLOY_USR_ORIGINAL) + { + original_runtime_target_path = "/usr"; + runtime_fd = original_runtime_fd; + runtime_files = original_runtime_files; } else { - runtime_files = g_object_ref (original_runtime_files); + g_assert_not_reached (); } - bin_ldconfig = g_file_resolve_relative_path (runtime_files, "bin/ldconfig"); - if (!g_file_query_exists (bin_ldconfig, NULL)) - use_ld_so_cache = FALSE; - - /* We can't use the ld.so cache if we are using a custom /usr or /app, - * because we don't have a unique ID for the /usr or /app, so we can't - * do cache-invalidation correctly. The caller can either build their - * own ld.so.cache before supplying us with the runtime, or supply - * their own LD_LIBRARY_PATH. */ - if (custom_usr_path != NULL || custom_app_path != NULL) - use_ld_so_cache = FALSE; - if (app_deploy != NULL) { g_autofree const char **previous_ids = NULL; gsize len = 0; gboolean do_migrate; - real_app_id_dir = flatpak_get_data_dir (app_id); original_app_files = flatpak_deploy_get_files (app_deploy); + original_app_fd = open (flatpak_file_get_path_cached (original_app_files), + O_PATH | O_CLOEXEC | O_NOFOLLOW); + if (original_app_fd < 0) + return glnx_throw_errno_prefix (error, "Failed to open original runtime"); + + real_app_id_dir = flatpak_get_data_dir (app_id); previous_app_id_dirs = g_ptr_array_new_with_free_func (g_object_unref); previous_ids = flatpak_deploy_data_get_previous_ids (app_deploy_data, &len); @@ -3308,19 +3420,60 @@ flatpak_run_app (FlatpakDecomposed *app_ref, app_id_dir = g_object_ref (real_app_id_dir); } - if (custom_app_path != NULL) + if (custom_app_fd >= 0) { - if (strcmp (custom_app_path, "") == 0) - app_files = NULL; - else - app_files = g_file_new_for_path (custom_app_path); + g_autofree char *path = NULL; - /* Mount the original app below here */ - app_target_path = "/run/parent/app"; + path = get_path_for_fd (custom_app_fd, error); + if (path == NULL) + return glnx_prefix_error (error, "Cannot convert custom app fd to path"); + + custom_app_files = g_file_new_for_path (path); + + original_app_target_path = "/run/parent/app"; + app_fd = custom_app_fd; + app_files = custom_app_files; } - else if (original_app_files != NULL) + else if (custom_app_fd == FLATPAK_RUN_APP_DEPLOY_APP_ORIGINAL) { - app_files = g_object_ref (original_app_files); + original_app_target_path = "/app"; + app_fd = original_app_fd; + app_files = original_app_files; + } + else if (custom_app_fd == FLATPAK_RUN_APP_DEPLOY_APP_EMPTY) + { + app_fd = -1; + app_files = NULL; + } + else + { + g_assert_not_reached (); + } + + /* We can't use the ld.so cache if we are using a custom /usr or /app, + * because we don't have a unique ID for the /usr or /app, so we can't + * do cache-invalidation correctly. The caller can either build their + * own ld.so.cache before supplying us with the runtime, or supply + * their own LD_LIBRARY_PATH. */ + if (runtime_fd == custom_runtime_fd || app_fd == custom_app_fd) + { + use_ld_so_cache = FALSE; + } + else + { + glnx_autofd int ldconfig_fd = -1; + + ldconfig_fd = glnx_chaseat (runtime_fd, "bin/ldconfig", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + &my_error); + if (ldconfig_fd < 0) + { + use_ld_so_cache = FALSE; + g_debug ("bin/ldconfig not found in runtime: %s", my_error->message); + } + + g_clear_error (&my_error); } flatpak_run_apply_env_clear (bwrap, !!(flags & FLATPAK_RUN_FLAG_CLEAR_ENV)); @@ -3334,75 +3487,86 @@ flatpak_run_app (FlatpakDecomposed *app_ref, flatpak_bwrap_set_env (bwrap, "FLATPAK_SANDBOX_DIR", flatpak_file_get_path_cached (sandbox_dir), TRUE); } - flatpak_bwrap_add_args (bwrap, - "--ro-bind", flatpak_file_get_path_cached (runtime_files), "/usr", - NULL); + if (!flatpak_bwrap_add_args_data_fd_dup (bwrap, + "--ro-bind-fd", runtime_fd, "/usr", + error)) + return FALSE; - if (runtime_files == original_runtime_files) - { - /* All true Flatpak runtimes have files/.ref */ - flatpak_bwrap_add_args (bwrap, - "--lock-file", "/usr/.ref", - NULL); - } - else - { - g_autoptr(GFile) runtime_child = NULL; + { + glnx_autofd int runtime_ref_fd = -1; - runtime_child = g_file_get_child (runtime_files, ".ref"); - - /* Lock ${usr}/.ref if it exists */ - if (g_file_query_exists (runtime_child, NULL)) + runtime_ref_fd = glnx_chaseat (runtime_fd, ".ref", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + NULL); + if (runtime_ref_fd >= 0) + { flatpak_bwrap_add_args (bwrap, "--lock-file", "/usr/.ref", NULL); + } + } + + if (runtime_fd == custom_runtime_fd) + { + glnx_autofd int original_runtime_ref_fd = -1; + glnx_autofd int original_runtime_etc_fd = -1; /* Put the real Flatpak runtime in /run/parent, so that the * replacement /usr can have symlinks into /run/parent in order * to use the Flatpak runtime's graphics drivers etc. if desired */ - flatpak_bwrap_add_args (bwrap, - "--ro-bind", - flatpak_file_get_path_cached (original_runtime_files), - "/run/parent/usr", - "--lock-file", "/run/parent/usr/.ref", - NULL); - flatpak_run_setup_usr_links (bwrap, original_runtime_files, + if (!flatpak_bwrap_add_args_data_fd_dup (bwrap, + "--ro-bind-fd", + original_runtime_fd, + "/run/parent/usr", + error)) + return FALSE; + + original_runtime_ref_fd = glnx_chaseat (original_runtime_fd, ".ref", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + NULL); + if (original_runtime_ref_fd >= 0) + { + flatpak_bwrap_add_args (bwrap, + "--lock-file", "/run/parent/usr/.ref", + NULL); + } + + original_runtime_etc_fd = glnx_chaseat (original_runtime_fd, "etc", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + NULL); + if (original_runtime_etc_fd >= 0) + { + flatpak_bwrap_add_args (bwrap, + "--symlink", "usr/etc", "/run/parent/etc", + NULL); + } + + flatpak_run_setup_usr_links (bwrap, original_runtime_fd, "/run/parent"); - - g_clear_object (&runtime_child); - runtime_child = g_file_get_child (original_runtime_files, "etc"); - - if (g_file_query_exists (runtime_child, NULL)) - flatpak_bwrap_add_args (bwrap, - "--symlink", "usr/etc", "/run/parent/etc", - NULL); } - if (app_files != NULL) + if (app_fd >= 0) { - flatpak_bwrap_add_args (bwrap, - "--ro-bind", flatpak_file_get_path_cached (app_files), "/app", - NULL); + glnx_autofd int app_ref_fd = -1; - if (app_files == original_app_files) + if (!flatpak_bwrap_add_args_data_fd_dup (bwrap, + "--ro-bind-fd", app_fd, "/app", + error)) + return FALSE; + + app_ref_fd = glnx_chaseat (app_fd, ".ref", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + NULL); + if (app_ref_fd >= 0) { - /* All true Flatpak apps have files/.ref */ flatpak_bwrap_add_args (bwrap, "--lock-file", "/app/.ref", NULL); } - else - { - g_autoptr(GFile) app_child = NULL; - - app_child = g_file_get_child (app_files, ".ref"); - - /* Lock ${app}/.ref if it exists */ - if (g_file_query_exists (app_child, NULL)) - flatpak_bwrap_add_args (bwrap, - "--lock-file", "/app/.ref", - NULL); - } } else { @@ -3411,7 +3575,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref, NULL); } - if (original_app_files != NULL && app_files != original_app_files) + if (original_app_fd >= 0 && original_app_fd != app_fd) { /* Put the real Flatpak app in /run/parent/app */ flatpak_bwrap_add_args (bwrap, @@ -3424,26 +3588,37 @@ flatpak_run_app (FlatpakDecomposed *app_ref, if (metakey != NULL && !flatpak_run_add_extension_args (bwrap, metakey, app_ref, - use_ld_so_cache, app_target_path, + use_ld_so_cache, original_app_target_path, &app_extensions, &app_ld_path, cancellable, error)) return FALSE; if (!flatpak_run_add_extension_args (bwrap, runtime_metakey, runtime_ref, - use_ld_so_cache, runtime_target_path, + use_ld_so_cache, original_runtime_target_path, &runtime_extensions, &runtime_ld_path, cancellable, error)) return FALSE; - if (custom_usr_path == NULL) + if (runtime_fd == original_runtime_fd) flatpak_run_extend_ld_path (bwrap, NULL, runtime_ld_path); - if (custom_app_path == NULL) + if (app_fd == original_app_fd) flatpak_run_extend_ld_path (bwrap, app_ld_path, NULL); - runtime_ld_so_conf = g_file_resolve_relative_path (runtime_files, "etc/ld.so.conf"); - if (lstat (flatpak_file_get_path_cached (runtime_ld_so_conf), &s) == 0) - generate_ld_so_conf = S_ISREG (s.st_mode) && s.st_size == 0; + { + glnx_autofd int ld_so_conf_fd = -1; + struct glnx_statx stx; + + ld_so_conf_fd = glnx_chase_and_statxat (runtime_fd, "etc/ld.so.conf", + GLNX_CHASE_RESOLVE_BENEATH | + GLNX_CHASE_MUST_BE_REGULAR, + GLNX_STATX_SIZE, + &stx, NULL); + if (ld_so_conf_fd < 0 || + !(stx.stx_mask & GLNX_STATX_SIZE) || + stx.stx_size != 0) + generate_ld_so_conf = FALSE; + } /* At this point we have the minimal argv set up, with just the app, runtime and extensions. We can reuse this to generate the ld.so.cache (if needed) */ @@ -3455,7 +3630,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref, bwrap->fds, app_id_dir, checksum, - runtime_files, + runtime_fd, generate_ld_so_conf, cancellable, error); if (ld_so_fd == -1) @@ -3465,7 +3640,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref, flags |= flatpak_context_features_to_run_flags (features); - if (!flatpak_run_setup_base_argv (bwrap, runtime_files, app_id_dir, app_arch, flags, error)) + if (!flatpak_run_setup_base_argv (bwrap, runtime_fd, app_id_dir, app_arch, flags, error)) return FALSE; if (generate_ld_so_conf)