diff --git a/app/flatpak-builtins-enter.c b/app/flatpak-builtins-enter.c index 4560e084..bd0e8a84 100644 --- a/app/flatpak-builtins-enter.c +++ b/app/flatpak-builtins-enter.c @@ -41,81 +41,6 @@ static GOptionEntry options[] = { { NULL } }; -static gboolean -write_to_file (int fd, const char *content, ssize_t len) -{ - ssize_t res; - - while (len > 0) - { - res = write (fd, content, len); - if (res < 0 && errno == EINTR) - continue; - if (res <= 0) - return FALSE; - len -= res; - content += res; - } - - return TRUE; -} - -static gboolean -write_file (const char *path, const char *content) -{ - int fd; - gboolean res; - int errsv; - - fd = open (path, O_RDWR | O_CLOEXEC, 0); - if (fd == -1) - return FALSE; - - res = TRUE; - if (content) - res = write_to_file (fd, content, strlen (content)); - - errsv = errno; - close (fd); - errno = errsv; - - return res; -} - -static uid_t uid; -static gid_t gid; - -static void -child_setup (gpointer user_data) -{ - g_autofree char *uid_map = NULL; - g_autofree char *gid_map = NULL; - uid_t ns_uid; - gid_t ns_gid; - - ns_uid = getuid (); - ns_gid = getgid (); - - if (ns_uid != uid || ns_gid != gid) - { - /* Work around user namespace devpts issue by creating a new - userspace and map our uid like the helper does */ - - if (unshare (CLONE_NEWUSER)) - { - g_warning ("Can't unshare user namespace: %s", g_strerror (errno)); - return; - } - - uid_map = g_strdup_printf ("%d %d 1\n", uid, ns_uid); - if (!write_file ("/proc/self/uid_map", uid_map)) - g_warning ("setting up uid map"); - - gid_map = g_strdup_printf ("%d %d 1\n", gid, ns_gid); - if (!write_file ("/proc/self/gid_map", gid_map)) - g_warning ("setting up gid map"); - } -} gboolean flatpak_builtin_enter (int argc, @@ -125,9 +50,9 @@ flatpak_builtin_enter (int argc, { g_autoptr(GOptionContext) context = NULL; int rest_argv_start, rest_argc; - const char *ns_name[5] = { "user", "ipc", "net", "pid", "mnt" }; + const char *ns_name[] = { "ipc", "net", "pid", "mnt", "user" }; int ns_fd[G_N_ELEMENTS (ns_name)]; - char pid_ns[256]; + char pid_ns[256] = { 0 }; ssize_t pid_ns_len; char self_ns[256]; ssize_t self_ns_len; @@ -142,12 +67,19 @@ flatpak_builtin_enter (int argc, g_autofree char *pulse_path = NULL; g_autofree char *session_bus_path = NULL; g_autofree char *xdg_runtime_dir = NULL; + g_autofree char *stat_path = NULL; + g_autofree char *root_path = NULL; + char root_link[256] = { 0 }; + gssize root_link_len; + g_autofree char *cwd_path = NULL; + char cwd_link[256] = { 0 }; + gssize cwd_link_len; int status; + struct stat stat_buf; + uid_t uid; + gid_t gid; - uid = getuid (); - gid = getgid (); - - context = g_option_context_new (_("MONITORPID [COMMAND [args...]] - Run a command inside a running sandbox")); + context = g_option_context_new (_("SANDBOXEDPID [COMMAND [args...]] - Run a command inside a running sandbox")); g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); rest_argc = 0; @@ -168,7 +100,7 @@ flatpak_builtin_enter (int argc, if (rest_argc < 2) { - usage_error (context, _("MONITORPID and COMMAND must be specified"), error); + usage_error (context, _("SANDBOXEDPID and COMMAND must be specified"), error); return FALSE; } @@ -178,10 +110,27 @@ flatpak_builtin_enter (int argc, if (pid <= 0) return flatpak_fail (error, _("Invalid pid %s"), pid_s); + stat_path = g_strdup_printf ("/proc/%d/root", pid); + if (stat (stat_path, &stat_buf)) + return flatpak_fail (error, _("No such pid %s"), pid_s); + + uid = stat_buf.st_uid; + gid = stat_buf.st_gid; + environment_path = g_strdup_printf ("/proc/%d/environ", pid); if (!g_file_get_contents (environment_path, &environment, &environment_len, error)) return FALSE; + cwd_path = g_strdup_printf ("/proc/%d/cwd", pid); + cwd_link_len = readlink (cwd_path, cwd_link, sizeof (cwd_link) - 1); + if (cwd_link_len <= 0) + return flatpak_fail (error, _("Can't read cwd")); + + root_path = g_strdup_printf ("/proc/%d/root", pid); + root_link_len = readlink (root_path, root_link, sizeof (root_link) - 1); + if (root_link_len <= 0) + return flatpak_fail (error, _("Can't read root")); + for (i = 0; i < G_N_ELEMENTS (ns_name); i++) { g_autofree char *path = g_strdup_printf ("/proc/%d/ns/%s", pid, ns_name[i]); @@ -220,6 +169,12 @@ flatpak_builtin_enter (int argc, } } + if (chdir (cwd_link)) + return flatpak_fail (error, _("Can't chdir")); + + if (chroot (root_link)) + return flatpak_fail (error, _("Can't chroot")); + envp_array = g_ptr_array_new_with_free_func (g_free); for (e = environment; e < environment + environment_len; e = e + strlen (e) + 1) { @@ -264,9 +219,15 @@ flatpak_builtin_enter (int argc, g_ptr_array_add (argv_array, g_strdup (argv[rest_argv_start + i])); g_ptr_array_add (argv_array, NULL); + if (setgid (gid)) + return flatpak_fail (error, _("Can't switch gid")); + + if (setuid (uid)) + return flatpak_fail (error, _("Can't switch uid")); + if (!g_spawn_sync (NULL, (char **) argv_array->pdata, (char **) envp_array->pdata, G_SPAWN_SEARCH_PATH_FROM_ENVP | G_SPAWN_CHILD_INHERITS_STDIN, - child_setup, NULL, + NULL, NULL, NULL, NULL, &status, error)) return FALSE; diff --git a/doc/flatpak-enter.xml b/doc/flatpak-enter.xml index 4ac07d65..6613a340 100644 --- a/doc/flatpak-enter.xml +++ b/doc/flatpak-enter.xml @@ -43,7 +43,7 @@ Enter a running sandbox. - MONITORPID must be the pid of the monitor process for a running sandbox. + SANDBOXEDPID must be the pid of a process running in a flatpak sandbox. COMMAND is the command to run in the sandbox. Extra arguments are passed on to the command. @@ -51,6 +51,9 @@ This creates a new process within the running sandbox, with the same environment. This is useful when you want to debug a problem with a running application. + + This command requires extra privileges, so must be run as root or via e.g. sudo. +