closefrom: Import some changes from sudo

Take most of the changes done in sudo, but preserve the existing local
changes and refactoring.

In addition, refactor pstat implementation into closefrom_pstat(), so
that the code is easier to read, and requires no conditional
declarations.
This commit is contained in:
Guillem Jover 2021-02-08 02:52:50 +01:00
parent 4676026286
commit a1f79978e8

View File

@ -1,6 +1,8 @@
/* /*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2014 * SPDX-License-Identifier: ISC
* Todd C. Miller <Todd.Miller@courtesan.com> *
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -17,19 +19,11 @@
#include <config.h> #include <config.h>
#include <sys/types.h> #include <errno.h>
#include <unistd.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_PSTAT_GETPROC #ifdef HAVE_PSTAT_GETPROC
# include <sys/param.h> # include <sys/param.h>
# include <sys/pstat.h> # include <sys/pstat.h>
@ -56,10 +50,6 @@
# define OPEN_MAX 256 # define OPEN_MAX 256
#endif #endif
#if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD)
# define closefrom closefrom_fallback
#endif
static inline void static inline void
closefrom_close(int fd) closefrom_close(int fd)
{ {
@ -81,46 +71,46 @@ closefrom_fallback(int lowfd)
long fd, maxfd; long fd, maxfd;
/* /*
* Fall back on sysconf() or getdtablesize(). We avoid checking * Fall back on sysconf(_SC_OPEN_MAX) or getdtablesize(). This is
* resource limits since it is possible to open a file descriptor * equivalent to checking the RLIMIT_NOFILE soft limit. It is
* and then drop the rlimit such that it is below the open fd. * possible for there to be open file descriptors past this limit
* but there is not much we can do about that since the hard limit
* may be RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems).
*/ */
#ifdef HAVE_SYSCONF #ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX); maxfd = sysconf(_SC_OPEN_MAX);
#else #else
maxfd = getdtablesize(); maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */ #endif /* HAVE_SYSCONF */
if (maxfd < 0) if (maxfd < OPEN_MAX)
maxfd = OPEN_MAX; maxfd = OPEN_MAX;
/* Make sure we did not get RLIM_INFINITY as the upper limit. */
if (maxfd > INT_MAX)
maxfd = INT_MAX;
for (fd = lowfd; fd < maxfd; fd++) for (fd = lowfd; fd < maxfd; fd++)
closefrom_close(fd); closefrom_close(fd);
} }
/* #if defined(HAVE_PSTAT_GETPROC)
* Close all file descriptors greater than or equal to lowfd. static int
* We try the fast way first, falling back on the slow method. closefrom_pstat(int lowfd)
*/
#if defined(HAVE_FCNTL_CLOSEM)
void
closefrom(int lowfd)
{ {
if (fcntl(lowfd, F_CLOSEM, 0) == -1) struct pst_status pst;
closefrom_fallback(lowfd);
}
#elif defined(HAVE_PSTAT_GETPROC)
void
closefrom(int lowfd)
{
struct pst_status pstat;
int fd; int fd;
if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) { /*
for (fd = lowfd; fd <= pstat.pst_highestfd; fd++) * EOVERFLOW is not a fatal error for the fields we use.
* See the "EOVERFLOW Error" section of pstat_getvminfo(3).
*/
if (pstat_getproc(&pst, sizeof(pst), 0, getpid()) != -1 ||
errno == EOVERFLOW) {
for (fd = lowfd; fd <= pst.pst_highestfd; fd++)
(void)close(fd); (void)close(fd);
} else { return 0;
closefrom_fallback(lowfd);
} }
return -1;
} }
#elif defined(HAVE_DIRFD) #elif defined(HAVE_DIRFD)
static int static int
@ -135,8 +125,8 @@ closefrom_procfs(int lowfd)
int ret = 0; int ret = 0;
int i; int i;
/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */ /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) # ifdef __APPLE__
path = "/dev/fd"; path = "/dev/fd";
# else # else
path = "/proc/self/fd"; path = "/proc/self/fd";
@ -180,13 +170,28 @@ closefrom_procfs(int lowfd)
return ret; return ret;
} }
#endif
/*
* Close all file descriptors greater than or equal to lowfd.
* We try the fast way first, falling back on the slow method.
*/
void void
closefrom(int lowfd) closefrom(int lowfd)
{ {
if (closefrom_procfs(lowfd) == 0) /* Try the fast method first, if possible. */
#if defined(HAVE_FCNTL_CLOSEM)
if (fcntl(lowfd, F_CLOSEM, 0) != -1)
return; return;
#endif /* HAVE_FCNTL_CLOSEM */
#if defined(HAVE_PSTAT_GETPROC)
if (closefrom_pstat(lowfd) != -1)
return;
#elif defined(HAVE_DIRFD)
if (closefrom_procfs(lowfd) != -1)
return;
#endif /* HAVE_DIRFD */
/* Do things the slow way. */
closefrom_fallback(lowfd); closefrom_fallback(lowfd);
} }
#endif /* HAVE_FCNTL_CLOSEM */