Skip to content
Snippets Groups Projects
Commit 9d13f240 authored by Ludovico de Nittis's avatar Ludovico de Nittis
Browse files

Merge branch 'wip/flatpak-portal-v5' into 'master'

Start to make use of Flatpak 1.10.1 features

See merge request !242
parents 9f46efcd 2a6f0fab
No related branches found
No related tags found
1 merge request!242Start to make use of Flatpak 1.10.1 features
Pipeline #9038 failed
...@@ -67,7 +67,7 @@ as a subprocess of **pressure-vessel-launcher**. ...@@ -67,7 +67,7 @@ as a subprocess of **pressure-vessel-launcher**.
owned by the **flatpak-portal** per-user service, and the owned by the **flatpak-portal** per-user service, and the
*COMMAND* is launched in a Flatpak sub-sandbox, similar to *COMMAND* is launched in a Flatpak sub-sandbox, similar to
**flatpak-spawn**(1) without the **--host** option. **flatpak-spawn**(1) without the **--host** option.
Options that alter how the sub-sandbox is created, such as Most options that alter how the sub-sandbox is created, such as
**--sandbox-flag**, are not currently supported. **--sandbox-flag**, are not currently supported.
As with **org.freedesktop.Flatpak**, the As with **org.freedesktop.Flatpak**, the
**--terminate** option is not allowed in this mode. **--terminate** option is not allowed in this mode.
...@@ -90,6 +90,15 @@ as a subprocess of **pressure-vessel-launcher**. ...@@ -90,6 +90,15 @@ as a subprocess of **pressure-vessel-launcher**.
(standard input, standard output and standard error) are always (standard input, standard output and standard error) are always
forwarded. forwarded.
**--share-pids**
: If used with **--bus-name=org.freedesktop.portal.Flatpak**, use the
same process ID namespace for the new subsandbox as for the calling
process. This requires Flatpak 1.10 or later, running on a host
operating system where **bwrap**(1) is not and does not need to be
setuid root.
When communicating with a different API, this option is ignored.
**--terminate** **--terminate**
: Instead of running a *COMMAND*, terminate the Launcher server. : Instead of running a *COMMAND*, terminate the Launcher server.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* pressure-vessel-launch — send IPC requests to create child processes * pressure-vessel-launch — send IPC requests to create child processes
* *
* Copyright © 2018 Red Hat, Inc. * Copyright © 2018 Red Hat, Inc.
* Copyright © 2020 Collabora Ltd. * Copyright © 2020-2021 Collabora Ltd.
* *
* SPDX-License-Identifier: LGPL-2.1-or-later * SPDX-License-Identifier: LGPL-2.1-or-later
* *
...@@ -53,6 +53,8 @@ typedef enum { ...@@ -53,6 +53,8 @@ typedef enum {
FLATPAK_SPAWN_FLAGS_NO_NETWORK = 1 << 3, FLATPAK_SPAWN_FLAGS_NO_NETWORK = 1 << 3,
FLATPAK_SPAWN_FLAGS_WATCH_BUS = 1 << 4, /* Since 1.2 */ FLATPAK_SPAWN_FLAGS_WATCH_BUS = 1 << 4, /* Since 1.2 */
FLATPAK_SPAWN_FLAGS_EXPOSE_PIDS = 1 << 5, /* Since 1.6, optional */ FLATPAK_SPAWN_FLAGS_EXPOSE_PIDS = 1 << 5, /* Since 1.6, optional */
FLATPAK_SPAWN_FLAGS_NOTIFY_START = 1 << 6,
FLATPAK_SPAWN_FLAGS_SHARE_PIDS = 1 << 7,
} FlatpakSpawnFlags; } FlatpakSpawnFlags;
typedef enum { typedef enum {
...@@ -74,6 +76,10 @@ typedef enum { ...@@ -74,6 +76,10 @@ typedef enum {
FLATPAK_SPAWN_SUPPORT_FLAGS_EXPOSE_PIDS = 1 << 0, FLATPAK_SPAWN_SUPPORT_FLAGS_EXPOSE_PIDS = 1 << 0,
} FlatpakSpawnSupportFlags; } FlatpakSpawnSupportFlags;
/* The same flag is reused: this feature is available under the same
* circumstances */
#define FLATPAK_SPAWN_SUPPORT_FLAGS_SHARE_PIDS FLATPAK_SPAWN_SUPPORT_FLAGS_EXPOSE_PIDS
typedef struct typedef struct
{ {
const char *service_iface; const char *service_iface;
...@@ -171,7 +177,7 @@ process_exited_cb (G_GNUC_UNUSED GDBusConnection *connection, ...@@ -171,7 +177,7 @@ process_exited_cb (G_GNUC_UNUSED GDBusConnection *connection,
* code specified neither WUNTRACED nor WIFSIGNALED, then exactly one * code specified neither WUNTRACED nor WIFSIGNALED, then exactly one
* of WIFEXITED() or WIFSIGNALED() will be true. * of WIFEXITED() or WIFSIGNALED() will be true.
*/ */
g_warning ("exit status %d is neither WIFEXITED() nor WIFSIGNALED()", g_warning ("wait status %d is neither WIFEXITED() nor WIFSIGNALED()",
wait_status); wait_status);
exit_code = LAUNCH_EX_CANNOT_REPORT; exit_code = LAUNCH_EX_CANNOT_REPORT;
} }
...@@ -327,7 +333,7 @@ name_owner_changed (G_GNUC_UNUSED GDBusConnection *connection, ...@@ -327,7 +333,7 @@ name_owner_changed (G_GNUC_UNUSED GDBusConnection *connection,
G_GNUC_UNUSED const gchar *interface_name, G_GNUC_UNUSED const gchar *interface_name,
G_GNUC_UNUSED const gchar *signal_name, G_GNUC_UNUSED const gchar *signal_name,
GVariant *parameters, GVariant *parameters,
gpointer user_data) G_GNUC_UNUSED gpointer user_data)
{ {
GMainLoop *loop = user_data; GMainLoop *loop = user_data;
const char *name, *from, *to; const char *name, *from, *to;
...@@ -367,6 +373,108 @@ connection_closed_cb (G_GNUC_UNUSED GDBusConnection *conn, ...@@ -367,6 +373,108 @@ connection_closed_cb (G_GNUC_UNUSED GDBusConnection *conn,
g_main_loop_quit (loop); g_main_loop_quit (loop);
} }
static guint32
get_portal_version (void)
{
static guint32 version = 0;
g_return_val_if_fail (api != NULL, 0);
g_return_val_if_fail (api == &host_api || api == &subsandbox_api, 0);
if (version == 0)
{
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) reply =
g_dbus_connection_call_sync (bus_or_peer_connection,
api->service_bus_name,
api->service_obj_path,
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new ("(ss)", api->service_iface, "version"),
G_VARIANT_TYPE ("(v)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
if (reply == NULL)
g_debug ("Failed to get version: %s", error->message);
else
{
g_autoptr(GVariant) v = g_variant_get_child_value (reply, 0);
g_autoptr(GVariant) v2 = g_variant_get_variant (v);
version = g_variant_get_uint32 (v2);
}
}
return version;
}
static void
check_portal_version (const char *option, guint32 version_needed)
{
guint32 portal_version = get_portal_version ();
if (portal_version < version_needed)
{
g_printerr ("--%s not supported by host portal version (need version %d, has %d)\n", option, version_needed, portal_version);
exit (1);
}
}
static guint32
get_portal_supports (void)
{
static guint32 supports = 0;
static gboolean ran = FALSE;
g_return_val_if_fail (api != NULL, 0);
g_return_val_if_fail (api == &host_api || api == &subsandbox_api, 0);
if (!ran)
{
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) reply = NULL;
ran = TRUE;
/* Support flags were added in version 3 */
if (get_portal_version () >= 3)
{
reply = g_dbus_connection_call_sync (bus_or_peer_connection,
api->service_bus_name,
api->service_obj_path,
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new ("(ss)", api->service_iface, "supports"),
G_VARIANT_TYPE ("(v)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
if (reply == NULL)
g_debug ("Failed to get supports: %s", error->message);
else
{
g_autoptr(GVariant) v = g_variant_get_child_value (reply, 0);
g_autoptr(GVariant) v2 = g_variant_get_variant (v);
supports = g_variant_get_uint32 (v2);
}
}
}
return supports;
}
static void
check_portal_supports (const char *option, guint32 supports_needed)
{
guint32 supports = get_portal_supports ();
if ((supports & supports_needed) != supports_needed)
{
g_printerr ("--%s not supported by host portal\n", option);
exit (1);
}
}
static gchar **forward_fds = NULL; static gchar **forward_fds = NULL;
static gboolean opt_clear_env = FALSE; static gboolean opt_clear_env = FALSE;
static gchar *opt_dbus_address = NULL; static gchar *opt_dbus_address = NULL;
...@@ -374,6 +482,7 @@ static gchar *opt_directory = NULL; ...@@ -374,6 +482,7 @@ static gchar *opt_directory = NULL;
static gchar *opt_socket = NULL; static gchar *opt_socket = NULL;
static GHashTable *opt_env = NULL; static GHashTable *opt_env = NULL;
static GHashTable *opt_unsetenv = NULL; static GHashTable *opt_unsetenv = NULL;
static gboolean opt_share_pids = FALSE;
static gboolean opt_terminate = FALSE; static gboolean opt_terminate = FALSE;
static gboolean opt_verbose = FALSE; static gboolean opt_verbose = FALSE;
static gboolean opt_version = FALSE; static gboolean opt_version = FALSE;
...@@ -496,6 +605,9 @@ static const GOptionEntry options[] = ...@@ -496,6 +605,9 @@ static const GOptionEntry options[] =
G_OPTION_FLAG_FILENAME, G_OPTION_ARG_CALLBACK, opt_env_cb, G_OPTION_FLAG_FILENAME, G_OPTION_ARG_CALLBACK, opt_env_cb,
"Pass environment variables matching a shell-style wildcard.", "Pass environment variables matching a shell-style wildcard.",
"WILDCARD" }, "WILDCARD" },
{ "share-pids", '\0',
G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_share_pids,
"Use same pid namespace as calling sandbox.", NULL },
{ "socket", '\0', { "socket", '\0',
G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &opt_socket, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &opt_socket,
"Connect to a Launcher server listening on this AF_UNIX socket.", "Connect to a Launcher server listening on this AF_UNIX socket.",
...@@ -848,11 +960,25 @@ main (int argc, ...@@ -848,11 +960,25 @@ main (int argc,
g_variant_new_variant (g_variant_new_boolean (TRUE))); g_variant_new_variant (g_variant_new_boolean (TRUE)));
} }
/* We just ignore this option when not using a subsandbox:
* host_api and launcher_api always share process IDs anyway */
if (opt_share_pids && api == &subsandbox_api)
{
check_portal_version ("share-pids", 5);
check_portal_supports ("share-pids", FLATPAK_SPAWN_SUPPORT_FLAGS_SHARE_PIDS);
spawn_flags |= FLATPAK_SPAWN_FLAGS_SHARE_PIDS;
}
if (g_hash_table_size (opt_unsetenv) > 0) if (g_hash_table_size (opt_unsetenv) > 0)
{ {
g_hash_table_iter_init (&iter, opt_unsetenv); g_hash_table_iter_init (&iter, opt_unsetenv);
if (api == &launcher_api) /* The host portal doesn't support options, so we always have to do
* this the hard way. The subsandbox portal supports unset-env in
* versions >= 5. pressure-vessel-launcher always supports it. */
if (api == &launcher_api
|| (api == &subsandbox_api && get_portal_version () >= 5))
{ {
GVariantBuilder strv_builder; GVariantBuilder strv_builder;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment