aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan/utils/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils/utils.c')
-rw-r--r--src/libstrongswan/utils/utils.c58
1 files changed, 53 insertions, 5 deletions
diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c
index 55eab8e14..c396540ec 100644
--- a/src/libstrongswan/utils/utils.c
+++ b/src/libstrongswan/utils/utils.c
@@ -25,7 +25,22 @@
#endif
#ifndef HAVE_CLOSEFROM
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <sys/syscall.h>
+/* This is from the kernel sources. We limit the length of directory names to
+ * 256 as we only use it to enumerate FDs. */
+struct linux_dirent64 {
+ u_int64_t d_ino;
+ int64_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
+#else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */
# include <dirent.h>
+#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
#endif
#include <library.h>
@@ -120,14 +135,46 @@ void wait_sigint()
*/
void closefrom(int low_fd)
{
+ int max_fd, dir_fd, fd;
+
+ /* try to close only open file descriptors on Linux... */
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+ /* By directly using a syscall we avoid any calls that might be unsafe after
+ * fork() (e.g. malloc()). */
+ char buffer[sizeof(struct linux_dirent64)];
+ struct linux_dirent64 *entry;
+ int offset, len;
+
+ dir_fd = open("/proc/self/fd", O_RDONLY);
+ if (dir_fd != -1)
+ {
+ while ((len = syscall(SYS_getdents64, dir_fd, buffer,
+ sizeof(buffer))) > 0)
+ {
+ for (offset = 0; offset < len; offset += entry->d_reclen)
+ {
+ entry = (struct linux_dirent64*)(buffer + offset);
+ if (!isdigit(entry->d_name[0]))
+ {
+ continue;
+ }
+ fd = atoi(entry->d_name);
+ if (fd != dir_fd && fd >= low_fd)
+ {
+ close(fd);
+ }
+ }
+ }
+ close(dir_fd);
+ return;
+ }
+#else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */
+ /* This is potentially unsafe when called after fork() in multi-threaded
+ * applications. In particular opendir() will require an allocation.
+ * Depends on how the malloc() implementation handles such situations. */
DIR *dir;
struct dirent *entry;
- int max_fd, dir_fd, fd;
- /* try to close only open file descriptors on Linux... This is potentially
- * unsafe when called after fork() in multi-threaded applications. In
- * particular opendir() will require an allocation. So it depends on how
- * the malloc() implementation handles such situations */
dir = opendir(FD_DIR);
if (dir)
{
@@ -147,6 +194,7 @@ void closefrom(int low_fd)
closedir(dir);
return;
}
+#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
/* ...fall back to closing all fds otherwise */
#ifdef WIN32