From f20f0d385ef0729653340477cd578ce721a486b2 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 13 Oct 2020 13:25:21 +0100 Subject: [PATCH] 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 Fixes: #2097 --- glib/gspawn.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/glib/gspawn.c b/glib/gspawn.c index db4f5ad02..aae0be2e9 100644 --- a/glib/gspawn.c +++ b/glib/gspawn.c @@ -1407,6 +1407,20 @@ 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 @@ -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]); }