diff --git a/SOURCES/1968.patch b/SOURCES/1968.patch new file mode 100644 index 0000000..1809214 --- /dev/null +++ b/SOURCES/1968.patch @@ -0,0 +1,1052 @@ +From 9e69f8b280afe8eccd9188cc53b8117e1b238db7 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Tue, 12 Oct 2021 15:52:18 -0500 +Subject: [PATCH 01/10] gspawn: use close_and_invalidate more + +--- + glib/gspawn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index a15fb1ca1..5d8422869 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1710,7 +1710,7 @@ do_exec (gint child_err_report_fd, + child_err_report_fd = safe_dup (child_err_report_fd); + + safe_dup2 (source_fds[i], target_fds[i]); +- (void) close (source_fds[i]); ++ close_and_invalidate (&source_fds[i]); + } + } + } +-- +2.33.1 + +From fe2148fd5dd4f2e5c413c5cc0bb56c4a19304887 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Thu, 14 Oct 2021 10:43:52 -0500 +Subject: [PATCH 02/10] gspawn: Improve error message when dup fails + +This error message is no longer accurate now that we allow arbitrary fd +remapping. +--- + glib/gspawn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index 5d8422869..e214a3998 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -2363,7 +2363,7 @@ fork_exec (gboolean intermediate_child, + g_set_error (error, + G_SPAWN_ERROR, + G_SPAWN_ERROR_FAILED, +- _("Failed to redirect output or input of child process (%s)"), ++ _("Failed to duplicate file descriptor for child process (%s)"), + g_strerror (buf[1])); + + break; +-- +2.33.1 + +From 566eccdb0a2594b4d3ec13c7443028d968b41af8 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Tue, 12 Oct 2021 15:33:59 -0500 +Subject: [PATCH 03/10] gspawn: fix hangs when duping child_err_report_fd + +In case child_err_report_fd conflicts with one of the target_fds, the +code here is careful to dup child_err_report_fd in order to avoid +conflating the two. It was a good idea, but evidently was not tested, +because the newly-created fd is not created with CLOEXEC set. This means +it stays open in the child process, causing the parent to hang forever +waiting to read from the other end of the pipe. Oops! + +The fix is simple: just set CLOEXEC. This removes our only usage of the +safe_dup() function, so it can be dropped. + +Fixes #2506 +--- + glib/gspawn.c | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index e214a3998..8bbe573f7 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1500,20 +1500,6 @@ safe_closefrom (int lowfd) + #endif + } + +-/* This function is called between fork() and exec() and hence must be +- * async-signal-safe (see signal-safety(7)). */ +-static gint +-safe_dup (gint fd) +-{ +- gint ret; +- +- do +- ret = dup (fd); +- while (ret < 0 && (errno == EINTR || errno == EBUSY)); +- +- return ret; +-} +- + /* This function is called between fork() and exec() and hence must be + * async-signal-safe (see signal-safety(7)). */ + static gint +@@ -1707,7 +1693,7 @@ do_exec (gint child_err_report_fd, + else + { + if (target_fds[i] == child_err_report_fd) +- child_err_report_fd = safe_dup (child_err_report_fd); ++ child_err_report_fd = dupfd_cloexec (child_err_report_fd); + + safe_dup2 (source_fds[i], target_fds[i]); + close_and_invalidate (&source_fds[i]); +-- +2.33.1 + +From b703fa8b760ac9272c5a0ed3e3763b2f71ecf574 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Thu, 14 Oct 2021 10:44:57 -0500 +Subject: [PATCH 04/10] gspawn: fix fd remapping conflation issue + +We currently dup all source fds to avoid possible conflation with the +target fds, but fail to consider that the result of a dup might itself +conflict with one of the target fds. Solve this the easy way by duping +all source_fds to values that are greater than the largest fd in +target_fds. + +Fixes #2503 +--- + glib/gspawn.c | 43 +++++++++++++++++++++++++------------------ + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index 8bbe573f7..2b48b5600 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1258,13 +1258,13 @@ unset_cloexec (int fd) + /* This function is called between fork() and exec() and hence must be + * async-signal-safe (see signal-safety(7)). */ + static int +-dupfd_cloexec (int parent_fd) ++dupfd_cloexec (int old_fd, int new_fd_min) + { + int fd, errsv; + #ifdef F_DUPFD_CLOEXEC + do + { +- fd = fcntl (parent_fd, F_DUPFD_CLOEXEC, 3); ++ fd = fcntl (old_fd, F_DUPFD_CLOEXEC, new_fd_min); + errsv = errno; + } + while (fd == -1 && errsv == EINTR); +@@ -1275,7 +1275,7 @@ dupfd_cloexec (int parent_fd) + int result, flags; + do + { +- fd = fcntl (parent_fd, F_DUPFD, 3); ++ fd = fcntl (old_fd, F_DUPFD, new_fd_min); + errsv = errno; + } + while (fd == -1 && errsv == EINTR); +@@ -1563,6 +1563,7 @@ do_exec (gint child_err_report_fd, + gpointer user_data) + { + gsize i; ++ gint max_target_fd = 0; + + if (working_directory && chdir (working_directory) < 0) + write_err_and_exit (child_err_report_fd, +@@ -1661,39 +1662,45 @@ do_exec (gint child_err_report_fd, + /* + * Work through the @source_fds and @target_fds mapping. + * +- * Based on code derived from ++ * Based on code originally derived from + * gnome-terminal:src/terminal-screen.c:terminal_screen_child_setup(), +- * used under the LGPLv2+ with permission from author. ++ * used under the LGPLv2+ with permission from author. (The code has ++ * since migrated to vte:src/spawn.cc:SpawnContext::exec and is no longer ++ * terribly similar to what we have here.) + */ + +- /* Basic fd assignments (where source == target) we can just unset FD_CLOEXEC +- * +- * If we're doing remapping fd assignments, we need to handle +- * the case where the user has specified e.g.: +- * 5 -> 4, 4 -> 6 +- * +- * We do this by duping the source fds temporarily in a first pass. +- * +- * If any of the @target_fds conflict with @child_err_report_fd, dup the +- * latter so it doesn’t get conflated. +- */ + if (n_fds > 0) + { ++ for (i = 0; i < n_fds; i++) ++ max_target_fd = MAX (max_target_fd, target_fds[i]); ++ ++ /* If we're doing remapping fd assignments, we need to handle ++ * the case where the user has specified e.g. 5 -> 4, 4 -> 6. ++ * We do this by duping all source fds, taking care to ensure the new ++ * fds are larger than any target fd to avoid introducing new conflicts. ++ */ + for (i = 0; i < n_fds; i++) + { + if (source_fds[i] != target_fds[i]) +- source_fds[i] = dupfd_cloexec (source_fds[i]); ++ source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); + } ++ + for (i = 0; i < n_fds; i++) + { ++ /* For basic fd assignments (where source == target), we can just ++ * unset FD_CLOEXEC. ++ */ + if (source_fds[i] == target_fds[i]) + { + unset_cloexec (source_fds[i]); + } + else + { ++ /* If any of the @target_fds conflict with @child_err_report_fd, ++ * dup it so it doesn’t get conflated. ++ */ + if (target_fds[i] == child_err_report_fd) +- child_err_report_fd = dupfd_cloexec (child_err_report_fd); ++ child_err_report_fd = dupfd_cloexec (child_err_report_fd, max_target_fd + 1); + + safe_dup2 (source_fds[i], target_fds[i]); + close_and_invalidate (&source_fds[i]); +-- +2.33.1 + +From ecc3538a942760e8b403c319d359711c8e166778 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Thu, 25 Feb 2021 12:20:39 -0600 +Subject: [PATCH 05/10] gspawn: Implement fd remapping for posix_spawn codepath + +This means that GSubprocess will (sometimes) be able to use the +optimized posix_spawn codepath instead of having to fall back to +fork/exec. +--- + glib/gspawn.c | 65 +++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 58 insertions(+), 7 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index 2b48b5600..9ef78dbe1 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1786,9 +1786,14 @@ do_posix_spawn (const gchar * const *argv, + gint *child_close_fds, + gint stdin_fd, + gint stdout_fd, +- gint stderr_fd) ++ gint stderr_fd, ++ const gint *source_fds, ++ const gint *target_fds, ++ gsize n_fds) + { + pid_t pid; ++ gint *duped_source_fds = NULL; ++ gint max_target_fd = 0; + const gchar * const *argv_pass; + posix_spawnattr_t attr; + posix_spawn_file_actions_t file_actions; +@@ -1797,7 +1802,8 @@ do_posix_spawn (const gchar * const *argv, + GSList *child_close = NULL; + GSList *elem; + sigset_t mask; +- int i, r; ++ size_t i; ++ int r; + + if (*argv[0] == '\0') + { +@@ -1911,6 +1917,43 @@ do_posix_spawn (const gchar * const *argv, + goto out_close_fds; + } + ++ /* If source_fds[i] != target_fds[i], we need to handle the case ++ * where the user has specified, e.g., 5 -> 4, 4 -> 6. We do this ++ * by duping the source fds, taking care to ensure the new fds are ++ * larger than any target fd to avoid introducing new conflicts. ++ * ++ * If source_fds[i] == target_fds[i], then we just need to leak ++ * the fd into the child process, which we *could* do by temporarily ++ * unsetting CLOEXEC and then setting it again after we spawn if ++ * it was originally set. POSIX requires that the addup2 action unset ++ * CLOEXEC if source and target are identical, so you'd think doing it ++ * manually wouldn't be needed, but unfortunately as of 2021 many ++ * libcs still don't do so. Example nonconforming libcs: ++ * Bionic: https://android.googlesource.com/platform/bionic/+/f6e5b582604715729b09db3e36a7aeb8c24b36a4/libc/bionic/spawn.cpp#71 ++ * uclibc-ng: https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/librt/spawn.c?id=7c36bcae09d66bbaa35cbb02253ae0556f42677e#n88 ++ * ++ * Anyway, unsetting CLOEXEC ourselves would open a small race window ++ * where the fd could be inherited into a child process if another ++ * thread spawns something at the same time, because we have not ++ * called fork() and are multithreaded here. This race is avoidable by ++ * using dupfd_cloexec, which we already have to do to handle the ++ * source_fds[i] != target_fds[i] case. So let's always do it! ++ */ ++ ++ for (i = 0; i < n_fds; i++) ++ max_target_fd = MAX (max_target_fd, target_fds[i]); ++ ++ duped_source_fds = g_new (gint, n_fds); ++ for (i = 0; i < n_fds; i++) ++ duped_source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); ++ ++ for (i = 0; i < n_fds; i++) ++ { ++ r = posix_spawn_file_actions_adddup2 (&file_actions, duped_source_fds[i], target_fds[i]); ++ if (r != 0) ++ goto out_close_fds; ++ } ++ + /* Intentionally close the fds in the child as the last file action, + * having been careful not to add the same fd to this list twice. + * +@@ -1940,9 +1983,16 @@ do_posix_spawn (const gchar * const *argv, + *child_pid = pid; + + out_close_fds: +- for (i = 0; i < num_parent_close_fds; i++) ++ for (i = 0; i < (size_t) num_parent_close_fds; i++) + close_and_invalidate (&parent_close_fds [i]); + ++ if (duped_source_fds != NULL) ++ { ++ for (i = 0; i < n_fds; i++) ++ close_and_invalidate (&duped_source_fds[i]); ++ g_free (duped_source_fds); ++ } ++ + posix_spawn_file_actions_destroy (&file_actions); + out_free_spawnattr: + posix_spawnattr_destroy (&attr); +@@ -2030,10 +2080,8 @@ fork_exec (gboolean intermediate_child, + child_close_fds[n_child_close_fds++] = -1; + + #ifdef POSIX_SPAWN_AVAILABLE +- /* FIXME: Handle @source_fds and @target_fds in do_posix_spawn() using the +- * file actions API. */ + if (!intermediate_child && working_directory == NULL && !close_descriptors && +- !search_path_from_envp && child_setup == NULL && n_fds == 0) ++ !search_path_from_envp && child_setup == NULL) + { + g_trace_mark (G_TRACE_CURRENT_TIME, 0, + "GLib", "posix_spawn", +@@ -2050,7 +2098,10 @@ fork_exec (gboolean intermediate_child, + child_close_fds, + stdin_fd, + stdout_fd, +- stderr_fd); ++ stderr_fd, ++ source_fds, ++ target_fds, ++ n_fds); + if (status == 0) + goto success; + +-- +2.33.1 + +From 731d6c32105dc97f2b777ef9a34c6b76d1489c04 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Thu, 25 Feb 2021 12:21:38 -0600 +Subject: [PATCH 06/10] gsubprocess: ensure we test fd remapping on the + posix_spawn() codepath + +We should run test_pass_fd twice, once using gspawn's fork/exec codepath +and once attempting to use its posix_spawn() codepath. There's no +guarantee we'll actually get the posix_spawn() codepath, but it works +for now on Linux. + +For good measure, run it a third time with no flags at all. + +This causes the test to fail if I separately break the fd remapping +implementation. Without this, we fail to test fd remapping on the +posix_spawn() codepath. +--- + gio/tests/gsubprocess.c | 44 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 41 insertions(+), 3 deletions(-) + +diff --git a/gio/tests/gsubprocess.c b/gio/tests/gsubprocess.c +index 7e22678ec..ba49c1c43 100644 +--- a/gio/tests/gsubprocess.c ++++ b/gio/tests/gsubprocess.c +@@ -1697,7 +1697,8 @@ test_child_setup (void) + } + + static void +-test_pass_fd (void) ++do_test_pass_fd (GSubprocessFlags flags, ++ GSpawnChildSetupFunc child_setup) + { + GError *local_error = NULL; + GError **error = &local_error; +@@ -1722,9 +1723,11 @@ test_pass_fd (void) + needdup_fd_str = g_strdup_printf ("%d", needdup_pipefds[1] + 1); + + args = get_test_subprocess_args ("write-to-fds", basic_fd_str, needdup_fd_str, NULL); +- launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE); ++ launcher = g_subprocess_launcher_new (flags); + g_subprocess_launcher_take_fd (launcher, basic_pipefds[1], basic_pipefds[1]); + g_subprocess_launcher_take_fd (launcher, needdup_pipefds[1], needdup_pipefds[1] + 1); ++ if (child_setup != NULL) ++ g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL); + proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error); + g_ptr_array_free (args, TRUE); + g_assert_no_error (local_error); +@@ -1754,6 +1757,39 @@ test_pass_fd (void) + g_object_unref (proc); + } + ++static void ++test_pass_fd (void) ++{ ++ do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, NULL); ++} ++ ++static void ++empty_child_setup (gpointer user_data) ++{ ++} ++ ++static void ++test_pass_fd_empty_child_setup (void) ++{ ++ /* Using a child setup function forces gspawn to use fork/exec ++ * rather than posix_spawn. ++ */ ++ do_test_pass_fd (G_SUBPROCESS_FLAGS_NONE, empty_child_setup); ++} ++ ++static void ++test_pass_fd_inherit_fds (void) ++{ ++ /* Try to test the optimized posix_spawn codepath instead of ++ * fork/exec. Currently this requires using INHERIT_FDS since gspawn's ++ * posix_spawn codepath does not currently handle closing ++ * non-inherited fds. Note that using INHERIT_FDS means our testing of ++ * g_subprocess_launcher_take_fd() is less-comprehensive than when ++ * using G_SUBPROCESS_FLAGS_NONE. ++ */ ++ do_test_pass_fd (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL); ++} ++ + #endif + + static void +@@ -1891,7 +1927,9 @@ main (int argc, char **argv) + g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file); + g_test_add_func ("/gsubprocess/stdout-fd", test_stdout_fd); + g_test_add_func ("/gsubprocess/child-setup", test_child_setup); +- g_test_add_func ("/gsubprocess/pass-fd", test_pass_fd); ++ g_test_add_func ("/gsubprocess/pass-fd/basic", test_pass_fd); ++ g_test_add_func ("/gsubprocess/pass-fd/empty-child-setup", test_pass_fd_empty_child_setup); ++ g_test_add_func ("/gsubprocess/pass-fd/inherit-fds", test_pass_fd_inherit_fds); + #endif + g_test_add_func ("/gsubprocess/launcher-environment", test_launcher_environment); + +-- +2.33.1 + +From 4608940466a04a32d4e6e71dbe872cfecb136118 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Thu, 14 Oct 2021 11:01:33 -0500 +Subject: [PATCH 07/10] gspawn: Check from errors from safe_dup2() and + dupfd_cloexec() + +Although unlikely, these functions can fail, e.g. if we run out of file +descriptors. Check for errors to improve robustness. This is especially +important now that I changed our use of dupfd_cloexec() to avoid +returning fds smaller than the largest fd in target_fds. An application +that attempts to remap to the highest-allowed fd value deserves at least +some sort of attempt at error reporting, not silent failure. +--- + glib/gspawn.c | 40 +++++++++++++++++++++++++++++----------- + 1 file changed, 29 insertions(+), 11 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index 9ef78dbe1..7ef678047 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1572,7 +1572,6 @@ do_exec (gint child_err_report_fd, + /* Redirect pipes as required */ + if (stdin_fd >= 0) + { +- /* dup2 can't actually fail here I don't think */ + if (safe_dup2 (stdin_fd, 0) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -1588,13 +1587,14 @@ do_exec (gint child_err_report_fd, + if (read_null < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +- safe_dup2 (read_null, 0); ++ if (safe_dup2 (read_null, 0) < 0) ++ write_err_and_exit (child_err_report_fd, ++ CHILD_DUP2_FAILED); + close_and_invalidate (&read_null); + } + + if (stdout_fd >= 0) + { +- /* dup2 can't actually fail here I don't think */ + if (safe_dup2 (stdout_fd, 1) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -1609,13 +1609,14 @@ do_exec (gint child_err_report_fd, + if (write_null < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +- safe_dup2 (write_null, 1); ++ if (safe_dup2 (write_null, 1) < 0) ++ write_err_and_exit (child_err_report_fd, ++ CHILD_DUP2_FAILED); + close_and_invalidate (&write_null); + } + + if (stderr_fd >= 0) + { +- /* dup2 can't actually fail here I don't think */ + if (safe_dup2 (stderr_fd, 2) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -1630,7 +1631,9 @@ do_exec (gint child_err_report_fd, + if (write_null < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +- safe_dup2 (write_null, 2); ++ if (safe_dup2 (write_null, 2) < 0) ++ write_err_and_exit (child_err_report_fd, ++ CHILD_DUP2_FAILED); + close_and_invalidate (&write_null); + } + +@@ -1643,7 +1646,8 @@ do_exec (gint child_err_report_fd, + { + if (child_setup == NULL && n_fds == 0) + { +- safe_dup2 (child_err_report_fd, 3); ++ if (safe_dup2 (child_err_report_fd, 3) < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED); + set_cloexec (GINT_TO_POINTER (0), 3); + safe_closefrom (4); + child_err_report_fd = 3; +@@ -1682,7 +1686,11 @@ do_exec (gint child_err_report_fd, + for (i = 0; i < n_fds; i++) + { + if (source_fds[i] != target_fds[i]) +- source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); ++ { ++ source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); ++ if (source_fds[i] < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED); ++ } + } + + for (i = 0; i < n_fds; i++) +@@ -1700,9 +1708,15 @@ do_exec (gint child_err_report_fd, + * dup it so it doesn’t get conflated. + */ + if (target_fds[i] == child_err_report_fd) +- child_err_report_fd = dupfd_cloexec (child_err_report_fd, max_target_fd + 1); ++ { ++ child_err_report_fd = dupfd_cloexec (child_err_report_fd, max_target_fd + 1); ++ if (child_err_report_fd < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED); ++ } ++ ++ if (safe_dup2 (source_fds[i], target_fds[i]) < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED); + +- safe_dup2 (source_fds[i], target_fds[i]); + close_and_invalidate (&source_fds[i]); + } + } +@@ -1945,7 +1959,11 @@ do_posix_spawn (const gchar * const *argv, + + duped_source_fds = g_new (gint, n_fds); + for (i = 0; i < n_fds; i++) +- duped_source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); ++ { ++ duped_source_fds[i] = dupfd_cloexec (source_fds[i], max_target_fd + 1); ++ if (duped_source_fds[i] < 0) ++ goto out_close_fds; ++ } + + for (i = 0; i < n_fds; i++) + { +-- +2.33.1 + +From 0198b6a1c8c215f524d7c6ed2d240fb1b31d9865 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Wed, 20 Oct 2021 16:51:44 -0500 +Subject: [PATCH 08/10] gspawn: add new error message for open() failures + +Reporting these as dup2() failures is bogus. +--- + glib/gspawn.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index 7ef678047..c2fe306dc 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1532,6 +1532,7 @@ enum + { + CHILD_CHDIR_FAILED, + CHILD_EXEC_FAILED, ++ CHILD_OPEN_FAILED, + CHILD_DUP2_FAILED, + CHILD_FORK_FAILED + }; +@@ -1586,7 +1587,7 @@ do_exec (gint child_err_report_fd, + gint read_null = safe_open ("/dev/null", O_RDONLY); + if (read_null < 0) + write_err_and_exit (child_err_report_fd, +- CHILD_DUP2_FAILED); ++ CHILD_OPEN_FAILED); + if (safe_dup2 (read_null, 0) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -1608,7 +1609,7 @@ do_exec (gint child_err_report_fd, + gint write_null = safe_open ("/dev/null", O_WRONLY); + if (write_null < 0) + write_err_and_exit (child_err_report_fd, +- CHILD_DUP2_FAILED); ++ CHILD_OPEN_FAILED); + if (safe_dup2 (write_null, 1) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -1630,7 +1631,7 @@ do_exec (gint child_err_report_fd, + gint write_null = safe_open ("/dev/null", O_WRONLY); + if (write_null < 0) + write_err_and_exit (child_err_report_fd, +- CHILD_DUP2_FAILED); ++ CHILD_OPEN_FAILED); + if (safe_dup2 (write_null, 2) < 0) + write_err_and_exit (child_err_report_fd, + CHILD_DUP2_FAILED); +@@ -2420,7 +2421,15 @@ fork_exec (gboolean intermediate_child, + g_strerror (buf[1])); + + break; +- ++ ++ case CHILD_OPEN_FAILED: ++ g_set_error (error, ++ G_SPAWN_ERROR, ++ G_SPAWN_ERROR_FAILED, ++ _("Failed to open file to remap file descriptor (%s)"), ++ g_strerror (buf[1])); ++ break; ++ + case CHILD_DUP2_FAILED: + g_set_error (error, + G_SPAWN_ERROR, +-- +2.33.1 + +From e4abb5f3db85b2f730e192e6398f26934e41ba21 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Tue, 26 Oct 2021 21:27:15 -0500 +Subject: [PATCH 09/10] Add tests for GSubprocess fd conflation issues + +This tests for #2503. It's fragile, but there is no non-fragile way to +test this. If the test breaks in the future, it will pass without +successfully testing the bug, not fail spuriously, so I think this is +OK. +--- + gio/tests/gsubprocess-testprog.c | 53 +++++++++++- + gio/tests/gsubprocess.c | 144 +++++++++++++++++++++++++++++++ + 2 files changed, 195 insertions(+), 2 deletions(-) + +diff --git a/gio/tests/gsubprocess-testprog.c b/gio/tests/gsubprocess-testprog.c +index c9b06c2a2..58cb1c71d 100644 +--- a/gio/tests/gsubprocess-testprog.c ++++ b/gio/tests/gsubprocess-testprog.c +@@ -5,8 +5,6 @@ + #include + #ifdef G_OS_UNIX + #include +-#include +-#include + #else + #include + #endif +@@ -150,6 +148,55 @@ write_to_fds (int argc, char **argv) + return 0; + } + ++static int ++read_from_fd (int argc, char **argv) ++{ ++ int fd; ++ const char expectedResult[] = "Yay success!"; ++ guint8 buf[sizeof (expectedResult) + 1]; ++ gsize bytes_read; ++ FILE *f; ++ ++ if (argc != 3) ++ { ++ g_print ("Usage: %s read-from-fd FD\n", argv[0]); ++ return 1; ++ } ++ ++ fd = atoi (argv[2]); ++ if (fd == 0) ++ { ++ g_warning ("Argument \"%s\" does not look like a valid nonzero file descriptor", argv[2]); ++ return 1; ++ } ++ ++ f = fdopen (fd, "r"); ++ if (f == NULL) ++ { ++ g_warning ("Failed to open fd %d: %s", fd, g_strerror (errno)); ++ return 1; ++ } ++ ++ bytes_read = fread (buf, 1, sizeof (buf), f); ++ if (bytes_read != sizeof (expectedResult)) ++ { ++ g_warning ("Read %zu bytes, but expected %zu", bytes_read, sizeof (expectedResult)); ++ return 1; ++ } ++ ++ if (memcmp (expectedResult, buf, sizeof (expectedResult)) != 0) ++ { ++ buf[sizeof (expectedResult)] = '\0'; ++ g_warning ("Expected \"%s\" but read \"%s\"", expectedResult, (char *)buf); ++ return 1; ++ } ++ ++ if (fclose (f) == -1) ++ g_assert_not_reached (); ++ ++ return 0; ++} ++ + static int + env_mode (int argc, char **argv) + { +@@ -242,6 +289,8 @@ main (int argc, char **argv) + return sleep_forever_mode (argc, argv); + else if (strcmp (mode, "write-to-fds") == 0) + return write_to_fds (argc, argv); ++ else if (strcmp (mode, "read-from-fd") == 0) ++ return read_from_fd (argc, argv); + else if (strcmp (mode, "env") == 0) + return env_mode (argc, argv); + else if (strcmp (mode, "cwd") == 0) +diff --git a/gio/tests/gsubprocess.c b/gio/tests/gsubprocess.c +index ba49c1c43..a6e24c2e8 100644 +--- a/gio/tests/gsubprocess.c ++++ b/gio/tests/gsubprocess.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1790,6 +1791,146 @@ test_pass_fd_inherit_fds (void) + do_test_pass_fd (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL); + } + ++static void ++do_test_fd_conflation (GSubprocessFlags flags, ++ GSpawnChildSetupFunc child_setup) ++{ ++ char success_message[] = "Yay success!"; ++ GError *error = NULL; ++ GOutputStream *output_stream; ++ GSubprocessLauncher *launcher; ++ GSubprocess *proc; ++ GPtrArray *args; ++ int unused_pipefds[2]; ++ int pipefds[2]; ++ gsize bytes_written; ++ gboolean success; ++ char *fd_str; ++ ++ /* This test must run in a new process because it is extremely sensitive to ++ * order of opened fds. ++ */ ++ if (!g_test_subprocess ()) ++ { ++ g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR); ++ g_test_trap_assert_passed (); ++ return; ++ } ++ ++ g_unix_open_pipe (unused_pipefds, FD_CLOEXEC, &error); ++ g_assert_no_error (error); ++ ++ g_unix_open_pipe (pipefds, FD_CLOEXEC, &error); ++ g_assert_no_error (error); ++ ++ /* The fds should be sequential since we are in a new process. */ ++ g_assert_cmpint (unused_pipefds[0] /* 3 */, ==, unused_pipefds[1] - 1); ++ g_assert_cmpint (unused_pipefds[1] /* 4 */, ==, pipefds[0] - 1); ++ g_assert_cmpint (pipefds[0] /* 5 */, ==, pipefds[1] /* 6 */ - 1); ++ ++ /* Because GSubprocess allows arbitrary remapping of fds, it has to be careful ++ * to avoid fd conflation issues, e.g. it should properly handle 5 -> 4 and ++ * 4 -> 5 at the same time. GIO previously attempted to handle this by naively ++ * dup'ing the source fds, but this was not good enough because it was ++ * possible that the dup'ed result could still conflict with one of the target ++ * fds. For example: ++ * ++ * source_fd 5 -> target_fd 9, source_fd 3 -> target_fd 7 ++ * ++ * dup(5) -> dup returns 8 ++ * dup(3) -> dup returns 9 ++ * ++ * After dup'ing, we wind up with: 8 -> 9, 9 -> 7. That means that after we ++ * dup2(8, 9), we have clobbered fd 9 before we dup2(9, 7). The end result is ++ * we have remapped 5 -> 9 as expected, but then remapped 5 -> 7 instead of ++ * 3 -> 7 as the application intended. ++ * ++ * This issue has been fixed in the simplest way possible, by passing a ++ * minimum fd value when using F_DUPFD_CLOEXEC that is higher than any of the ++ * target fds, to guarantee all source fds are different than all target fds, ++ * eliminating any possibility of conflation. ++ * ++ * Anyway, that is why we have the unused_pipefds here. We need to open fds in ++ * a certain order in order to trick older GSubprocess into conflating the ++ * fds. The primary goal of this test is to ensure this particular conflation ++ * issue is not reintroduced. See glib#2503. ++ * ++ * Be aware this test is necessarily extremely fragile. To reproduce these ++ * bugs, it relies on internals of gspawn and gmain that will likely change ++ * in the future, eventually causing this test to no longer test the the bugs ++ * it was originally designed to test. That is OK! If the test fails, at ++ * least you know *something* is wrong. ++ */ ++ launcher = g_subprocess_launcher_new (flags); ++ g_subprocess_launcher_take_fd (launcher, pipefds[0] /* 5 */, pipefds[1] + 3 /* 9 */); ++ g_subprocess_launcher_take_fd (launcher, unused_pipefds[0] /* 3 */, pipefds[1] + 1 /* 7 */); ++ if (child_setup != NULL) ++ g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL); ++ fd_str = g_strdup_printf ("%d", pipefds[1] + 3); ++ args = get_test_subprocess_args ("read-from-fd", fd_str, NULL); ++ proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, &error); ++ g_assert_no_error (error); ++ g_assert_nonnull (proc); ++ g_ptr_array_free (args, TRUE); ++ g_object_unref (launcher); ++ g_free (fd_str); ++ ++ /* Close the read ends of the pipes. */ ++ close (unused_pipefds[0]); ++ close (pipefds[0]); ++ ++ /* Also close the write end of the unused pipe. */ ++ close (unused_pipefds[1]); ++ ++ /* So now pipefds[0] should be inherited into the subprocess as ++ * pipefds[1] + 2, and unused_pipefds[0] should be inherited as ++ * pipefds[1] + 1. We will write to pipefds[1] and the subprocess will verify ++ * that it reads the expected data. But older broken GIO will accidentally ++ * clobber pipefds[1] + 2 with pipefds[1] + 1! This will cause the subprocess ++ * to hang trying to read from the wrong pipe. ++ */ ++ output_stream = g_unix_output_stream_new (pipefds[1], TRUE); ++ success = g_output_stream_write_all (output_stream, ++ success_message, sizeof (success_message), ++ &bytes_written, ++ NULL, ++ &error); ++ g_assert_no_error (error); ++ g_assert_cmpint (bytes_written, ==, sizeof (success_message)); ++ g_assert_true (success); ++ g_object_unref (output_stream); ++ ++ success = g_subprocess_wait_check (proc, NULL, &error); ++ g_assert_no_error (error); ++ g_object_unref (proc); ++} ++ ++static void ++test_fd_conflation (void) ++{ ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, NULL); ++} ++ ++static void ++test_fd_conflation_empty_child_setup (void) ++{ ++ /* Using a child setup function forces gspawn to use fork/exec ++ * rather than posix_spawn. ++ */ ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup); ++} ++ ++static void ++test_fd_conflation_inherit_fds (void) ++{ ++ /* Try to test the optimized posix_spawn codepath instead of ++ * fork/exec. Currently this requires using INHERIT_FDS since gspawn's ++ * posix_spawn codepath does not currently handle closing ++ * non-inherited fds. ++ */ ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL); ++} ++ + #endif + + static void +@@ -1930,6 +2071,9 @@ main (int argc, char **argv) + g_test_add_func ("/gsubprocess/pass-fd/basic", test_pass_fd); + g_test_add_func ("/gsubprocess/pass-fd/empty-child-setup", test_pass_fd_empty_child_setup); + g_test_add_func ("/gsubprocess/pass-fd/inherit-fds", test_pass_fd_inherit_fds); ++ g_test_add_func ("/gsubprocess/fd-conflation/basic", test_fd_conflation); ++ g_test_add_func ("/gsubprocess/fd-conflation/empty-child-setup", test_fd_conflation_empty_child_setup); ++ g_test_add_func ("/gsubprocess/fd-conflation/inherit-fds", test_fd_conflation_inherit_fds); + #endif + g_test_add_func ("/gsubprocess/launcher-environment", test_launcher_environment); + +-- +2.33.1 + +From 5542612c805857a244561ec160e904dd302ae799 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Wed, 27 Oct 2021 18:30:47 -0500 +Subject: [PATCH 10/10] Add test for child_err_report_fd conflation with target + fds + +This tests for glib#2506. +--- + gio/tests/gsubprocess.c | 42 ++++++++++++++++++++++++++++++++++------- + 1 file changed, 35 insertions(+), 7 deletions(-) + +diff --git a/gio/tests/gsubprocess.c b/gio/tests/gsubprocess.c +index a6e24c2e8..4629cdea7 100644 +--- a/gio/tests/gsubprocess.c ++++ b/gio/tests/gsubprocess.c +@@ -1793,7 +1793,8 @@ test_pass_fd_inherit_fds (void) + + static void + do_test_fd_conflation (GSubprocessFlags flags, +- GSpawnChildSetupFunc child_setup) ++ GSpawnChildSetupFunc child_setup, ++ gboolean test_child_err_report_fd) + { + char success_message[] = "Yay success!"; + GError *error = NULL; +@@ -1803,6 +1804,7 @@ do_test_fd_conflation (GSubprocessFlags flags, + GPtrArray *args; + int unused_pipefds[2]; + int pipefds[2]; ++ int fd_to_pass_to_child; + gsize bytes_written; + gboolean success; + char *fd_str; +@@ -1855,18 +1857,26 @@ do_test_fd_conflation (GSubprocessFlags flags, + * fds. The primary goal of this test is to ensure this particular conflation + * issue is not reintroduced. See glib#2503. + * ++ * This test also has an alternate mode of operation where it instead tests ++ * for conflation with gspawn's child_err_report_fd, glib#2506. ++ * + * Be aware this test is necessarily extremely fragile. To reproduce these + * bugs, it relies on internals of gspawn and gmain that will likely change + * in the future, eventually causing this test to no longer test the the bugs + * it was originally designed to test. That is OK! If the test fails, at + * least you know *something* is wrong. + */ ++ if (test_child_err_report_fd) ++ fd_to_pass_to_child = pipefds[1] + 2 /* 8 */; ++ else ++ fd_to_pass_to_child = pipefds[1] + 3 /* 9 */; ++ + launcher = g_subprocess_launcher_new (flags); +- g_subprocess_launcher_take_fd (launcher, pipefds[0] /* 5 */, pipefds[1] + 3 /* 9 */); ++ g_subprocess_launcher_take_fd (launcher, pipefds[0] /* 5 */, fd_to_pass_to_child); + g_subprocess_launcher_take_fd (launcher, unused_pipefds[0] /* 3 */, pipefds[1] + 1 /* 7 */); + if (child_setup != NULL) + g_subprocess_launcher_set_child_setup (launcher, child_setup, NULL, NULL); +- fd_str = g_strdup_printf ("%d", pipefds[1] + 3); ++ fd_str = g_strdup_printf ("%d", fd_to_pass_to_child); + args = get_test_subprocess_args ("read-from-fd", fd_str, NULL); + proc = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, &error); + g_assert_no_error (error); +@@ -1882,12 +1892,20 @@ do_test_fd_conflation (GSubprocessFlags flags, + /* Also close the write end of the unused pipe. */ + close (unused_pipefds[1]); + +- /* So now pipefds[0] should be inherited into the subprocess as ++ /* If doing our normal test: ++ * ++ * So now pipefds[0] should be inherited into the subprocess as + * pipefds[1] + 2, and unused_pipefds[0] should be inherited as + * pipefds[1] + 1. We will write to pipefds[1] and the subprocess will verify + * that it reads the expected data. But older broken GIO will accidentally + * clobber pipefds[1] + 2 with pipefds[1] + 1! This will cause the subprocess + * to hang trying to read from the wrong pipe. ++ * ++ * If testing conflation with child_err_report_fd: ++ * ++ * We are actually already done. The real test succeeded if we made it this ++ * far without hanging while spawning the child. But let's continue with our ++ * write and read anyway, to ensure things are good. + */ + output_stream = g_unix_output_stream_new (pipefds[1], TRUE); + success = g_output_stream_write_all (output_stream, +@@ -1908,7 +1926,7 @@ do_test_fd_conflation (GSubprocessFlags flags, + static void + test_fd_conflation (void) + { +- do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, NULL); ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, NULL, FALSE); + } + + static void +@@ -1917,7 +1935,7 @@ test_fd_conflation_empty_child_setup (void) + /* Using a child setup function forces gspawn to use fork/exec + * rather than posix_spawn. + */ +- do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup); ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, FALSE); + } + + static void +@@ -1928,7 +1946,16 @@ test_fd_conflation_inherit_fds (void) + * posix_spawn codepath does not currently handle closing + * non-inherited fds. + */ +- do_test_fd_conflation (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL); ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_INHERIT_FDS, NULL, FALSE); ++} ++ ++static void ++test_fd_conflation_child_err_report_fd (void) ++{ ++ /* Using a child setup function forces gspawn to use fork/exec ++ * rather than posix_spawn. ++ */ ++ do_test_fd_conflation (G_SUBPROCESS_FLAGS_NONE, empty_child_setup, TRUE); + } + + #endif +@@ -2074,6 +2101,7 @@ main (int argc, char **argv) + g_test_add_func ("/gsubprocess/fd-conflation/basic", test_fd_conflation); + g_test_add_func ("/gsubprocess/fd-conflation/empty-child-setup", test_fd_conflation_empty_child_setup); + g_test_add_func ("/gsubprocess/fd-conflation/inherit-fds", test_fd_conflation_inherit_fds); ++ g_test_add_func ("/gsubprocess/fd-conflation/child-err-report-fd", test_fd_conflation_child_err_report_fd); + #endif + g_test_add_func ("/gsubprocess/launcher-environment", test_launcher_environment); + +-- +2.33.1 + diff --git a/SOURCES/2435.patch b/SOURCES/2435.patch new file mode 100644 index 0000000..862503b --- /dev/null +++ b/SOURCES/2435.patch @@ -0,0 +1,132 @@ +From a879d08e912a4421786b44af479f94f7b4503f5a Mon Sep 17 00:00:00 2001 +From: Philip Withnall +Date: Mon, 17 Jan 2022 15:27:24 +0000 +Subject: [PATCH] gspawn: Report errors with closing file descriptors between + fork/exec +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a seccomp policy is set up incorrectly so that it returns `EPERM` for +`close_range()` rather than `ENOSYS` due to it not being recognised, no +error would previously be reported from GLib, but some file descriptors +wouldn’t be closed, and that would cause a hung zombie process. The +zombie process would be waiting for one half of a socket to be closed. + +Fix that by correctly propagating errors from `close_range()` back to the +parent process so they can be reported correctly. + +Distributions which aren’t yet carrying the Docker fix to correctly +return `ENOSYS` from unrecognised syscalls may want to temporarily carry +an additional patch to fall back to `safe_fdwalk()` if `close_range()` +fails with `EPERM`. This change will not be accepted upstream as `EPERM` +is not the right error for `close_range()` to be returning. + +Signed-off-by: Philip Withnall + +Fixes: #2580 +--- + glib/gspawn.c | 35 ++++++++++++++++++++++++++--------- + 1 file changed, 26 insertions(+), 9 deletions(-) + +diff --git a/glib/gspawn.c b/glib/gspawn.c +index c2fe306dc..9c2f7ba7b 100644 +--- a/glib/gspawn.c ++++ b/glib/gspawn.c +@@ -1457,8 +1457,10 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data) + } + + /* This function is called between fork() and exec() and hence must be +- * async-signal-safe (see signal-safety(7)). */ +-static void ++ * async-signal-safe (see signal-safety(7)). ++ * ++ * On failure, `-1` will be returned and errno will be set. */ ++static int + safe_closefrom (int lowfd) + { + #if defined(__FreeBSD__) || defined(__OpenBSD__) +@@ -1472,6 +1474,7 @@ safe_closefrom (int lowfd) + * should be safe to use. + */ + (void) closefrom (lowfd); ++ return 0; + #elif defined(__DragonFly__) + /* It is unclear whether closefrom function included in DragonFlyBSD libc_r + * is safe to use because it calls a lot of library functions. It is also +@@ -1479,12 +1482,13 @@ safe_closefrom (int lowfd) + * direct system call here ourselves to avoid possible issues. + */ + (void) syscall (SYS_closefrom, lowfd); ++ return 0; + #elif defined(F_CLOSEM) + /* NetBSD and AIX have a special fcntl command which does the same thing as + * closefrom. NetBSD also includes closefrom function, which seems to be a + * simple wrapper of the fcntl command. + */ +- (void) fcntl (lowfd, F_CLOSEM); ++ return fcntl (lowfd, F_CLOSEM); + #else + + #if defined(HAVE_CLOSE_RANGE) +@@ -1494,9 +1498,11 @@ safe_closefrom (int lowfd) + * + * Handle ENOSYS in case it’s supported in libc but not the kernel; if so, + * fall back to safe_fdwalk(). */ +- if (close_range (lowfd, G_MAXUINT, 0) != 0 && errno == ENOSYS) ++ int ret = close_range (lowfd, G_MAXUINT, 0); ++ if (ret == 0 || errno != ENOSYS) ++ return ret; + #endif /* HAVE_CLOSE_RANGE */ +- (void) safe_fdwalk (close_func, GINT_TO_POINTER (lowfd)); ++ return safe_fdwalk (close_func, GINT_TO_POINTER (lowfd)); + #endif + } + +@@ -1534,7 +1540,8 @@ enum + CHILD_EXEC_FAILED, + CHILD_OPEN_FAILED, + CHILD_DUP2_FAILED, +- CHILD_FORK_FAILED ++ CHILD_FORK_FAILED, ++ CHILD_CLOSE_FAILED, + }; + + /* This function is called between fork() and exec() and hence must be +@@ -1650,12 +1657,14 @@ do_exec (gint child_err_report_fd, + if (safe_dup2 (child_err_report_fd, 3) < 0) + write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED); + set_cloexec (GINT_TO_POINTER (0), 3); +- safe_closefrom (4); ++ if (safe_closefrom (4) < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED); + child_err_report_fd = 3; + } + else + { +- safe_fdwalk (set_cloexec, GINT_TO_POINTER (3)); ++ if (safe_fdwalk (set_cloexec, GINT_TO_POINTER (3)) < 0) ++ write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED); + } + } + else +@@ -2446,7 +2455,15 @@ fork_exec (gboolean intermediate_child, + _("Failed to fork child process (%s)"), + g_strerror (buf[1])); + break; +- ++ ++ case CHILD_CLOSE_FAILED: ++ g_set_error (error, ++ G_SPAWN_ERROR, ++ G_SPAWN_ERROR_FAILED, ++ _("Failed to close file descriptor for child process (%s)"), ++ g_strerror (buf[1])); ++ break; ++ + default: + g_set_error (error, + G_SPAWN_ERROR, +-- +2.34.1 + diff --git a/SPECS/glib2.spec b/SPECS/glib2.spec index 95a728f..42547df 100644 --- a/SPECS/glib2.spec +++ b/SPECS/glib2.spec @@ -1,6 +1,6 @@ Name: glib2 Version: 2.68.4 -Release: 3%{?dist} +Release: 5%{?dist} Summary: A library of handy utility functions License: LGPLv2+ @@ -31,6 +31,11 @@ Patch5: 2244.patch # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2291 Patch6: 2291.patch +# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1968 +Patch7: 1968.patch +# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2435 +Patch8: 2435.patch + BuildRequires: chrpath BuildRequires: gcc BuildRequires: gcc-c++ @@ -247,6 +252,14 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %{_datadir}/installed-tests %changelog +* Fri Jan 21 2022 Michael Catanzaro - 2.68.4-5 +- Add one more upstream patch to gspawn patchset +- Related: #1910092 + +* Fri Jan 21 2022 Michael Catanzaro - 2.68.4-4 +- Add gspawn patchset +- Resolves: #1910092 + * Wed Dec 01 2021 Michael Catanzaro - 2.68.4-3 - Fix GNetworkMonitor after NetworkManager D-Bus API changes - Resolves: #2014624