summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <pwithnall@endlessos.org>2020-10-13 13:25:21 +0100
committerPhilip Withnall <pwithnall@endlessos.org>2021-02-16 13:44:00 +0000
commitf20f0d385ef0729653340477cd578ce721a486b2 (patch)
treeb9a5038a68f5b93157e4f44d10c63c576c7cf1b2
parent7be9767cc46366f0ea6601337d010226d283ed38 (diff)
downloadglib-f20f0d385ef0729653340477cd578ce721a486b2.tar.gz
gspawn: Avoid custom FDs conflicting with the child_err_report_fd
It was previously possible to specify the FD number which `child_err_report_fd` was assigned, as a target FD in the FD mapping set up using `g_subprocess_launcher_take_fd()`. Signed-off-by: Philip Withnall <pwithnall@endlessos.org> Fixes: #2097
-rw-r--r--glib/gspawn.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/glib/gspawn.c b/glib/gspawn.c
index db4f5ad02..aae0be2e9 100644
--- a/glib/gspawn.c
+++ b/glib/gspawn.c
@@ -1410,6 +1410,20 @@ safe_closefrom (int lowfd)
/* 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
safe_dup2 (gint fd1, gint fd2)
{
gint ret;
@@ -1574,6 +1588,9 @@ do_exec (gint child_err_report_fd,
* 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)
{
@@ -1590,6 +1607,9 @@ 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);
+
safe_dup2 (source_fds[i], target_fds[i]);
(void) close (source_fds[i]);
}