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
This commit is contained in:
Philip Withnall 2020-10-13 13:25:21 +01:00
parent 7be9767cc4
commit f20f0d385e

View File

@ -1407,6 +1407,20 @@ safe_closefrom (int lowfd)
#endif #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 /* This function is called between fork() and exec() and hence must be
* async-signal-safe (see signal-safety(7)). */ * async-signal-safe (see signal-safety(7)). */
static gint static gint
@ -1574,6 +1588,9 @@ do_exec (gint child_err_report_fd,
* 5 -> 4, 4 -> 6 * 5 -> 4, 4 -> 6
* *
* We do this by duping the source fds temporarily in a first pass. * 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 doesnt get conflated.
*/ */
if (n_fds > 0) if (n_fds > 0)
{ {
@ -1590,6 +1607,9 @@ do_exec (gint child_err_report_fd,
} }
else 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]); safe_dup2 (source_fds[i], target_fds[i]);
(void) close (source_fds[i]); (void) close (source_fds[i]);
} }