Fix issue with fast file-descriptor close on *BSD.

This fixes a problem introduced in 8a5fe8ce6b

On BSD, fdescfs is normally mounted at /dev/fd. However
if it is NOT mounted, devfs creates a directory at /dev/fd
which contains (only) the file descriptors 0,1 and 2.

Under these conditions, opendir() will succeed, and
if we proceed we will fail to close extant
file descriptors which should be closed.

Check that there is a filesystem mounted at /dev/fd
by checking that the device changes between /dev/fd
and /dev. If if doesn't, fall back to the dumb path.

Thanks to Roman Bogorodskiy for spotting the problem
and helping with diagnosis.
This commit is contained in:
Simon Kelley
2025-06-22 23:04:36 +01:00
parent ade97495e6
commit 15841f187d

View File

@@ -34,6 +34,10 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#endif #endif
#ifdef HAVE_BSD_NETWORK
#include <libgen.h>
#endif
/* SURF random number generator */ /* SURF random number generator */
static u32 seed[32]; static u32 seed[32];
@@ -831,9 +835,34 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
#endif #endif
#ifdef FDESCFS #ifdef FDESCFS
DIR *d; DIR *d = NULL;
if ((d = opendir(FDESCFS))) # ifdef HAVE_BSD_NETWORK
dev_t dirdev = 0;
char fdescfs[] = FDESCFS; /* string must be writable */
struct stat statbuf;
/* On BSD, fdescfs is normally mounted at /dev/fd. However
if it is NOT mounted, devfs creates a directory at /dev/fd
which contains (only) the file descriptors 0,1 and 2.
Under these conditions, opendir() will succeed, and
if we proceed we will fail to close extant
file descriptors which should be closed.
Check that there is a filesystem mounted at /dev/fd
by checking that the device changes between /dev/fd
and /dev. If if doesn't, fall back to the dumb path. */
if (stat(fdescfs, &statbuf) != -1)
dirdev = statbuf.st_dev;
if (stat(dirname(fdescfs), &statbuf) != -1 &&
dirdev != statbuf.st_dev)
# endif
d = opendir(FDESCFS);
if (d)
{ {
struct dirent *de; struct dirent *de;