Enable GnuTLS-based GHmac in Fedora and reenable glib2-static in RHEL

Consolidate GDesktopAppInfo changes into gdesktopappinfo.patch
Disable check-rpath since it seems to be broken
This commit is contained in:
Michael Catanzaro 2021-06-17 10:45:30 -05:00
parent ba26123977
commit 1f79f05203
7 changed files with 1325 additions and 912 deletions

View File

@ -1,30 +0,0 @@
From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Fri, 23 Oct 2020 18:20:01 +0200
Subject: [PATCH 1/4] tests: Iterate mainloop during launch test
When launching an application, we wait for the DBus response from
systemd before executing the binary. Because of this the main loop needs
to be iterated for spawning to completed and the file to be created.
Without this the test will time out if GLib was able to connect to the
session bus.
---
gio/tests/desktop-app-info.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c
index fcc29c579..743230cbb 100644
--- a/gio/tests/desktop-app-info.c
+++ b/gio/tests/desktop-app-info.c
@@ -334,6 +334,7 @@ wait_for_file (const gchar *want_this,
*/
while (access (want_this, F_OK) != 0)
{
+ g_main_context_iteration (NULL, FALSE);
g_usleep (100000); /* 100ms */
g_assert_cmpuint (retries, >, 0);
retries--;
--
2.31.1

View File

@ -1,388 +0,0 @@
From ba3b85a8fea0151e74de50e841a7f16f9b077a56 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Mon, 27 Jul 2020 22:22:32 +0200
Subject: [PATCH 2/4] gdesktopappinfo: Move launched applications into
transient scope
Try to move the spawned executable into its own systemd scope. To avoid
possible race conditions and ensure proper accounting, we delay the
execution of the real command until after the DBus call to systemd has
finished.
From the two approaches we can take here, this is better in the sense
that we have a child that the API consumer can watch. API consumers
should not be doing this, however, gnome-session needs to watch children
during session startup. Until gnome-session is fixed, we will not be
able to change this.
The alternative approach is to delegate launching itself to systemd by
creating a transient .service unit instead. This is cleaner and has e.g.
the advantage that systemd will take care of log redirection and similar
issues.
Note that this patch is incomplete. The DBus call is done in a "fire and
forget" manner, which is fine in most cases, but means that "gio open"
will fail to move the child into the new scope as gio quits before the
DBus call finishes.
---
gio/gdesktopappinfo.c | 264 ++++++++++++++++++++++++++++++++++++------
1 file changed, 227 insertions(+), 37 deletions(-)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 1a4b97918..afdcd42ac 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2730,6 +2730,148 @@ notify_desktop_launch (GDBusConnection *session_bus,
#define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
+#if defined(__linux__) && !defined(__BIONIC__)
+typedef struct {
+ int pipe[2];
+ GSpawnChildSetupFunc user_setup;
+ gpointer user_setup_data;
+} SpawnWrapperData;
+
+static void
+launch_uris_with_spawn_delay_exec (gpointer user_data)
+{
+ SpawnWrapperData *data = user_data;
+
+ /* Clear CLOEXEC again, as that was set due to
+ * G_SPAWN_LEAVE_DESCRIPTORS_OPEN not being set. */
+ fcntl (data->pipe[0], F_SETFD, 0);
+
+ /* No need to close read side, we have CLOEXEC set. */
+
+ if (data->user_setup)
+ data->user_setup (data->user_setup_data);
+}
+
+static gchar *
+systemd_unit_name_escape (const gchar *in)
+{
+ /* Adapted from systemd source */
+ GString * const str = g_string_sized_new (strlen (in));
+
+ for (; *in; in++)
+ {
+ if (g_ascii_isalnum (*in) || *in == ':' || *in == '_' || *in == '.')
+ g_string_append_c (str, *in);
+ else
+ g_string_append_printf (str, "\\x%02x", *in);
+ }
+ return g_string_free (str, FALSE);
+}
+
+static void
+create_systemd_scope (GDBusConnection *session_bus,
+ GDesktopAppInfo *info,
+ gint pid,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVariantBuilder builder;
+ const char *app_name = g_get_application_name ();
+ char *appid = NULL;
+ char *appid_escaped = NULL;
+ char *snid_escaped = NULL;
+ char *unit_name = NULL;
+
+ /* In this order:
+ * 1. Actual application ID from file
+ * 2. Stripping the .desktop from the desktop ID
+ * 3. Fall back to using the binary name
+ */
+ if (info->app_id)
+ appid = g_strdup (info->app_id);
+ else if (info->desktop_id && g_str_has_suffix (info->desktop_id, ".desktop"))
+ appid = g_strndup (info->desktop_id, strlen (info->desktop_id) - 8);
+ else
+ appid = g_path_get_basename (info->binary);
+
+ appid_escaped = systemd_unit_name_escape (appid);
+
+ /* Generate a name conforming to
+ * https://systemd.io/DESKTOP_ENVIRONMENTS/
+ * We use the PID to disambiguate, as that should be unique enough.
+ */
+ unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
+ g_variant_builder_add (&builder, "s", unit_name);
+ g_variant_builder_add (&builder, "s", "fail");
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
+
+ /* Add a generic human readable description, can be changed at will. */
+ if (app_name)
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "Description",
+ g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
+ app_name)));
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "PIDs",
+ g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
+ /* Default to let systemd garbage collect failed applications we launched. */
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "CollectMode",
+ g_variant_new_string ("inactive-or-failed"));
+
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
+ g_variant_builder_close (&builder);
+
+ g_dbus_connection_call (session_bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit",
+ g_variant_builder_end (&builder),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 1000,
+ NULL,
+ callback,
+ user_data);
+
+ g_free (appid);
+ g_free (appid_escaped);
+ g_free (snid_escaped);
+ g_free (unit_name);
+}
+
+static void
+systemd_scope_created_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GVariant *res = NULL;
+ GError *error = NULL;
+
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
+ if (error != NULL)
+ {
+ g_debug ("Failed to move new child into scope: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* Unblock the waiting wrapper binary. */
+ close (GPOINTER_TO_INT (user_data));
+
+ if (res)
+ g_variant_unref (res);
+}
+#endif
+
static gboolean
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GDBusConnection *session_bus,
@@ -2750,13 +2892,14 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GList *old_uris;
GList *dup_uris;
- char **argv, **envp;
+ GStrv argv = NULL, envp = NULL;
+ GStrv wrapped_argv = NULL;
+ GList *launched_uris = NULL;
+ char *sn_id = NULL;
int argc;
g_return_val_if_fail (info != NULL, FALSE);
- argv = NULL;
-
if (launch_context)
envp = g_app_launch_context_get_environment (launch_context);
else
@@ -2770,27 +2913,19 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
do
{
GPid pid;
- GList *launched_uris;
GList *iter;
- char *sn_id = NULL;
- char **wrapped_argv;
int i;
- gsize j;
- const gchar * const wrapper_argv[] =
- {
- "/bin/sh",
- "-e",
- "-u",
- "-c", "export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"",
- "sh", /* argv[0] for sh */
- };
+#if defined(__linux__) && !defined(__BIONIC__)
+ SpawnWrapperData wrapper_data;
+#endif
+ GSpawnChildSetupFunc setup = user_setup;
+ gpointer setup_data = user_setup_data;
old_uris = dup_uris;
if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
- goto out;
+ return FALSE;
/* Get the subset of URIs we're launching with this process */
- launched_uris = NULL;
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
launched_uris = g_list_prepend (launched_uris, iter->data);
launched_uris = g_list_reverse (launched_uris);
@@ -2799,7 +2934,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Unable to find terminal required for application"));
- goto out;
+ return FALSE;
}
if (info->filename)
@@ -2808,7 +2943,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
info->filename,
TRUE);
- sn_id = NULL;
if (launch_context)
{
GList *launched_files = create_files_for_uris (launched_uris);
@@ -2837,38 +2971,93 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
* with a wrapper program (grep the GLib git history for
* `gio-launch-desktop` for an example of this which could be
* resurrected). */
- wrapped_argv = g_new (char *, argc + G_N_ELEMENTS (wrapper_argv) + 1);
+ wrapped_argv = g_new (char *, argc + 6 + 1);
+
+ wrapped_argv[0] = g_strdup ("/bin/sh");
+ wrapped_argv[1] = g_strdup ("-e");
+ wrapped_argv[2] = g_strdup ("-u");
+ wrapped_argv[3] = g_strdup ("-c");
+ /* argument 4 is filled in below */
+ wrapped_argv[5] = g_strdup ("sh");
- for (j = 0; j < G_N_ELEMENTS (wrapper_argv); j++)
- wrapped_argv[j] = g_strdup (wrapper_argv[j]);
for (i = 0; i < argc; i++)
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = g_steal_pointer (&argv[i]);
+ wrapped_argv[i + 6] = g_steal_pointer (&argv[i]);
+
+ wrapped_argv[i + 6] = NULL;
+ g_clear_pointer (&argv, g_free);
+
+#if defined(__linux__) && !defined(__BIONIC__)
+ /* Create pipes, if we use a setup func, then set cloexec,
+ * otherwise our wrapper script will close both sides. */
+ if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to create pipe for systemd synchronization"));
+ return FALSE;
+ }
+
+ /* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
+ fcntl (wrapper_data.pipe[1], F_SETFD, FD_CLOEXEC);
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = NULL;
- g_free (argv);
- argv = NULL;
+ if (!(spawn_flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
+ {
+ /* In this case, we use a setup function (which could probably also
+ * overwrite envp to set GIO_LAUNCHED_DESKTOP_FILE_PID).
+ *
+ * Note that this does not incur an additional cost because
+ * G_SPAWN_LEAVE_DESCRIPTOR_OPEN must be set in order to use
+ * posix_spawn. */
+ wrapper_data.user_setup = setup;
+ wrapper_data.user_setup_data = setup_data;
+
+ setup = launch_uris_with_spawn_delay_exec;
+ setup_data = &wrapper_data;
+ }
+
+ wrapped_argv[4] = g_strdup_printf ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; cat <&%1$d; exec \"$@\" %1$d<&-",
+ wrapper_data.pipe[0]);
+#else
+ wrapped_argv[4] = g_strdup ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"");
+#endif
if (!g_spawn_async_with_fds (info->path,
wrapped_argv,
envp,
spawn_flags,
- user_setup,
- user_setup_data,
+ setup,
+ setup_data,
&pid,
stdin_fd,
stdout_fd,
stderr_fd,
error))
{
+#if defined(__linux__) && !defined(__BIONIC__)
+ close (wrapper_data.pipe[0]);
+ close (wrapper_data.pipe[1]);
+#endif
+
if (sn_id)
g_app_launch_context_launch_failed (launch_context, sn_id);
- g_free (sn_id);
- g_list_free (launched_uris);
-
goto out;
}
+#if defined(__linux__) && !defined(__BIONIC__)
+ /* We close write side asynchronously later on when the dbus call
+ * to systemd finishes. */
+ close (wrapper_data.pipe[0]);
+
+ if (session_bus)
+ create_systemd_scope (session_bus,
+ info,
+ pid,
+ systemd_scope_created_cb,
+ GINT_TO_POINTER (wrapper_data.pipe[1]));
+ else
+ close (wrapper_data.pipe[1]);
+#endif
+
if (pid_callback != NULL)
pid_callback (info, pid, pid_callback_data);
@@ -2893,19 +3082,20 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
sn_id,
launched_uris);
- g_free (sn_id);
- g_list_free (launched_uris);
-
- g_strfreev (wrapped_argv);
- wrapped_argv = NULL;
+ g_clear_pointer (&sn_id, g_free);
+ g_clear_pointer (&launched_uris, g_list_free);
+ g_clear_pointer (&wrapped_argv, g_strfreev);
}
while (dup_uris != NULL);
completed = TRUE;
- out:
+out:
g_strfreev (argv);
g_strfreev (envp);
+ g_clear_pointer (&wrapped_argv, g_strfreev);
+ g_list_free (launched_uris);
+ g_free (sn_id);
return completed;
}
--
2.31.1

