diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build index 06685702e..114de49da 100644 --- a/docs/reference/glib/meson.build +++ b/docs/reference/glib/meson.build @@ -38,6 +38,7 @@ if get_option('gtk_doc') 'gutilsprivate.h', 'gvalgrind.h', 'dirent.h', + 'glib-unixprivate.h', 'glib-visibility.h', 'gmodule-visibility.h', ] diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index 0983ac49c..b73ff0d6e 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -53,6 +53,12 @@ #include #endif +#ifdef G_OS_WIN32 +#define FO_CLOEXEC "" +#else +#define FO_CLOEXEC "e" +#endif + #include "glibintl.h" /** @@ -711,7 +717,7 @@ g_dbus_address_connect (const gchar *address_entry, int errsv; /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */ - f = fopen (nonce_file, "rb"); + f = fopen (nonce_file, "rb" FO_CLOEXEC); errsv = errno; if (f == NULL) { diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c index fb6488a2a..c8aa08977 100644 --- a/gio/gdbusauthmechanismsha1.c +++ b/gio/gdbusauthmechanismsha1.c @@ -37,6 +37,10 @@ #include "gwin32sid.h" #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "gdbusauthmechanismsha1.h" #include "gcredentials.h" #include "gdbuserror.h" @@ -519,7 +523,7 @@ create_lock_exclusive (const gchar *lock_path, int errsv; gint ret; - ret = g_open (lock_path, O_CREAT | O_EXCL, 0600); + ret = g_open (lock_path, O_CREAT | O_EXCL | O_CLOEXEC, 0600); errsv = errno; if (ret < 0) { diff --git a/gio/glocalfile.c b/gio/glocalfile.c index a6fea94a2..2b43ff47c 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -51,6 +51,10 @@ #define O_BINARY 0 #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "gfileattribute.h" #include "glocalfile.h" #include "glocalfileinfo.h" @@ -1352,7 +1356,7 @@ g_local_file_read (GFile *file, int fd, ret; GLocalFileStat buf; - fd = g_open (local->filename, O_RDONLY|O_BINARY, 0); + fd = g_open (local->filename, O_RDONLY | O_BINARY | O_CLOEXEC, 0); if (fd == -1) { int errsv = errno; @@ -2227,7 +2231,7 @@ g_local_file_trash (GFile *file, infofile = g_build_filename (infodir, infoname, NULL); g_free (infoname); - fd = g_open (infofile, O_CREAT | O_EXCL, 0666); + fd = g_open (infofile, O_CREAT | O_EXCL | O_CLOEXEC, 0666); errsv = errno; } while (fd == -1 && errsv == EEXIST); @@ -2881,9 +2885,9 @@ g_local_file_measure_size_of_file (gint parent_fd, #ifdef AT_FDCWD #ifdef HAVE_OPEN_O_DIRECTORY - dir_fd = openat (parent_fd, name->data, O_RDONLY|O_DIRECTORY); + dir_fd = openat (parent_fd, name->data, O_RDONLY | O_DIRECTORY | O_CLOEXEC); #else - dir_fd = openat (parent_fd, name->data, O_RDONLY); + dir_fd = openat (parent_fd, name->data, O_RDONLY | O_CLOEXEC); #endif errsv = errno; if (dir_fd < 0) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 420e9d4b2..dab34c67b 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -92,6 +92,10 @@ #endif #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "glocalfileinfo.h" #include "gioerror.h" #include "gthemedicon.h" @@ -1391,11 +1395,11 @@ get_content_type (const char *basename, sniff_length = 4096; #ifdef O_NOATIME - fd = g_open (path, O_RDONLY | O_NOATIME, 0); + fd = g_open (path, O_RDONLY | O_NOATIME | O_CLOEXEC, 0); errsv = errno; if (fd < 0 && errsv == EPERM) #endif - fd = g_open (path, O_RDONLY, 0); + fd = g_open (path, O_RDONLY | O_CLOEXEC, 0); if (fd != -1) { diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c index 3ce987fba..74a642da8 100644 --- a/gio/glocalfileoutputstream.c +++ b/gio/glocalfileoutputstream.c @@ -700,7 +700,7 @@ _g_local_file_output_stream_open (const char *filename, if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; - open_flags = O_BINARY; + open_flags = O_BINARY | O_CLOEXEC; if (readable) open_flags |= O_RDWR; else @@ -737,7 +737,7 @@ _g_local_file_output_stream_create (const char *filename, mode = mode_from_flags_or_info (flags, reference_info); - open_flags = O_CREAT | O_EXCL | O_BINARY; + open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC; if (readable) open_flags |= O_RDWR; else @@ -762,7 +762,7 @@ _g_local_file_output_stream_append (const char *filename, else mode = 0666; - return output_stream_open (filename, O_CREAT | O_APPEND | O_WRONLY | O_BINARY, mode, + return output_stream_open (filename, O_CREAT | O_APPEND | O_WRONLY | O_BINARY | O_CLOEXEC, mode, cancellable, error); } @@ -865,9 +865,9 @@ handle_overwrite_open (const char *filename, /* We only need read access to the original file if we are creating a backup. * We also add O_CREAT to avoid a race if the file was just removed */ if (create_backup || readable) - open_flags = O_RDWR | O_CREAT | O_BINARY; + open_flags = O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC; else - open_flags = O_WRONLY | O_CREAT | O_BINARY; + open_flags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC; /* Some systems have O_NOFOLLOW, which lets us avoid some races * when finding out if the file we opened was a symlink */ @@ -1113,7 +1113,7 @@ handle_overwrite_open (const char *filename, } bfd = g_open (backup_filename, - O_WRONLY | O_CREAT | O_EXCL | O_BINARY, + O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, _g_stat_mode (&original_stat) & 0777); if (bfd == -1) @@ -1208,9 +1208,9 @@ handle_overwrite_open (const char *filename, } if (readable) - open_flags = O_RDWR | O_CREAT | O_BINARY; + open_flags = O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC; else - open_flags = O_WRONLY | O_CREAT | O_BINARY; + open_flags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC; fd = g_open (filename, open_flags, mode); if (fd == -1) { diff --git a/gio/gsocket.c b/gio/gsocket.c index 0ccc53f98..2dc005b63 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -2858,6 +2858,9 @@ g_socket_accept (GSocket *socket, GCancellable *cancellable, GError **error) { +#ifdef HAVE_ACCEPT4 + gboolean try_accept4 = TRUE; +#endif GSocket *new_socket; gint ret; @@ -2871,7 +2874,28 @@ g_socket_accept (GSocket *socket, while (TRUE) { - if ((ret = accept (socket->priv->fd, NULL, 0)) < 0) + gboolean try_accept = TRUE; + +#ifdef HAVE_ACCEPT4 + if (try_accept4) + { + ret = accept4 (socket->priv->fd, NULL, 0, SOCK_CLOEXEC); + if (ret < 0 && errno == ENOSYS) + { + try_accept4 = FALSE; + } + else + { + try_accept = FALSE; + } + } + + g_assert (try_accept4 || try_accept); +#endif + if (try_accept) + ret = accept (socket->priv->fd, NULL, 0); + + if (ret < 0) { int errsv = get_socket_errno (); diff --git a/gio/gtestdbus.c b/gio/gtestdbus.c index 6aedb3eae..34cead176 100644 --- a/gio/gtestdbus.c +++ b/gio/gtestdbus.c @@ -50,6 +50,7 @@ #ifdef G_OS_UNIX #include "glib-unix.h" +#include "glib-unixprivate.h" #endif /* -------------------------------------------------------------------------- */ @@ -248,7 +249,7 @@ watcher_init (void) gint pipe_fds[2]; /* fork a child to clean up when we are killed */ - if (pipe (pipe_fds) != 0) + if (!g_unix_open_pipe_internal (pipe_fds, TRUE)) { errsv = errno; g_warning ("pipe() failed: %s", g_strerror (errsv)); diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c index 9a02de3b5..4a2f0a248 100644 --- a/gio/gunixmounts.c +++ b/gio/gunixmounts.c @@ -3166,7 +3166,7 @@ _resolve_dev_root (void) /* see if device with similar major:minor as /dev/root is mention * in /etc/mtab (it usually is) */ - f = fopen ("/etc/mtab", "r"); + f = fopen ("/etc/mtab", "re"); if (f != NULL) { struct mntent *entp; diff --git a/gio/kqueue/gkqueuefilemonitor.c b/gio/kqueue/gkqueuefilemonitor.c index f69f98e1c..b664753a1 100644 --- a/gio/kqueue/gkqueuefilemonitor.c +++ b/gio/kqueue/gkqueuefilemonitor.c @@ -32,6 +32,10 @@ #include #include +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include #include #include @@ -583,7 +587,7 @@ _kqsub_start_watching (kqueue_sub *sub) struct stat st; struct kevent ev; - sub->fd = open (sub->filename, O_KQFLAG); + sub->fd = open (sub->filename, O_KQFLAG | O_CLOEXEC); if (sub->fd == -1) return FALSE; diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c index 9c52a7d29..b708b1636 100644 --- a/glib/gbacktrace.c +++ b/glib/gbacktrace.c @@ -45,6 +45,7 @@ #include #ifdef G_OS_UNIX +#include "glib-unixprivate.h" #include #include #include @@ -397,7 +398,8 @@ stack_trace (const char * const *args) stack_trace_done = FALSE; signal (SIGCHLD, stack_trace_sigchld); - if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1)) + if (!g_unix_open_pipe_internal (in_fd, TRUE) || + !g_unix_open_pipe_internal (out_fd, TRUE)) { perror ("unable to open pipe"); _exit (0); diff --git a/glib/gcharset.c b/glib/gcharset.c index 31d46b659..82cd0a7b8 100644 --- a/glib/gcharset.c +++ b/glib/gcharset.c @@ -446,7 +446,7 @@ read_aliases (const gchar *file, FILE *fp; char buf[256]; - fp = fopen (file,"r"); + fp = fopen (file, "re"); if (!fp) return; while (fgets (buf, 256, fp)) diff --git a/glib/gfileutils.c b/glib/gfileutils.c index 826c5e242..ef3fc90f2 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -329,7 +329,7 @@ g_mkdir_with_parents (const gchar *pathname, * } * * // DO THIS INSTEAD - * fd = g_open (filename, O_WRONLY | O_NOFOLLOW); + * fd = g_open (filename, O_WRONLY | O_NOFOLLOW | O_CLOEXEC); * if (fd == -1) * { * // check error @@ -908,7 +908,7 @@ get_contents_posix (const gchar *filename, gint fd; /* O_BINARY useful on Cygwin */ - fd = open (filename, O_RDONLY|O_BINARY); + fd = open (filename, O_RDONLY | O_BINARY | O_CLOEXEC); if (fd < 0) { @@ -1083,7 +1083,7 @@ rename_file (const char *old_name, if (do_fsync) { gchar *dir = g_path_get_dirname (new_name); - int dir_fd = g_open (dir, O_RDONLY, 0); + int dir_fd = g_open (dir, O_RDONLY | O_CLOEXEC, 0); if (dir_fd >= 0) { diff --git a/glib/giounix.c b/glib/giounix.c index 067cecf9a..9d9492b28 100644 --- a/glib/giounix.c +++ b/glib/giounix.c @@ -44,6 +44,10 @@ #include #include +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "giochannel.h" #include "gerror.h" @@ -527,7 +531,7 @@ g_io_channel_new_file (const gchar *filename, create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - fid = g_open (filename, flags, create_mode); + fid = g_open (filename, flags | O_CLOEXEC, create_mode); if (fid == -1) { int err = errno; diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c index fb65d55c5..9a4821bc5 100644 --- a/glib/gkeyfile.c +++ b/glib/gkeyfile.c @@ -53,6 +53,10 @@ #endif /* G_OS_WIN23 */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "gconvert.h" #include "gdataset.h" #include "gerror.h" @@ -761,7 +765,7 @@ find_file_in_data_dirs (const gchar *file, path = g_build_filename (data_dir, sub_dir, candidate_file, NULL); - fd = g_open (path, O_RDONLY, 0); + fd = g_open (path, O_RDONLY | O_CLOEXEC, 0); if (fd == -1) { @@ -917,7 +921,7 @@ g_key_file_load_from_file (GKeyFile *key_file, g_return_val_if_fail (key_file != NULL, FALSE); g_return_val_if_fail (file != NULL, FALSE); - fd = g_open (file, O_RDONLY, 0); + fd = g_open (file, O_RDONLY | O_CLOEXEC, 0); errsv = errno; if (fd == -1) diff --git a/glib/glib-unix.c b/glib/glib-unix.c index bc152d766..1c9f12599 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -23,12 +23,8 @@ #include "config.h" -/* To make bionic export pipe2() */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif - #include "glib-unix.h" +#include "glib-unixprivate.h" #include "gmain-internal.h" #include @@ -94,48 +90,13 @@ g_unix_open_pipe (int *fds, int flags, GError **error) { - int ecode; - /* We only support FD_CLOEXEC */ g_return_val_if_fail ((flags & (FD_CLOEXEC)) == flags, FALSE); -#ifdef HAVE_PIPE2 - { - int pipe2_flags = 0; - if (flags & FD_CLOEXEC) - pipe2_flags |= O_CLOEXEC; - /* Atomic */ - ecode = pipe2 (fds, pipe2_flags); - if (ecode == -1 && errno != ENOSYS) - return g_unix_set_error_from_errno (error, errno); - else if (ecode == 0) - return TRUE; - /* Fall through on -ENOSYS, we must be running on an old kernel */ - } -#endif - ecode = pipe (fds); - if (ecode == -1) + if (!g_unix_open_pipe_internal (fds, + (flags & FD_CLOEXEC) != 0)) return g_unix_set_error_from_errno (error, errno); - if (flags == 0) - return TRUE; - - ecode = fcntl (fds[0], F_SETFD, flags); - if (ecode == -1) - { - int saved_errno = errno; - close (fds[0]); - close (fds[1]); - return g_unix_set_error_from_errno (error, saved_errno); - } - ecode = fcntl (fds[1], F_SETFD, flags); - if (ecode == -1) - { - int saved_errno = errno; - close (fds[0]); - close (fds[1]); - return g_unix_set_error_from_errno (error, saved_errno); - } return TRUE; } diff --git a/glib/glib-unixprivate.h b/glib/glib-unixprivate.h new file mode 100644 index 000000000..d4c64bd1e --- /dev/null +++ b/glib/glib-unixprivate.h @@ -0,0 +1,87 @@ +/* glib-unixprivate.h - Unix specific integration private functions + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#ifndef __G_UNIXPRIVATE_H__ +#define __G_UNIXPRIVATE_H__ + +#include "config.h" + +#ifndef G_OS_UNIX +#error "This header may only be used on UNIX" +#endif + +/* To make bionic export pipe2() */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include "gmacros.h" +#include "gtypes.h" + +#include +#include +#include + +G_BEGIN_DECLS + +static inline gboolean +g_unix_open_pipe_internal (int *fds, + gboolean close_on_exec) + { +#ifdef HAVE_PIPE2 + do + { + int ecode; + + /* Atomic */ + ecode = pipe2 (fds, close_on_exec ? O_CLOEXEC : 0); + if (ecode == -1 && errno != ENOSYS) + return FALSE; + else if (ecode == 0) + return TRUE; + /* Fall through on -ENOSYS, we must be running on an old kernel */ + } + while (FALSE); +#endif + + if (pipe (fds) == -1) + return FALSE; + + if (!close_on_exec) + return TRUE; + + if (fcntl (fds[0], F_SETFD, FD_CLOEXEC) == -1 || + fcntl (fds[1], F_SETFD, FD_CLOEXEC) == -1) + { + int saved_errno = errno; + + close (fds[0]); + close (fds[1]); + fds[0] = -1; + fds[1] = -1; + + errno = saved_errno; + return FALSE; + } + + return TRUE; +} + +G_END_DECLS + +#endif /* __G_UNIXPRIVATE_H__ */ diff --git a/glib/gmappedfile.c b/glib/gmappedfile.c index 16b38b358..4d7a89eb2 100644 --- a/glib/gmappedfile.c +++ b/glib/gmappedfile.c @@ -50,6 +50,10 @@ #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "gconvert.h" #include "gerror.h" #include "gfileutils.h" @@ -252,7 +256,7 @@ g_mapped_file_new (const gchar *filename, g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (!error || *error == NULL, NULL); - fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0); + fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY | O_CLOEXEC, 0); if (fd == -1) { int save_errno = errno; diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 1a63bfe42..fcf1caff3 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -3858,8 +3858,9 @@ wait_for_child (GPid pid, * Since: 2.16 * * Deprecated: This function is implemented only on Unix platforms, - * and is not always reliable due to problems inherent in - * fork-without-exec. Use g_test_trap_subprocess() instead. + * is not always reliable due to problems inherent in fork-without-exec + * and doesn't set close-on-exec flag on its file descriptors. + * Use g_test_trap_subprocess() instead. */ G_GNUC_BEGIN_IGNORE_DEPRECATIONS gboolean diff --git a/glib/meson.build b/glib/meson.build index 75b3b4018..da76fc005 100644 --- a/glib/meson.build +++ b/glib/meson.build @@ -365,7 +365,7 @@ if host_system == 'windows' glib_sources += files('dirent/wdirent.c') endif else - glib_sources += files('glib-unix.c', 'gspawn.c', 'giounix.c') + glib_sources += files('glib-unix.c', 'glib-unixprivate.h', 'gspawn.c', 'giounix.c') platform_deps = [] endif diff --git a/gmodule/gmodule.c b/gmodule/gmodule.c index 00a2c055f..aafaaf0ad 100644 --- a/gmodule/gmodule.c +++ b/gmodule/gmodule.c @@ -45,6 +45,10 @@ #include /* For open() and close() prototypes. */ #endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + #include "gmoduleconf.h" #include "gstdio.h" @@ -388,7 +392,7 @@ parse_libtool_archive (const gchar* libtool_name) GTokenType token; GScanner *scanner; - int fd = g_open (libtool_name, O_RDONLY, 0); + int fd = g_open (libtool_name, O_RDONLY | O_CLOEXEC, 0); if (fd < 0) { gchar *display_libtool_name = g_filename_display_name (libtool_name); diff --git a/meson.build b/meson.build index 4630025ca..f9baa409b 100644 --- a/meson.build +++ b/meson.build @@ -606,6 +606,7 @@ if host_system == 'windows' endif functions = [ + 'accept4', 'close_range', 'endmntent', 'endservent',