utils: Directly use syscall() to close open FDs in closefrom()
This avoids any allocations, since calling malloc() after fork() is potentially unsafe. Fixes #990.
This commit is contained in:
parent
b410d7f8ff
commit
f25f4192c7
|
@ -591,7 +591,7 @@ AC_CHECK_FUNC([syslog], [
|
||||||
])
|
])
|
||||||
AM_CONDITIONAL(USE_SYSLOG, [test "x$syslog" = xtrue])
|
AM_CONDITIONAL(USE_SYSLOG, [test "x$syslog" = xtrue])
|
||||||
|
|
||||||
AC_CHECK_HEADERS(sys/sockio.h glob.h net/if_tun.h)
|
AC_CHECK_HEADERS(sys/sockio.h sys/syscall.h glob.h net/if_tun.h)
|
||||||
AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h)
|
AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h)
|
||||||
AC_CHECK_HEADERS([netinet/ip6.h linux/fib_rules.h], [], [],
|
AC_CHECK_HEADERS([netinet/ip6.h linux/fib_rules.h], [], [],
|
||||||
[
|
[
|
||||||
|
|
|
@ -25,7 +25,22 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_CLOSEFROM
|
#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>
|
# include <dirent.h>
|
||||||
|
#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
|
@ -120,14 +135,46 @@ void wait_sigint()
|
||||||
*/
|
*/
|
||||||
void closefrom(int low_fd)
|
void closefrom(int low_fd)
|
||||||
{
|
{
|
||||||
DIR *dir;
|
|
||||||
struct dirent *entry;
|
|
||||||
int max_fd, dir_fd, fd;
|
int max_fd, dir_fd, fd;
|
||||||
|
|
||||||
/* try to close only open file descriptors on Linux... This is potentially
|
/* try to close only open file descriptors on Linux... */
|
||||||
* unsafe when called after fork() in multi-threaded applications. In
|
#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
|
||||||
* particular opendir() will require an allocation. So it depends on how
|
/* By directly using a syscall we avoid any calls that might be unsafe after
|
||||||
* the malloc() implementation handles such situations */
|
* 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;
|
||||||
|
|
||||||
dir = opendir(FD_DIR);
|
dir = opendir(FD_DIR);
|
||||||
if (dir)
|
if (dir)
|
||||||
{
|
{
|
||||||
|
@ -147,6 +194,7 @@ void closefrom(int low_fd)
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
|
||||||
|
|
||||||
/* ...fall back to closing all fds otherwise */
|
/* ...fall back to closing all fds otherwise */
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
Loading…
Reference in New Issue