View File

@ -1,382 +0,0 @@
From cd67a1b0256d2397dac0836e154f3449b63a6b19 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Tue, 28 Jul 2020 12:11:13 +0200
Subject: [PATCH 3/4] gdesktopappinfo: Handle task completion from spawn
function
This allows delaying the return of the task until all dbus calls (in
particular the ones to setup the scope) have finished.
This fixes the behaviour of the previous commit which would not
correctly move the process into the scope if the application exited
right after the task returned.
---
gio/gdesktopappinfo.c | 212 +++++++++++++++++++++++++++++-------------
1 file changed, 146 insertions(+), 66 deletions(-)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index afdcd42ac..8d0f1688e 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2849,11 +2849,17 @@ create_systemd_scope (GDBusConnection *session_bus,
g_free (unit_name);
}
+typedef struct {
+ GTask *task;
+ int fd;
+} ScopeCreatedData;
+
static void
systemd_scope_created_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
+ ScopeCreatedData *data = user_data;
GVariant *res = NULL;
GError *error = NULL;
@@ -2865,13 +2871,47 @@ systemd_scope_created_cb (GObject *object,
}
/* Unblock the waiting wrapper binary. */
- close (GPOINTER_TO_INT (user_data));
+
+ close (data->fd);
+
+ if (data->task)
+ {
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (data->task));
+ pending -= 1;
+ g_task_set_task_data (data->task, GINT_TO_POINTER (pending), NULL);
+
+ if (pending == 0 && !g_task_get_completed (data->task))
+ g_task_return_boolean (data->task, TRUE);
+ }
if (res)
g_variant_unref (res);
+ g_clear_object (&data->task);
+ g_free (data);
}
#endif
+static void
+launch_uris_with_spawn_flush_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ gint pending;
+
+ g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
+
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending -= 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ if (pending == 0 && !g_task_get_completed (task))
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
static gboolean
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GDBusConnection *session_bus,
@@ -2886,9 +2926,10 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
- GError **error)
+ GTask *task,
+ GError **error_out)
{
- gboolean completed = FALSE;
+ GError *error = NULL;
GList *old_uris;
GList *dup_uris;
@@ -2898,8 +2939,15 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
char *sn_id = NULL;
int argc;
+ /* We may get a task to report back on or an error. But never both. */
+ g_assert (!(task && error_out));
g_return_val_if_fail (info != NULL, FALSE);
+ /* Surrounding code must not have set any data on the task
+ * (it is cleared before calling this function). */
+ if (session_bus && task)
+ g_assert (g_task_get_task_data (task) == NULL);
+
if (launch_context)
envp = g_app_launch_context_get_environment (launch_context);
else
@@ -2922,8 +2970,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gpointer setup_data = user_setup_data;
old_uris = dup_uris;
- if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
- return FALSE;
+ if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, &error))
+ goto out;
/* Get the subset of URIs we're launching with this process */
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
@@ -2932,9 +2980,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to find terminal required for application"));
- return FALSE;
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to find terminal required for application"));
+ goto out;
}
if (info->filename)
@@ -2991,9 +3039,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
* otherwise our wrapper script will close both sides. */
if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to create pipe for systemd synchronization"));
- return FALSE;
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to create pipe for systemd synchronization"));
+ goto out;
}
/* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
@@ -3030,7 +3078,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
stdin_fd,
stdout_fd,
stderr_fd,
- error))
+ &error))
{
#if defined(__linux__) && !defined(__BIONIC__)
close (wrapper_data.pipe[0]);
@@ -3049,11 +3097,29 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
close (wrapper_data.pipe[0]);
if (session_bus)
- create_systemd_scope (session_bus,
- info,
- pid,
- systemd_scope_created_cb,
- GINT_TO_POINTER (wrapper_data.pipe[1]));
+ {
+ ScopeCreatedData *data;
+
+ data = g_new0 (ScopeCreatedData, 1);
+
+ if (task)
+ {
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending += 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ data->task = g_object_ref (task);
+ }
+
+ data->fd = wrapper_data.pipe[1];
+
+ create_systemd_scope (session_bus,
+ info,
+ pid,
+ systemd_scope_created_cb,
+ data);
+ }
else
close (wrapper_data.pipe[1]);
#endif
@@ -3088,8 +3154,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
}
while (dup_uris != NULL);
- completed = TRUE;
-
out:
g_strfreev (argv);
g_strfreev (envp);
@@ -3097,7 +3161,52 @@ out:
g_list_free (launched_uris);
g_free (sn_id);
- return completed;
+ if (!error)
+ {
+ if (session_bus && task)
+ {
+ GCancellable *cancellable = g_task_get_cancellable (task);
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending += 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ /* FIXME: The D-Bus message from the notify_desktop_launch() function
+ * can be still lost even if flush is called later. See:
+ * https://gitlab.freedesktop.org/dbus/dbus/issues/72
+ */
+ g_dbus_connection_flush (session_bus,
+ cancellable,
+ launch_uris_with_spawn_flush_cb,
+ g_steal_pointer (&task));
+ }
+ else if (session_bus)
+ {
+ /* No task available. */
+ g_dbus_connection_flush (session_bus,
+ NULL,
+ NULL,
+ NULL);
+ }
+ else if (task)
+ {
+ /* Return the given task. */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+ }
+ else
+ {
+ if (task)
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ }
+ else
+ g_propagate_error (error_out, error);
+ }
+
+ return !error;
}
static gchar *
@@ -3246,17 +3355,9 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
spawn_flags, user_setup, user_setup_data,
pid_callback, pid_callback_data,
- stdin_fd, stdout_fd, stderr_fd, error);
+ stdin_fd, stdout_fd, stderr_fd, NULL, error);
- if (session_bus != NULL)
- {
- /* This asynchronous flush holds a reference until it completes,
- * which ensures that the following unref won't immediately kill
- * the connection if we were the initial owner.
- */
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
- g_object_unref (session_bus);
- }
+ g_clear_object (&session_bus);
return success;
}
@@ -3310,18 +3411,6 @@ launch_uris_with_dbus_cb (GObject *object,
g_object_unref (task);
}
-static void
-launch_uris_flush_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GTask *task = G_TASK (user_data);
-
- g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
static void
launch_uris_bus_get_cb (GObject *object,
GAsyncResult *result,
@@ -3330,12 +3419,20 @@ launch_uris_bus_get_cb (GObject *object,
GTask *task = G_TASK (user_data);
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (g_task_get_source_object (task));
LaunchUrisData *data = g_task_get_task_data (task);
+ LaunchUrisData *data_copy = NULL;
GCancellable *cancellable = g_task_get_cancellable (task);
GDBusConnection *session_bus;
- GError *error = NULL;
session_bus = g_bus_get_finish (result, NULL);
+ data_copy = g_new0 (LaunchUrisData, 1);
+ data_copy->appinfo = g_steal_pointer (&data->appinfo);
+ data_copy->uris = g_steal_pointer (&data->uris);
+ data_copy->context = g_steal_pointer (&data->context);
+
+ /* Allow other data to be attached to the task. */
+ g_task_set_task_data (task, NULL, NULL);
+
if (session_bus && info->app_id)
{
/* FIXME: The g_document_portal_add_documents() function, which is called
@@ -3343,34 +3440,21 @@ launch_uris_bus_get_cb (GObject *object,
* uses blocking calls.
*/
g_desktop_app_info_launch_uris_with_dbus (info, session_bus,
- data->uris, data->context,
+ data_copy->uris, data_copy->context,
cancellable,
launch_uris_with_dbus_cb,
g_steal_pointer (&task));
}
else
{
- /* FIXME: The D-Bus message from the notify_desktop_launch() function
- * can be still lost even if flush is called later. See:
- * https://gitlab.freedesktop.org/dbus/dbus/issues/72
- */
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec,
- data->uris, data->context,
+ data_copy->uris, data_copy->context,
_SPAWN_FLAGS_DEFAULT, NULL,
NULL, NULL, NULL, -1, -1, -1,
- &error);
- if (error != NULL)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- g_object_unref (task);
- }
- else
- g_dbus_connection_flush (session_bus,
- cancellable,
- launch_uris_flush_cb,
- g_steal_pointer (&task));
+ g_steal_pointer (&task), NULL);
}
+ launch_uris_data_free (data_copy);
g_clear_object (&session_bus);
}
@@ -5186,16 +5270,12 @@ g_desktop_app_info_launch_action (GDesktopAppInfo *info,
if (exec_line)
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL,
- -1, -1, -1, NULL);
+ -1, -1, -1, NULL, NULL);
g_free (exec_line);
}
- if (session_bus != NULL)
- {
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
- g_object_unref (session_bus);
- }
+ g_clear_object (&session_bus);
}
/* Epilogue {{{1 */
--
2.31.1

