aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--am/ax_closefrom.m464
-rw-r--r--configure.ac3
-rw-r--r--src/Makefile.am1
-rw-r--r--src/closefrom.c135
-rw-r--r--src/directive.c10
-rw-r--r--src/exec.c3
-rw-r--r--src/wydawca.h3
7 files changed, 212 insertions, 7 deletions
diff --git a/am/ax_closefrom.m4 b/am/ax_closefrom.m4
new file mode 100644
index 0000000..959e767
--- /dev/null
+++ b/am/ax_closefrom.m4
@@ -0,0 +1,64 @@
+# SYNOPSIS
+#
+# AX_CLOSEFROM
+#
+# DESCRIPTION
+#
+# This macro figures out the best way to close all file descriptors
+# greater than or equal to the given one. It evaluates the following
+# variants:
+#
+# 1. closefrom call (FreeBSD)
+# 2. F_CLOSEM fcntl (NetBSD, AIX, IRIX)
+# 3. proc_pidinfo call (Darwin)
+# 4. /proc/self/fd filesystem (Linux)
+#
+# If none of these is applicable, brute force approach will be used.
+#
+# LICENSE
+#
+# This file is part of Wydawca
+# Copyright (C) 2021-2023 Sergey Poznyakoff
+#
+# Wydawca is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Wydawca 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with wydawca. If not, see <http://www.gnu.org/licenses/>.
+
+AC_DEFUN([AX_CLOSEFROM],
+[
+AC_CHECK_FUNCS([sysconf getdtablesize closefrom proc_pidinfo])
+
+AC_CHECK_DECL([F_CLOSEM],
+ AC_DEFINE([HAVE_FCNTL_CLOSEM], [1],
+ [Use F_CLOSEM fcntl for wy_close_fds_from]),
+ [],
+ [#include <limits.h>
+ #include <fcntl.h>
+])
+
+AC_CHECK_HEADERS([libproc.h])
+
+AC_MSG_CHECKING([for closefrom interface])
+if test "$ac_cv_func_closefrom" = yes; then
+ closefrom_api=closefrom
+elif test "$ac_cv_have_decl_F_CLOSEM" = yes; then
+ closefrom_api=F_CLOSEM
+elif test "${ac_cv_header_libproc_h}-$ac_cv_func_proc_pidinfo" = "yes-yes"; then
+ closefrom_api=proc_pidinfo
+elif test -d "/proc/self/fd" ; then
+ AC_DEFINE([HAVE_PROC_SELF_FD], [1], [Define if you have /proc/self/fd])
+ closefrom_api=proc
+else
+ closefrom_api=bruteforce
+fi
+AC_MSG_RESULT([$closefrom_api])
+])
diff --git a/configure.ac b/configure.ac
index 963fc05..b08fcb1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,19 +49,20 @@ AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,
#include <time.h>
])
# Checks for library functions.
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([setegid setregid setresgid setresuid seteuid \
- setreuid vsyslog sysconf getdtablesize])
+ setreuid vsyslog])
# Check for POSIX threads support
AX_PTHREAD([],
[AC_MSG_ERROR([POSIX threads support is required, but not available])])
AX_THREAD_NAMES
+AX_CLOSEFROM
# **********************
# Mailutils
# **********************
AM_GNU_MAILUTILS(3.3, [mailer], [status_mailutils=yes], [status_mailutils=no])
diff --git a/src/Makefile.am b/src/Makefile.am
index 46bdcc7..3d32d59 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,12 +17,13 @@
sbin_PROGRAMS=wydawca
wydawca_SOURCES=\
backup.c\
builtin.c\
builtin.h\
+ closefrom.c\
cmdline.h\
config.c\
dictionary.c\
directive.c\
diskio.c\
exec.c\
diff --git a/src/closefrom.c b/src/closefrom.c
new file mode 100644
index 0000000..a7a144c
--- /dev/null
+++ b/src/closefrom.c
@@ -0,0 +1,135 @@
+/* This file is part of Wydawca
+ Copyright (C) 2021-2023 Sergey Poznyakoff
+
+ Wydawca is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Wydawca 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wydawca. If not, see <http://www.gnu.org/licenses/>. */
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if defined (HAVE_FUNC_CLOSEFROM)
+static int
+close_fds_sys(int minfd)
+{
+ closefrom(minfd);
+ return 0;
+}
+
+#elif defined (HAVE_FCNTL_CLOSEM)
+# include <fcntl.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ fcntl(minfd, F_CLOSEM, 0);
+ return 0;
+}
+
+#elif defined (HAVE_LIBPROC_H) && defined (HAVE_FUNC_PROC_PIDINFO)
+#include <libproc.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ pid_t pid = getpid();
+ struct proc_fdinfo *fdinfo;
+ int i, n, size;
+
+ size = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
+ if (size == 0)
+ return 0;
+ else if (size < 0)
+ return -1;
+
+ fdinfo = calloc(size, sizeof(fdinfo[0]));
+ if (!fdinfo)
+ return -1;
+
+ n = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo, size);
+ if (n <= 0) {
+ free(fdinfo);
+ return -1;
+ }
+
+ n /= PROC_PIDLISTFD_SIZE;
+
+ for (i = minfd; i < n; i++)
+ close(fdinfo_buf[i].proc_fd);
+
+ free(fdinfo);
+ return 0;
+}
+
+#elif defined (HAVE_PROC_SELF_FD)
+# include <sys/types.h>
+# include <dirent.h>
+# include <limits.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir("/proc/self/fd");
+ if (!dir)
+ return -1;
+ while ((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] != '.') {
+ char *p;
+ long n = strtol(ent->d_name, &p, 10);
+ if (n >= minfd && n < INT_MAX && *p == 0)
+ close((int) n);
+ }
+ }
+ closedir(dir);
+ return 0;
+}
+
+#else
+# define close_fds_sys(fd) (-1)
+#endif
+
+#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
+# define __getmaxfd() sysconf(_SC_OPEN_MAX)
+#elif defined (HAVE_GETDTABLESIZE)
+# define __getmaxfd() getdtablesize()
+#elif defined OPEN_MAX
+# define __getmaxfd() OPEN_MAX
+#else
+# define __getmaxfd() 256
+#endif
+
+static int
+close_fds_bruteforce(int minfd)
+{
+ int i, n = __getmaxfd();
+
+ for (i = minfd; i < n; i++)
+ close(i);
+
+ return 0;
+}
+
+void
+wy_close_fds_from(int minfd)
+{
+ if (close_fds_sys(minfd))
+ close_fds_bruteforce(minfd);
+}
+
+void
+wy_close_fds_above(int fd)
+{
+ wy_close_fds_from(fd + 1);
+}
diff --git a/src/directive.c b/src/directive.c
index e69888b..0df6611 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -555,16 +555,18 @@ run_check_script(const char *script, struct wy_triplet *trp,
signal(SIGALRM, SIG_DFL);
efd = stderr_redirector(script_file);
if (efd == -1)
_exit(127);
- for (i = getdtablesize(); i >= 0; i--) {
- if (i != p[1] && i != efd)
- close(i);
- }
+ /* Select the biggest fd. */
+ i = p[1];
+ if (efd > i)
+ i = efd;
+ /* Close all fds above it. */
+ wy_close_fds_above(i);
if (p[1] != 1 && dup2(p[1], 1) != 1) {
wy_log(LOG_CRIT,
"cannot duplicate script's stdout: %s",
strerror(errno));
_exit(127);
diff --git a/src/exec.c b/src/exec.c
index 6c342c8..a56963f 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -49,14 +49,13 @@ start_prog(int argc, const char **argv, pid_t * ppid)
_exit(EX_UNAVAILABLE);
}
close(p[0]);
/* Close unneded descripitors */
- for (i = getdtablesize(); i > 2; i--)
- close(i);
+ wy_close_fds_above(2);
execvp(argv[0], (char **) argv);
wy_log(LOG_CRIT, _("cannot run %s: %s"), argv[0], strerror(errno));
exit(EX_UNAVAILABLE);
case -1:
diff --git a/src/wydawca.h b/src/wydawca.h
index 21e1d9e..66c820d 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -557,6 +557,9 @@ void *wy_thr_cleaner(void *ptr);
void wy_triplet_wait(void);
void *wy_thr_tcpmux(void *ptr);
void *wy_thr_connection_watcher(void *ptr);
char *wy_tempdir(void);
int wy_rmdir_r(const char *name);
+
+void wy_close_fds_from(int minfd);
+void wy_close_fds_above(int minfd);

Return to:

Send suggestions and report system problems to the System administrator.