From 1f79f0520372d7802c298defcde49252386ce119 Mon Sep 17 00:00:00 2001 From: Michael Catanzaro Date: Thu, 17 Jun 2021 10:45:30 -0500 Subject: [PATCH] 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 --- ...-Iterate-mainloop-during-launch-test.patch | 30 - ...Move-launched-applications-into-tran.patch | 388 -------- ...Handle-task-completion-from-spawn-fu.patch | 382 -------- ...Add-SourcePath-to-transient-systemd-.patch | 56 -- gdesktopappinfo.patch | 855 ++++++++++++++++++ glib2.spec | 44 +- gnutls-hmac.patch | 482 +++++++++- 7 files changed, 1325 insertions(+), 912 deletions(-) delete mode 100644 0001-tests-Iterate-mainloop-during-launch-test.patch delete mode 100644 0002-gdesktopappinfo-Move-launched-applications-into-tran.patch delete mode 100644 0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch delete mode 100644 0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch create mode 100644 gdesktopappinfo.patch diff --git a/0001-tests-Iterate-mainloop-during-launch-test.patch b/0001-tests-Iterate-mainloop-during-launch-test.patch deleted file mode 100644 index 5290431..0000000 --- a/0001-tests-Iterate-mainloop-during-launch-test.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -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 - diff --git a/0002-gdesktopappinfo-Move-launched-applications-into-tran.patch b/0002-gdesktopappinfo-Move-launched-applications-into-tran.patch deleted file mode 100644 index a4e6290..0000000 --- a/0002-gdesktopappinfo-Move-launched-applications-into-tran.patch +++ /dev/null @@ -1,388 +0,0 @@ -From ba3b85a8fea0151e74de50e841a7f16f9b077a56 Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -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 - diff --git a/0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch b/0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch deleted file mode 100644 index 84a8d7a..0000000 --- a/0003-gdesktopappinfo-Handle-task-completion-from-spawn-fu.patch +++ /dev/null @@ -1,382 +0,0 @@ -From cd67a1b0256d2397dac0836e154f3449b63a6b19 Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -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 - diff --git a/0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch b/0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch deleted file mode 100644 index ae8a719..0000000 --- a/0004-gdesktopappinfo-Add-SourcePath-to-transient-systemd-.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 8da8a3ef6df8af6de8bd388192bebe8b51b3e782 Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -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 - diff --git a/gdesktopappinfo.patch b/gdesktopappinfo.patch new file mode 100644 index 0000000..786ac7c --- /dev/null +++ b/gdesktopappinfo.patch @@ -0,0 +1,855 @@ +From 5e42384cc4499293259a8a37a737014a56de34df Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +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 +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 +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 +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 diff --git a/glib2.spec b/glib2.spec index 91e031e..a45ca6e 100644 --- a/glib2.spec +++ b/glib2.spec @@ -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 - 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 - 2.68.2-1 - Update to 2.68.2 diff --git a/gnutls-hmac.patch b/gnutls-hmac.patch index 5d193f4..90ee2ee 100644 --- a/gnutls-hmac.patch +++ b/gnutls-hmac.patch @@ -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 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 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 +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 + #include +-#include + + #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 +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 + #include + #include + ++#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