View File

@ -1,56 +0,0 @@
From 8da8a3ef6df8af6de8bd388192bebe8b51b3e782 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Thu, 17 Sep 2020 17:35:58 +0200
Subject: [PATCH 4/4] gdesktopappinfo: Add SourcePath= to transient systemd
units
systemd allows setting a SourcePath= which shows the file that the unit
has been generated from. KDE is starting to set this and it seems like a
good idea, so do the same here.
See https://invent.kde.org/frameworks/kio/-/merge_requests/124
---
gio/gdesktopappinfo.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 8d0f1688e..a833de4e6 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2777,6 +2777,7 @@ create_systemd_scope (GDBusConnection *session_bus,
{
GVariantBuilder builder;
const char *app_name = g_get_application_name ();
+ const char *source_path = NULL;
char *appid = NULL;
char *appid_escaped = NULL;
char *snid_escaped = NULL;
@@ -2802,6 +2803,8 @@ create_systemd_scope (GDBusConnection *session_bus,
*/
unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
+ source_path = g_desktop_app_info_get_filename (info);
+
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
g_variant_builder_add (&builder, "s", unit_name);
g_variant_builder_add (&builder, "s", "fail");
@@ -2815,6 +2818,16 @@ create_systemd_scope (GDBusConnection *session_bus,
"Description",
g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
app_name)));
+
+ /* If we have a .desktop file, document that the scope has been "generated"
+ * from it.
+ */
+ if (source_path && g_utf8_validate (source_path, -1, NULL))
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "SourcePath",
+ g_variant_new_string (source_path));
+
g_variant_builder_add (&builder,
"(sv)",
"PIDs",
--
2.31.1

855
gdesktopappinfo.patch Normal file
View File

@ -0,0 +1,855 @@
From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Fri, 23 Oct 2020 18:20:01 +0200
Subject: [PATCH 1/4] tests: Iterate mainloop during launch test
When launching an application, we wait for the DBus response from
systemd before executing the binary. Because of this the main loop needs
to be iterated for spawning to completed and the file to be created.
Without this the test will time out if GLib was able to connect to the
session bus.
---
gio/tests/desktop-app-info.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c
index fcc29c579..743230cbb 100644
--- a/gio/tests/desktop-app-info.c
+++ b/gio/tests/desktop-app-info.c
@@ -334,6 +334,7 @@ wait_for_file (const gchar *want_this,
*/
while (access (want_this, F_OK) != 0)
{
+ g_main_context_iteration (NULL, FALSE);
g_usleep (100000); /* 100ms */
g_assert_cmpuint (retries, >, 0);
retries--;
--
2.31.1
From ba3b85a8fea0151e74de50e841a7f16f9b077a56 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Mon, 27 Jul 2020 22:22:32 +0200
Subject: [PATCH 2/4] gdesktopappinfo: Move launched applications into
transient scope
Try to move the spawned executable into its own systemd scope. To avoid
possible race conditions and ensure proper accounting, we delay the
execution of the real command until after the DBus call to systemd has
finished.
From the two approaches we can take here, this is better in the sense
that we have a child that the API consumer can watch. API consumers
should not be doing this, however, gnome-session needs to watch children
during session startup. Until gnome-session is fixed, we will not be
able to change this.
The alternative approach is to delegate launching itself to systemd by
creating a transient .service unit instead. This is cleaner and has e.g.
the advantage that systemd will take care of log redirection and similar
issues.
Note that this patch is incomplete. The DBus call is done in a "fire and
forget" manner, which is fine in most cases, but means that "gio open"
will fail to move the child into the new scope as gio quits before the
DBus call finishes.
---
gio/gdesktopappinfo.c | 264 ++++++++++++++++++++++++++++++++++++------
1 file changed, 227 insertions(+), 37 deletions(-)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 1a4b97918..afdcd42ac 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2730,6 +2730,148 @@ notify_desktop_launch (GDBusConnection *session_bus,
#define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
+#if defined(__linux__) && !defined(__BIONIC__)
+typedef struct {
+ int pipe[2];
+ GSpawnChildSetupFunc user_setup;
+ gpointer user_setup_data;
+} SpawnWrapperData;
+
+static void
+launch_uris_with_spawn_delay_exec (gpointer user_data)
+{
+ SpawnWrapperData *data = user_data;
+
+ /* Clear CLOEXEC again, as that was set due to
+ * G_SPAWN_LEAVE_DESCRIPTORS_OPEN not being set. */
+ fcntl (data->pipe[0], F_SETFD, 0);
+
+ /* No need to close read side, we have CLOEXEC set. */
+
+ if (data->user_setup)
+ data->user_setup (data->user_setup_data);
+}
+
+static gchar *
+systemd_unit_name_escape (const gchar *in)
+{
+ /* Adapted from systemd source */
+ GString * const str = g_string_sized_new (strlen (in));
+
+ for (; *in; in++)
+ {
+ if (g_ascii_isalnum (*in) || *in == ':' || *in == '_' || *in == '.')
+ g_string_append_c (str, *in);
+ else
+ g_string_append_printf (str, "\\x%02x", *in);
+ }
+ return g_string_free (str, FALSE);
+}
+
+static void
+create_systemd_scope (GDBusConnection *session_bus,
+ GDesktopAppInfo *info,
+ gint pid,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVariantBuilder builder;
+ const char *app_name = g_get_application_name ();
+ char *appid = NULL;
+ char *appid_escaped = NULL;
+ char *snid_escaped = NULL;
+ char *unit_name = NULL;
+
+ /* In this order:
+ * 1. Actual application ID from file
+ * 2. Stripping the .desktop from the desktop ID
+ * 3. Fall back to using the binary name
+ */
+ if (info->app_id)
+ appid = g_strdup (info->app_id);
+ else if (info->desktop_id && g_str_has_suffix (info->desktop_id, ".desktop"))
+ appid = g_strndup (info->desktop_id, strlen (info->desktop_id) - 8);
+ else
+ appid = g_path_get_basename (info->binary);
+
+ appid_escaped = systemd_unit_name_escape (appid);
+
+ /* Generate a name conforming to
+ * https://systemd.io/DESKTOP_ENVIRONMENTS/
+ * We use the PID to disambiguate, as that should be unique enough.
+ */
+ unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
+ g_variant_builder_add (&builder, "s", unit_name);
+ g_variant_builder_add (&builder, "s", "fail");
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
+
+ /* Add a generic human readable description, can be changed at will. */
+ if (app_name)
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "Description",
+ g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
+ app_name)));
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "PIDs",
+ g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
+ /* Default to let systemd garbage collect failed applications we launched. */
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "CollectMode",
+ g_variant_new_string ("inactive-or-failed"));
+
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
+ g_variant_builder_close (&builder);
+
+ g_dbus_connection_call (session_bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit",
+ g_variant_builder_end (&builder),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 1000,
+ NULL,
+ callback,
+ user_data);
+
+ g_free (appid);
+ g_free (appid_escaped);
+ g_free (snid_escaped);
+ g_free (unit_name);
+}
+
+static void
+systemd_scope_created_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GVariant *res = NULL;
+ GError *error = NULL;
+
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
+ if (error != NULL)
+ {
+ g_debug ("Failed to move new child into scope: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* Unblock the waiting wrapper binary. */
+ close (GPOINTER_TO_INT (user_data));
+
+ if (res)
+ g_variant_unref (res);
+}
+#endif
+
static gboolean
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GDBusConnection *session_bus,
@@ -2750,13 +2892,14 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GList *old_uris;
GList *dup_uris;
- char **argv, **envp;
+ GStrv argv = NULL, envp = NULL;
+ GStrv wrapped_argv = NULL;
+ GList *launched_uris = NULL;
+ char *sn_id = NULL;
int argc;
g_return_val_if_fail (info != NULL, FALSE);
- argv = NULL;
-
if (launch_context)
envp = g_app_launch_context_get_environment (launch_context);
else
@@ -2770,27 +2913,19 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
do
{
GPid pid;
- GList *launched_uris;
GList *iter;
- char *sn_id = NULL;
- char **wrapped_argv;
int i;
- gsize j;
- const gchar * const wrapper_argv[] =
- {
- "/bin/sh",
- "-e",
- "-u",
- "-c", "export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"",
- "sh", /* argv[0] for sh */
- };
+#if defined(__linux__) && !defined(__BIONIC__)
+ SpawnWrapperData wrapper_data;
+#endif
+ GSpawnChildSetupFunc setup = user_setup;
+ gpointer setup_data = user_setup_data;
old_uris = dup_uris;
if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
- goto out;
+ return FALSE;
/* Get the subset of URIs we're launching with this process */
- launched_uris = NULL;
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
launched_uris = g_list_prepend (launched_uris, iter->data);
launched_uris = g_list_reverse (launched_uris);
@@ -2799,7 +2934,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Unable to find terminal required for application"));
- goto out;
+ return FALSE;
}
if (info->filename)
@@ -2808,7 +2943,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
info->filename,
TRUE);
- sn_id = NULL;
if (launch_context)
{
GList *launched_files = create_files_for_uris (launched_uris);
@@ -2837,38 +2971,93 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
* with a wrapper program (grep the GLib git history for
* `gio-launch-desktop` for an example of this which could be
* resurrected). */
- wrapped_argv = g_new (char *, argc + G_N_ELEMENTS (wrapper_argv) + 1);
+ wrapped_argv = g_new (char *, argc + 6 + 1);
+
+ wrapped_argv[0] = g_strdup ("/bin/sh");
+ wrapped_argv[1] = g_strdup ("-e");
+ wrapped_argv[2] = g_strdup ("-u");
+ wrapped_argv[3] = g_strdup ("-c");
+ /* argument 4 is filled in below */
+ wrapped_argv[5] = g_strdup ("sh");
- for (j = 0; j < G_N_ELEMENTS (wrapper_argv); j++)
- wrapped_argv[j] = g_strdup (wrapper_argv[j]);
for (i = 0; i < argc; i++)
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = g_steal_pointer (&argv[i]);
+ wrapped_argv[i + 6] = g_steal_pointer (&argv[i]);
+
+ wrapped_argv[i + 6] = NULL;
+ g_clear_pointer (&argv, g_free);
+
+#if defined(__linux__) && !defined(__BIONIC__)
+ /* Create pipes, if we use a setup func, then set cloexec,
+ * otherwise our wrapper script will close both sides. */
+ if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to create pipe for systemd synchronization"));
+ return FALSE;
+ }
+
+ /* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
+ fcntl (wrapper_data.pipe[1], F_SETFD, FD_CLOEXEC);
- wrapped_argv[i + G_N_ELEMENTS (wrapper_argv)] = NULL;
- g_free (argv);
- argv = NULL;
+ if (!(spawn_flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
+ {
+ /* In this case, we use a setup function (which could probably also
+ * overwrite envp to set GIO_LAUNCHED_DESKTOP_FILE_PID).
+ *
+ * Note that this does not incur an additional cost because
+ * G_SPAWN_LEAVE_DESCRIPTOR_OPEN must be set in order to use
+ * posix_spawn. */
+ wrapper_data.user_setup = setup;
+ wrapper_data.user_setup_data = setup_data;
+
+ setup = launch_uris_with_spawn_delay_exec;
+ setup_data = &wrapper_data;
+ }
+
+ wrapped_argv[4] = g_strdup_printf ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; cat <&%1$d; exec \"$@\" %1$d<&-",
+ wrapper_data.pipe[0]);
+#else
+ wrapped_argv[4] = g_strdup ("export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; exec \"$@\"");
+#endif
if (!g_spawn_async_with_fds (info->path,
wrapped_argv,
envp,
spawn_flags,
- user_setup,
- user_setup_data,
+ setup,
+ setup_data,
&pid,
stdin_fd,
stdout_fd,
stderr_fd,
error))
{
+#if defined(__linux__) && !defined(__BIONIC__)
+ close (wrapper_data.pipe[0]);
+ close (wrapper_data.pipe[1]);
+#endif
+
if (sn_id)
g_app_launch_context_launch_failed (launch_context, sn_id);
- g_free (sn_id);
- g_list_free (launched_uris);
-
goto out;
}
+#if defined(__linux__) && !defined(__BIONIC__)
+ /* We close write side asynchronously later on when the dbus call
+ * to systemd finishes. */
+ close (wrapper_data.pipe[0]);
+
+ if (session_bus)
+ create_systemd_scope (session_bus,
+ info,
+ pid,
+ systemd_scope_created_cb,
+ GINT_TO_POINTER (wrapper_data.pipe[1]));
+ else
+ close (wrapper_data.pipe[1]);
+#endif
+
if (pid_callback != NULL)
pid_callback (info, pid, pid_callback_data);
@@ -2893,19 +3082,20 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
sn_id,
launched_uris);
- g_free (sn_id);
- g_list_free (launched_uris);
-
- g_strfreev (wrapped_argv);
- wrapped_argv = NULL;
+ g_clear_pointer (&sn_id, g_free);
+ g_clear_pointer (&launched_uris, g_list_free);
+ g_clear_pointer (&wrapped_argv, g_strfreev);
}
while (dup_uris != NULL);
completed = TRUE;
- out:
+out:
g_strfreev (argv);
g_strfreev (envp);
+ g_clear_pointer (&wrapped_argv, g_strfreev);
+ g_list_free (launched_uris);
+ g_free (sn_id);
return completed;
}
--
2.31.1
From cd67a1b0256d2397dac0836e154f3449b63a6b19 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Tue, 28 Jul 2020 12:11:13 +0200
Subject: [PATCH 3/4] gdesktopappinfo: Handle task completion from spawn
function
This allows delaying the return of the task until all dbus calls (in
particular the ones to setup the scope) have finished.
This fixes the behaviour of the previous commit which would not
correctly move the process into the scope if the application exited
right after the task returned.
---
gio/gdesktopappinfo.c | 212 +++++++++++++++++++++++++++++-------------
1 file changed, 146 insertions(+), 66 deletions(-)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index afdcd42ac..8d0f1688e 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2849,11 +2849,17 @@ create_systemd_scope (GDBusConnection *session_bus,
g_free (unit_name);
}
+typedef struct {
+ GTask *task;
+ int fd;
+} ScopeCreatedData;
+
static void
systemd_scope_created_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
+ ScopeCreatedData *data = user_data;
GVariant *res = NULL;
GError *error = NULL;
@@ -2865,13 +2871,47 @@ systemd_scope_created_cb (GObject *object,
}
/* Unblock the waiting wrapper binary. */
- close (GPOINTER_TO_INT (user_data));
+
+ close (data->fd);
+
+ if (data->task)
+ {
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (data->task));
+ pending -= 1;
+ g_task_set_task_data (data->task, GINT_TO_POINTER (pending), NULL);
+
+ if (pending == 0 && !g_task_get_completed (data->task))
+ g_task_return_boolean (data->task, TRUE);
+ }
if (res)
g_variant_unref (res);
+ g_clear_object (&data->task);
+ g_free (data);
}
#endif
+static void
+launch_uris_with_spawn_flush_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ gint pending;
+
+ g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
+
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending -= 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ if (pending == 0 && !g_task_get_completed (task))
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
static gboolean
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GDBusConnection *session_bus,
@@ -2886,9 +2926,10 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
- GError **error)
+ GTask *task,
+ GError **error_out)
{
- gboolean completed = FALSE;
+ GError *error = NULL;
GList *old_uris;
GList *dup_uris;
@@ -2898,8 +2939,15 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
char *sn_id = NULL;
int argc;
+ /* We may get a task to report back on or an error. But never both. */
+ g_assert (!(task && error_out));
g_return_val_if_fail (info != NULL, FALSE);
+ /* Surrounding code must not have set any data on the task
+ * (it is cleared before calling this function). */
+ if (session_bus && task)
+ g_assert (g_task_get_task_data (task) == NULL);
+
if (launch_context)
envp = g_app_launch_context_get_environment (launch_context);
else
@@ -2922,8 +2970,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gpointer setup_data = user_setup_data;
old_uris = dup_uris;
- if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
- return FALSE;
+ if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, &error))
+ goto out;
/* Get the subset of URIs we're launching with this process */
for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
@@ -2932,9 +2980,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to find terminal required for application"));
- return FALSE;
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to find terminal required for application"));
+ goto out;
}
if (info->filename)
@@ -2991,9 +3039,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
* otherwise our wrapper script will close both sides. */
if (!g_unix_open_pipe (wrapper_data.pipe, 0, NULL))
{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to create pipe for systemd synchronization"));
- return FALSE;
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Unable to create pipe for systemd synchronization"));
+ goto out;
}
/* Set CLOEXEC on the write pipe, so we don't need to deal with it in the child. */
@@ -3030,7 +3078,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
stdin_fd,
stdout_fd,
stderr_fd,
- error))
+ &error))
{
#if defined(__linux__) && !defined(__BIONIC__)
close (wrapper_data.pipe[0]);
@@ -3049,11 +3097,29 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
close (wrapper_data.pipe[0]);
if (session_bus)
- create_systemd_scope (session_bus,
- info,
- pid,
- systemd_scope_created_cb,
- GINT_TO_POINTER (wrapper_data.pipe[1]));
+ {
+ ScopeCreatedData *data;
+
+ data = g_new0 (ScopeCreatedData, 1);
+
+ if (task)
+ {
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending += 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ data->task = g_object_ref (task);
+ }
+
+ data->fd = wrapper_data.pipe[1];
+
+ create_systemd_scope (session_bus,
+ info,
+ pid,
+ systemd_scope_created_cb,
+ data);
+ }
else
close (wrapper_data.pipe[1]);
#endif
@@ -3088,8 +3154,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
}
while (dup_uris != NULL);
- completed = TRUE;
-
out:
g_strfreev (argv);
g_strfreev (envp);
@@ -3097,7 +3161,52 @@ out:
g_list_free (launched_uris);
g_free (sn_id);
- return completed;
+ if (!error)
+ {
+ if (session_bus && task)
+ {
+ GCancellable *cancellable = g_task_get_cancellable (task);
+ gint pending;
+ pending = GPOINTER_TO_INT (g_task_get_task_data (task));
+ pending += 1;
+ g_task_set_task_data (task, GINT_TO_POINTER (pending), NULL);
+
+ /* FIXME: The D-Bus message from the notify_desktop_launch() function
+ * can be still lost even if flush is called later. See:
+ * https://gitlab.freedesktop.org/dbus/dbus/issues/72
+ */
+ g_dbus_connection_flush (session_bus,
+ cancellable,
+ launch_uris_with_spawn_flush_cb,
+ g_steal_pointer (&task));
+ }
+ else if (session_bus)
+ {
+ /* No task available. */
+ g_dbus_connection_flush (session_bus,
+ NULL,
+ NULL,
+ NULL);
+ }
+ else if (task)
+ {
+ /* Return the given task. */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+ }
+ else
+ {
+ if (task)
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ }
+ else
+ g_propagate_error (error_out, error);
+ }
+
+ return !error;
}
static gchar *
@@ -3246,17 +3355,9 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
spawn_flags, user_setup, user_setup_data,
pid_callback, pid_callback_data,
- stdin_fd, stdout_fd, stderr_fd, error);
+ stdin_fd, stdout_fd, stderr_fd, NULL, error);
- if (session_bus != NULL)
- {
- /* This asynchronous flush holds a reference until it completes,
- * which ensures that the following unref won't immediately kill
- * the connection if we were the initial owner.
- */
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
- g_object_unref (session_bus);
- }
+ g_clear_object (&session_bus);
return success;
}
@@ -3310,18 +3411,6 @@ launch_uris_with_dbus_cb (GObject *object,
g_object_unref (task);
}
-static void
-launch_uris_flush_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GTask *task = G_TASK (user_data);
-
- g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
static void
launch_uris_bus_get_cb (GObject *object,
GAsyncResult *result,
@@ -3330,12 +3419,20 @@ launch_uris_bus_get_cb (GObject *object,
GTask *task = G_TASK (user_data);
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (g_task_get_source_object (task));
LaunchUrisData *data = g_task_get_task_data (task);
+ LaunchUrisData *data_copy = NULL;
GCancellable *cancellable = g_task_get_cancellable (task);
GDBusConnection *session_bus;
- GError *error = NULL;
session_bus = g_bus_get_finish (result, NULL);
+ data_copy = g_new0 (LaunchUrisData, 1);
+ data_copy->appinfo = g_steal_pointer (&data->appinfo);
+ data_copy->uris = g_steal_pointer (&data->uris);
+ data_copy->context = g_steal_pointer (&data->context);
+
+ /* Allow other data to be attached to the task. */
+ g_task_set_task_data (task, NULL, NULL);
+
if (session_bus && info->app_id)
{
/* FIXME: The g_document_portal_add_documents() function, which is called
@@ -3343,34 +3440,21 @@ launch_uris_bus_get_cb (GObject *object,
* uses blocking calls.
*/
g_desktop_app_info_launch_uris_with_dbus (info, session_bus,
- data->uris, data->context,
+ data_copy->uris, data_copy->context,
cancellable,
launch_uris_with_dbus_cb,
g_steal_pointer (&task));
}
else
{
- /* FIXME: The D-Bus message from the notify_desktop_launch() function
- * can be still lost even if flush is called later. See:
- * https://gitlab.freedesktop.org/dbus/dbus/issues/72
- */
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec,
- data->uris, data->context,
+ data_copy->uris, data_copy->context,
_SPAWN_FLAGS_DEFAULT, NULL,
NULL, NULL, NULL, -1, -1, -1,
- &error);
- if (error != NULL)
- {
- g_task_return_error (task, g_steal_pointer (&error));
- g_object_unref (task);
- }
- else
- g_dbus_connection_flush (session_bus,
- cancellable,
- launch_uris_flush_cb,
- g_steal_pointer (&task));
+ g_steal_pointer (&task), NULL);
}
+ launch_uris_data_free (data_copy);
g_clear_object (&session_bus);
}
@@ -5186,16 +5270,12 @@ g_desktop_app_info_launch_action (GDesktopAppInfo *info,
if (exec_line)
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL,
- -1, -1, -1, NULL);
+ -1, -1, -1, NULL, NULL);
g_free (exec_line);
}
- if (session_bus != NULL)
- {
- g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
- g_object_unref (session_bus);
- }
+ g_clear_object (&session_bus);
}
/* Epilogue {{{1 */
--
2.31.1
From 8da8a3ef6df8af6de8bd388192bebe8b51b3e782 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Thu, 17 Sep 2020 17:35:58 +0200
Subject: [PATCH 4/4] gdesktopappinfo: Add SourcePath= to transient systemd
units
systemd allows setting a SourcePath= which shows the file that the unit
has been generated from. KDE is starting to set this and it seems like a
good idea, so do the same here.
See https://invent.kde.org/frameworks/kio/-/merge_requests/124
---
gio/gdesktopappinfo.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 8d0f1688e..a833de4e6 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2777,6 +2777,7 @@ create_systemd_scope (GDBusConnection *session_bus,
{
GVariantBuilder builder;
const char *app_name = g_get_application_name ();
+ const char *source_path = NULL;
char *appid = NULL;
char *appid_escaped = NULL;
char *snid_escaped = NULL;
@@ -2802,6 +2803,8 @@ create_systemd_scope (GDBusConnection *session_bus,
*/
unit_name = g_strdup_printf ("app-glib-%s-%d.scope", appid_escaped, pid);
+ source_path = g_desktop_app_info_get_filename (info);
+
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
g_variant_builder_add (&builder, "s", unit_name);
g_variant_builder_add (&builder, "s", "fail");
@@ -2815,6 +2818,16 @@ create_systemd_scope (GDBusConnection *session_bus,
"Description",
g_variant_new_take_string (g_strdup_printf ("Application launched by %s",
app_name)));
+
+ /* If we have a .desktop file, document that the scope has been "generated"
+ * from it.
+ */
+ if (source_path && g_utf8_validate (source_path, -1, NULL))
+ g_variant_builder_add (&builder,
+ "(sv)",
+ "SourcePath",
+ g_variant_new_string (source_path));
+
g_variant_builder_add (&builder,
"(sv)",
"PIDs",
--
2.31.1

View File

@ -1,25 +1,24 @@
# https://bugzilla.redhat.com/show_bug.cgi?id=1973304
%global __brp_check_rpaths %{nil}
Name: glib2
Version: 2.68.2
Release: 1%{?dist}
Release: 2%{?dist}
Summary: A library of handy utility functions
License: LGPLv2+
URL: http://www.gtk.org
Source0: http://download.gnome.org/sources/glib/2.68/glib-%{version}.tar.xz
%if 0%{?rhel}
# Required for RHEL core crypto components policy.
# Required for RHEL core crypto components policy. Good for Fedora too.
# https://bugzilla.redhat.com/show_bug.cgi?id=1630260
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
Patch0: gnutls-hmac.patch
%endif
# Add patches to move applications into systemd scopes in compliance with
# https://systemd.io/DESKTOP_ENVIRONMENTS/
# Proposed upstream at https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1596
Patch001: 0001-tests-Iterate-mainloop-during-launch-test.patch
Patch002: 0002-gdesktopappinfo-Move-launched-applications-into-tran.patch
Patch003: 0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch
Patch004: 0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch
Patch1: gdesktopappinfo.patch
BuildRequires: chrpath
BuildRequires: gcc
@ -34,10 +33,6 @@ BuildRequires: libselinux-devel
BuildRequires: meson
# for sys/sdt.h
BuildRequires: systemtap-sdt-devel
%if 0%{?rhel}
# For gnutls-hmac.patch
BuildRequires: pkgconfig(gnutls)
%endif
BuildRequires: pkgconfig(libelf)
BuildRequires: pkgconfig(libffi)
BuildRequires: pkgconfig(libpcre)
@ -46,6 +41,15 @@ BuildRequires: pkgconfig(sysprof-capture-4)
BuildRequires: pkgconfig(zlib)
BuildRequires: python3-devel
# For gnutls-hmac.patch. We now dlopen libgnutls.so.30 so that we can build a
# static glib2 without depending on a static build of GnuTLS as well. This will
# ensure we notice if the GnuTLS soname bumps, so that we can update our patch.
%if 0%{__isa_bits} == 64
Requires: libgnutls.so.30()(64bit)
%else
Requires: libgnutls.so.30()
%endif
# for GIO content-type support
Recommends: shared-mime-info
@ -82,14 +86,12 @@ BuildArch: noarch
%description doc
The glib2-doc package includes documentation for the GLib library.
%if !0%{?rhel}
%package static
Summary: glib static
Requires: %{name}-devel = %{version}-%{release}
%description static
The %{name}-static subpackage contains static libraries for %{name}.
%endif
%package tests
Summary: Tests for the glib2 package
@ -107,9 +109,6 @@ the functionality of the installed glib2 package.
rm -rf glib/pcre
rm -rf subprojects
# We cannot build with GnuTLS in Fedora since there is no gnutls-static
# subpackage. (glib2-static is needed by qemu in Fedora, but not in RHEL.)
# Accordingly, we can't build a usable glib2-static in RHEL.
%meson \
-Dman=true \
-Ddtrace=true \
@ -118,12 +117,8 @@ rm -rf subprojects
-Dglib_debug=disabled \
-Dgtk_doc=true \
-Dinstalled_tests=true \
%if 0%{?rhel}
-Dgnutls=true \
%endif
%if !0%{?rhel}
--default-library=both \
%endif
%{nil}
%meson_build
@ -233,20 +228,23 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%files doc
%{_datadir}/gtk-doc/
%if !0%{?rhel}
%files static
%{_libdir}/libgio-2.0.a
%{_libdir}/libglib-2.0.a
%{_libdir}/libgmodule-2.0.a
%{_libdir}/libgobject-2.0.a
%{_libdir}/libgthread-2.0.a
%endif
%files tests
%{_libexecdir}/installed-tests
%{_datadir}/installed-tests
%changelog
* Thu Jun 17 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.2-2
- Enable GnuTLS-based GHmac in Fedora and reenable glib2-static in RHEL
- Consolidate GDesktopAppInfo changes into gdesktopappinfo.patch
- Disable check-rpath since it seems to be broken
* Tue May 11 2021 Kalev Lember <klember@redhat.com> - 2.68.2-1
- Update to 2.68.2

View File

@ -1,7 +1,7 @@
From 12e9cd51eb0ef07c3554cd035f92d8b7b5b82304 Mon Sep 17 00:00:00 2001
From 86412ea2265ae018ba6146d525cafce78782c0fc Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 18:44:43 +0000
Subject: [PATCH 1/2] ghmac: Split off wrapper functions into ghmac-utils.c
Subject: [PATCH 1/4] ghmac: Split off wrapper functions into ghmac-utils.c
Prep for adding a GnuTLS HMAC implementation; these are just
utility functions that call the "core" API.
@ -284,10 +284,10 @@ index 49fd272f0..4f181f21f 100644
- (const guchar *) str, length);
-}
diff --git a/glib/meson.build b/glib/meson.build
index 8c18e6de4..329b8d197 100644
index 28bfae200..0a37d19ea 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -253,6 +253,7 @@ glib_sources = files(
@@ -254,6 +254,7 @@ glib_sources = files(
'ggettext.c',
'ghash.c',
'ghmac.c',
@ -296,13 +296,12 @@ index 8c18e6de4..329b8d197 100644
'ghostutils.c',
'giochannel.c',
--
2.29.2
2.31.1
From 231ed985074af4a354405cf1961fabf9c60bce43 Mon Sep 17 00:00:00 2001
From a5ee9970772e182de1c249ee514e87ef38e08360 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 19:36:54 +0000
Subject: [PATCH 2/2] Add a gnutls backend for GHmac
Subject: [PATCH 2/4] Add a gnutls backend for GHmac
For RHEL we want apps to use FIPS-certified crypto libraries,
and HMAC apparently counts as "keyed" and hence needs to
@ -316,18 +315,47 @@ Most distributors ship glib-networking built with GnuTLS, and
most apps use glib-networking, so this isn't a net-new library
in most cases.
mcatanzaro note: I've updated Colin's original patch to implement
g_hmac_copy() using gnutls_hmac_copy(), which didn't exist when Colin
developed this patch.
=======================================================================
mcatanzaro note:
I've updated Colin's original patch with several enhancements:
Implement g_hmac_copy() using gnutls_hmac_copy(), which didn't exist
when Colin developed this patch.
Removed use of GSlice
Better error checking in g_hmac_new(). It is possible for
gnutls_hmac_init() to fail if running in FIPS mode and an MD5 digest is
requested. In this case, we should return NULL rather than returning a
broken GHmac with a NULL gnutls_hmac_hd_t. This was leading to a later
null pointer dereference inside gnutls_hmac_update(). Applications are
responsible for checking to ensure the return value of g_hmac_new() is
not NULL since it is annotated as nullable. Added documentation to
indicate this possibility.
Properly handle length -1 in g_hmac_update(). This means we've been
given a NUL-terminated string and should use strlen(). GnuTLS doesn't
accept -1, so let's call strlen() ourselves.
Crash the application with g_error() if gnutls_hmac() fails for any
reason. This is necessary because g_hmac_update() is not fallible, so we
have no way to indicate error. Crashing seems better than returning the
wrong result later when g_hmac_get_string() or g_hmac_get_digest() is
later called. (Those functions are also not fallible.) Fortunately, I
don't think this error should actually be hit in practice.
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
---
glib/gchecksum.c | 9 ++-
glib/gchecksumprivate.h | 32 ++++++++
glib/ghmac-gnutls.c | 164 ++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 3 +
glib/gchecksum.c | 9 +-
glib/gchecksumprivate.h | 32 +++++++
glib/ghmac-gnutls.c | 187 ++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 15 ++++
glib/meson.build | 10 ++-
meson.build | 7 ++
meson_options.txt | 5 ++
7 files changed, 224 insertions(+), 6 deletions(-)
7 files changed, 259 insertions(+), 6 deletions(-)
create mode 100644 glib/gchecksumprivate.h
create mode 100644 glib/ghmac-gnutls.c
@ -406,10 +434,10 @@ index 000000000..86c7a3b61
\ No newline at end of file
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
new file mode 100644
index 000000000..f1a74a849
index 000000000..a55375060
--- /dev/null
+++ b/glib/ghmac-gnutls.c
@@ -0,0 +1,164 @@
@@ -0,0 +1,187 @@
+/* ghmac.h - data hashing functions
+ *
+ * Copyright (C) 2011 Collabora Ltd.
@ -464,9 +492,11 @@ index 000000000..f1a74a849
+ gsize key_len)
+{
+ gnutls_mac_algorithm_t algo;
+ GHmac *hmac = g_slice_new0 (GHmac);
+ GHmac *hmac = g_new0 (GHmac, 1);
+ int ret;
+
+ hmac->ref_count = 1;
+ hmac->digest_type = digest_type;
+ hmac->digest_type = digest_type;
+
+ switch (digest_type)
+ {
@ -489,7 +519,16 @@ index 000000000..f1a74a849
+ g_return_val_if_reached (NULL);
+ }
+
+ gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
+ ret = gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
+ if (ret != 0)
+ {
+ /* There is no way to report an error here, but one possible cause of
+ * failure is that the requested digest may be disabled by Fedora or RHEL
+ * system crypto policy. As of 2021, MD5 and SHA-1 are likely disabled.
+ */
+ g_free (hmac->hmac);
+ return NULL;
+ }
+
+ return hmac;
+}
@ -501,11 +540,15 @@ index 000000000..f1a74a849
+
+ g_return_val_if_fail (hmac != NULL, NULL);
+
+ copy = g_slice_new0 (GHmac);
+ copy = g_new0 (GHmac, 1);
+ copy->ref_count = 1;
+ copy->digest_type = hmac->digest_type;
+ copy->hmac = gnutls_hmac_copy (hmac->hmac);
+
+ /* g_hmac_copy is not allowed to fail, so we'll have to crash on error. */
+ if (!copy->hmac)
+ g_error ("gnutls_hmac_copy failed");
+
+ return copy;
+}
+
@ -528,7 +571,7 @@ index 000000000..f1a74a849
+ {
+ gnutls_hmac_deinit (hmac->hmac, NULL);
+ g_free (hmac->digest_str);
+ g_slice_free (GHmac, hmac);
+ g_free (hmac);
+ }
+}
+
@ -538,10 +581,18 @@ index 000000000..f1a74a849
+ const guchar *data,
+ gssize length)
+{
+ int ret;
+
+ g_return_if_fail (hmac != NULL);
+ g_return_if_fail (length == 0 || data != NULL);
+
+ gnutls_hmac (hmac->hmac, data, length);
+ if (length == -1)
+ length = strlen ((const char *)data);
+
+ /* g_hmac_update is not allowed to fail, so we'll have to crash on error. */
+ ret = gnutls_hmac (hmac->hmac, data, length);
+ if (ret != 0)
+ g_error ("gnutls_hmac failed: %s", gnutls_strerror (ret));
+}
+
+const gchar *
@ -575,7 +626,7 @@ index 000000000..f1a74a849
+ *digest_len = g_checksum_type_get_length (hmac->digest_type);
+}
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 4f181f21f..c62d9ce4e 100644
index 4f181f21f..0e39ea40a 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,6 +33,9 @@
@ -588,11 +639,30 @@ index 4f181f21f..c62d9ce4e 100644
/**
* SECTION:hmac
@@ -84,6 +87,18 @@ struct _GHmac
* Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
* Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
*
+ * Note that #GHmac creation may fail, in which case this function will
+ * return %NULL. Since there is no error parameter, it is not possible
+ * to indicate why.
+ *
+ * In Fedora, CentOS Stream, and Red Hat Enterprise Linux, GLib is
+ * configured to use GnuTLS to implement #GHmac in order to support FIPS
+ * compliance. This introduces additional failure possibilities that are
+ * not present in upstream GLib. For example, the creation of a #GHmac
+ * will fail if @digest_type is %G_CHECKSUM_MD5 and the system is
+ * running in FIPS mode. #GHmac creation may also fail if GLib is unable
+ * to load GnuTLS.
+ *
* Returns: the newly created #GHmac, or %NULL.
* Use g_hmac_unref() to free the memory allocated by it.
*
diff --git a/glib/meson.build b/glib/meson.build
index 329b8d197..2942a7e9b 100644
index 0a37d19ea..b17c89dd9 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -252,7 +252,6 @@ glib_sources = files(
@@ -253,7 +253,6 @@ glib_sources = files(
'gfileutils.c',
'ggettext.c',
'ghash.c',
@ -600,7 +670,7 @@ index 329b8d197..2942a7e9b 100644
'ghmac-utils.c',
'ghook.c',
'ghostutils.c',
@@ -308,6 +307,7 @@ glib_sources = files(
@@ -309,6 +308,7 @@ glib_sources = files(
'guriprivate.h',
'gutils.c',
'gutilsprivate.h',
@ -608,7 +678,7 @@ index 329b8d197..2942a7e9b 100644
'guuid.c',
'gvariant.c',
'gvariant-core.c',
@@ -352,6 +352,12 @@ else
@@ -353,6 +353,12 @@ else
glib_dtrace_hdr = []
endif
@ -621,7 +691,7 @@ index 329b8d197..2942a7e9b 100644
pcre_static_args = []
if use_pcre_static_flag
@@ -378,7 +384,7 @@ libglib = library('glib-2.0',
@@ -379,7 +385,7 @@ libglib = library('glib-2.0',
# intl.lib is not compatible with SAFESEH
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
include_directories : configinc,
@ -631,10 +701,10 @@ index 329b8d197..2942a7e9b 100644
objc_args : glib_c_args,
)
diff --git a/meson.build b/meson.build
index 0d892fb2d..091029fea 100644
index a0ee8b774..064dba800 100644
--- a/meson.build
+++ b/meson.build
@@ -2078,6 +2078,13 @@ if host_system == 'linux'
@@ -2104,6 +2104,13 @@ if host_system == 'linux'
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
endif
@ -665,5 +735,351 @@ index 072765361..d2370042f 100644
type : 'boolean',
value : false,
--
2.29.2
2.31.1
From cde56a63aa12ae7c30f85af7d058fa5e666aa2e9 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 16 Jun 2021 20:35:00 -0500
Subject: [PATCH 3/4] dlopen GnuTLS instead of linking directly
I'd like to enable our GnuTLS GHmac patchset in Fedora in order to
ensure it is receiving sufficient real-world testing, since we've
discovered several bugs thus far. Problem is Fedora has one requirement
that RHEL does not: it needs to build glib as a static lib. This is
needed by QEMU in Fedora for complicated technical reasons that I don't
understand. However, nothing in RHEL needs it. This means we failed to
notice that glib2-static is broken in RHEL, because there is no
gnutls-static! We could fix this by adding a gnutls-static package, but
that seems like overkill, and adding more static libraries where they're
not truly necessary is not the direction we want to move in anyway. So
instead, let's just dlopen GnuTLS to sidestep this problem entirely.
This would not be a good solution for upstream, but upstream has made
clear that this patchset is already non-upstreamable, so it will be fine
for our purposes.
---
glib/ghmac-gnutls.c | 101 ++++++++++++++++++++++++++++++++++++++++++--
glib/ghmac.c | 2 +-
glib/meson.build | 2 +-
meson.build | 6 +--
4 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
index a55375060..0469d2bd0 100644
--- a/glib/ghmac-gnutls.c
+++ b/glib/ghmac-gnutls.c
@@ -19,8 +19,8 @@
#include "config.h"
+#include <dlfcn.h>
#include <string.h>
-#include <gnutls/crypto.h>
#include "ghmac.h"
@@ -31,13 +31,16 @@
#include "gstrfuncs.h"
#include "gchecksumprivate.h"
#include "gtestutils.h"
+#include "gthread.h"
#include "gtypes.h"
#include "glibintl.h"
-#ifndef HAVE_GNUTLS
+#ifndef USE_GNUTLS
#error "build configuration error"
#endif
+typedef gpointer gnutls_hmac_hd_t;
+
struct _GHmac
{
int ref_count;
@@ -46,15 +49,107 @@ struct _GHmac
gchar *digest_str;
};
+typedef enum
+{
+ GNUTLS_MAC_MD5 = 2,
+ GNUTLS_MAC_SHA1 = 3,
+ GNUTLS_MAC_SHA256 = 6,
+ GNUTLS_MAC_SHA384 = 7,
+ GNUTLS_MAC_SHA512 = 8,
+} gnutls_mac_algorithm_t;
+
+/* Why are we dlopening GnuTLS instead of linking to it directly? Because we
+ * want to be able to build GLib as a static library without depending on a
+ * static build of GnuTLS. QEMU depends on static linking with GLib, but Fedora
+ * does not ship a static build of GnuTLS, and this allows us to avoid changing
+ * that.
+ */
+static int (*gnutls_hmac_init) (gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm, const void *key, size_t keylen);
+static gnutls_hmac_hd_t (*gnutls_hmac_copy) (gnutls_hmac_hd_t handle);
+static void (*gnutls_hmac_deinit) (gnutls_hmac_hd_t handle, void *digest);
+static int (*gnutls_hmac) (gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len);
+static void (*gnutls_hmac_output) (gnutls_hmac_hd_t handle, void *digest);
+static const char * (*gnutls_strerror) (int error);
+
+static gsize gnutls_initialize_attempted = 0;
+static gboolean gnutls_initialize_successful = FALSE;
+
+static void
+initialize_gnutls (void)
+{
+ gpointer libgnutls;
+
+ libgnutls = dlopen ("libgnutls.so.30", RTLD_LAZY | RTLD_GLOBAL);
+ if (!libgnutls)
+ {
+ g_warning ("Cannot use GHmac: failed to load libgnutls.so.30: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_init = dlsym (libgnutls, "gnutls_hmac_init");
+ if (!gnutls_hmac_init)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_init: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_copy = dlsym (libgnutls, "gnutls_hmac_copy");
+ if (!gnutls_hmac_copy)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_copy: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_deinit = dlsym (libgnutls, "gnutls_hmac_deinit");
+ if (!gnutls_hmac_deinit)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_deinit: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac = dlsym (libgnutls, "gnutls_hmac");
+ if (!gnutls_hmac)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_output = dlsym (libgnutls, "gnutls_hmac_output");
+ if (!gnutls_hmac_output)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_output: %s", dlerror ());
+ return;
+ }
+
+ gnutls_strerror = dlsym (libgnutls, "gnutls_strerror");
+ if (!gnutls_strerror)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_strerror: %s", dlerror ());
+ return;
+ }
+
+ gnutls_initialize_successful = TRUE;
+}
+
GHmac *
g_hmac_new (GChecksumType digest_type,
const guchar *key,
gsize key_len)
{
gnutls_mac_algorithm_t algo;
- GHmac *hmac = g_new0 (GHmac, 1);
+ GHmac *hmac;
int ret;
+ if (g_once_init_enter (&gnutls_initialize_attempted))
+ {
+ initialize_gnutls ();
+ g_once_init_leave (&gnutls_initialize_attempted, 1);
+ }
+
+ if (!gnutls_initialize_successful)
+ return NULL;
+
+ hmac = g_new0 (GHmac, 1);
hmac->ref_count = 1;
hmac->digest_type = digest_type;
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 0e39ea40a..2d9be91b8 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,7 +33,7 @@
#include "gtypes.h"
#include "glibintl.h"
-#ifdef HAVE_GNUTLS
+#ifdef USE_GNUTLS
#error "build configuration error"
#endif
diff --git a/glib/meson.build b/glib/meson.build
index b17c89dd9..a015f7755 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -385,7 +385,7 @@ libglib = library('glib-2.0',
# intl.lib is not compatible with SAFESEH
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
include_directories : configinc,
- dependencies : pcre_deps + libgnutls_dep + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
+ dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep] + [libdl_dep],
c_args : glib_c_args,
objc_args : glib_c_args,
)
diff --git a/meson.build b/meson.build
index 064dba800..7aae7dfea 100644
--- a/meson.build
+++ b/meson.build
@@ -2104,11 +2104,9 @@ if host_system == 'linux'
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
endif
-# gnutls is used optionally by ghmac
-libgnutls_dep = []
+# gnutls is used optionally by GHmac
if get_option('gnutls')
- libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
- glib_conf.set('HAVE_GNUTLS', 1)
+ glib_conf.set('USE_GNUTLS', 1)
endif
if host_system == 'windows'
--
2.31.1
From b61ea19037287cae2e6152e9616767a691bf4af0 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 16 Jun 2021 20:46:24 -0500
Subject: [PATCH 4/4] Add test for GHmac in FIPS mode
This will test a few problems that we hit recently:
g_hmac_copy() is broken, https://bugzilla.redhat.com/show_bug.cgi?id=1786538
Crash in g_hmac_update() in FIPS mode, https://bugzilla.redhat.com/show_bug.cgi?id=1971533
Crash when passing -1 length to g_hmac_update() (discovered in #1971533)
We'll also test to ensure MD5 fails, and stop compiling the other MD5
tests.
---
glib/tests/hmac.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/glib/tests/hmac.c b/glib/tests/hmac.c
index 3ac3206df..6698c4d19 100644
--- a/glib/tests/hmac.c
+++ b/glib/tests/hmac.c
@@ -1,7 +1,10 @@
+#include "config.h"
+
#include <glib.h>
#include <string.h>
#include <stdlib.h>
+#ifndef USE_GNUTLS
/* HMAC-MD5 test vectors as per RFC 2202 */
/* Test 1 */
@@ -81,6 +84,7 @@ guint8 key_md5_test7[] = {
guint8 result_md5_test7[] = {
0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e };
+#endif
/* HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 test vectors
* as per RFCs 2202 and 4868.
@@ -299,6 +303,7 @@ typedef struct {
gconstpointer result;
} HmacCase;
+#ifndef USE_GNUTLS
HmacCase hmac_md5_tests[] = {
{ G_CHECKSUM_MD5, key_md5_test1, 16, "Hi There", 8, result_md5_test1 },
{ G_CHECKSUM_MD5, "Jefe", 4, "what do ya want for nothing?", 28,
@@ -317,6 +322,7 @@ HmacCase hmac_md5_tests[] = {
73, result_md5_test7 },
{ -1, NULL, 0, NULL, 0, NULL },
};
+#endif
HmacCase hmac_sha1_tests[] = {
{ G_CHECKSUM_SHA1, key_sha_test1, 20, "Hi There", 8, result_sha1_test1 },
@@ -493,11 +499,44 @@ test_hmac_for_bytes (void)
g_bytes_unref (data);
}
+#ifdef USE_GNUTLS
+static void
+test_gnutls_fips_mode (void)
+{
+ GHmac *hmac;
+ GHmac *copy;
+
+ /* No MD5 in FIPS mode. */
+ hmac = g_hmac_new (G_CHECKSUM_MD5, "abc123", sizeof ("abc123"));
+ g_assert_null (hmac);
+
+ /* SHA-256 should be good. */
+ hmac = g_hmac_new (G_CHECKSUM_SHA256, "abc123", sizeof ("abc123"));
+ g_assert_nonnull (hmac);
+
+ /* Ensure g_hmac_update() does not crash when called with -1. */
+ g_hmac_update (hmac, "You win again, gravity!", -1);
+
+ /* Ensure g_hmac_copy() does not crash. */
+ copy = g_hmac_copy (hmac);
+ g_assert_nonnull (hmac);
+ g_hmac_unref (hmac);
+
+ g_assert_cmpstr (g_hmac_get_string (copy), ==, "795ba6900bcb22e8ce65c2ec02db4e85697da921deb960ee3143bf88a4a60f83");
+ g_hmac_unref (copy);
+}
+#endif
+
int
main (int argc,
char **argv)
{
int i;
+
+#ifdef USE_GNUTLS
+ g_setenv ("GNUTLS_FORCE_FIPS_MODE", "1", FALSE);
+#endif
+
g_test_init (&argc, &argv, NULL);
for (i = 0 ; hmac_sha1_tests[i].key_len > 0 ; i++)
@@ -532,6 +571,7 @@ main (int argc,
g_free (name);
}
+#ifndef USE_GNUTLS
for (i = 0 ; hmac_md5_tests[i].key_len > 0 ; i++)
{
gchar *name = g_strdup_printf ("/hmac/md5-%d", i + 1);
@@ -539,6 +579,7 @@ main (int argc,
(void (*)(const void *)) test_hmac);
g_free (name);
}
+#endif
g_test_add_func ("/hmac/ref-unref", test_hmac_ref_unref);
g_test_add_func ("/hmac/copy", test_hmac_copy);
@@ -546,5 +587,9 @@ main (int argc,
g_test_add_func ("/hmac/for-string", test_hmac_for_string);
g_test_add_func ("/hmac/for-bytes", test_hmac_for_bytes);
+#ifdef USE_GNUTLS
+ g_test_add_func ("/hmac/gnutls-fips-mode", test_gnutls_fips_mode);
+#endif
+
return g_test_run ();
}
--
2.31.1