From ee9c928e06eeb89dc027651ceecb84e00333dcb4 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 28 Oct 2022 10:16:56 -0400 Subject: [PATCH] glib-unix: Ensure g_unix_open_pipe never leaves standard io fd range exposed It's now possible that g_unix_open_pipe will reject an fd because it's STDIN, STDOUT, or STDERR. Having those fds left open to be used by the next thing is causing buggy apps to fail, since they relied on g_unix_open_pipe using the fds. This commit puts a /dev/null placeholder on an standard fds that g_unix_open_pipe rejects. Closes: https://gitlab.gnome.org/GNOME/glib/-/issues/2795 --- glib/glib-unix.c | 78 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/glib/glib-unix.c b/glib/glib-unix.c index 905ecee04..ecd0969ae 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -30,6 +30,7 @@ #include "glib-unix.h" #include "gmain-internal.h" +#include "gstdio.h" #include #include @@ -70,6 +71,59 @@ g_unix_set_error_from_errno (GError **error, return FALSE; } +static gboolean +move_pipe_fds_away_from_standard_io_range (int *fds, + GError **error) +{ + int i; + gboolean result = TRUE; + + /* For backward compatibilty with buggy apps, still make sure + * the standard fd slots get used up with something harmless + */ + for (i = 0; i < 2; i++) + { + int open_flags = 0; + int ret; + g_autofd int dev_null = -1; + + switch (fds[i]) + { + case STDIN_FILENO: + open_flags = O_RDONLY; + break; + case STDOUT_FILENO: + case STDERR_FILENO: + open_flags = O_WRONLY; + break; + default: + continue; + } + + dev_null = g_open ("/dev/null", open_flags, 0); + + if (dev_null < 0) + { + g_unix_set_error_from_errno (error, errno); + result = FALSE; + break; + } + + do + ret = dup2 (g_steal_fd (&dev_null), fds[i]); + while (ret < 0 && (errno == EINTR || errno == EBUSY)); + + if (ret < 0) + { + g_unix_set_error_from_errno (error, errno); + result = FALSE; + break; + } + } + + return result; +} + /** * g_unix_open_pipe: * @fds: (array fixed-size=2): Array of two integers @@ -111,10 +165,14 @@ g_unix_open_pipe (int *fds, /* Don't reassign pipes to stdin, stdout, stderr if closed meanwhile */ else if (fds[0] < 3 || fds[1] < 3) { - int old_fds[2] = { fds[0], fds[1] }; - gboolean result = g_unix_open_pipe (fds, flags, error); - close (old_fds[0]); - close (old_fds[1]); + gboolean result; + + result = move_pipe_fds_away_from_standard_io_range (fds, error); + + if (!result) + return FALSE; + + result = g_unix_open_pipe (fds, flags, error); return result; } @@ -129,10 +187,14 @@ g_unix_open_pipe (int *fds, /* Don't reassign pipes to stdin, stdout, stderr if closed meanwhile */ else if (fds[0] < 3 || fds[1] < 3) { - int old_fds[2] = { fds[0], fds[1] }; - gboolean result = g_unix_open_pipe (fds, flags, error); - close (old_fds[0]); - close (old_fds[1]); + gboolean result; + + result = move_pipe_fds_away_from_standard_io_range (fds, error); + + if (!result) + return FALSE; + + result = g_unix_open_pipe (fds, flags, error); return result; }