Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
371 views
in Technique[技术] by (71.8m points)

posix - Getting the highest allocated file descriptor

Is there a portable way (POSIX) to get the highest allocated file descriptor number for the current process?

I know that there's a nice way to get the number on AIX, for example, but I'm looking for a portable method.

The reason I'm asking is that I want to close all open file descriptors. My program is a server which runs as root and forks and execs child programs for non-root users. Leaving the privileged file descriptors open in the child process is a security problem. Some file descriptors may be opened by code I cannot control (the C library, third party libraries, etc.), so I cannot rely on FD_CLOEXEC either.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

While portable, closing all file descriptors up to sysconf(_SC_OPEN_MAX) is not reliable, because on most systems this call returns the current file descriptor soft limit, which could have been lowered below the highest used file descriptor. Another issue is that on many systems sysconf(_SC_OPEN_MAX) may return INT_MAX, which can cause this approach to be unacceptably slow. Unfortunately, there is no reliable, portable alternative that does not involve iterating over every possible non-negative int file descriptor.

Although not portable, most operating systems in common use today provide one or more of the following solutions to this problem:

  1. A library function to close all open file descriptors >= fd or within a range. This is the simplest solution for the common case of closing all file descriptors, although it cannot be used for much else. To close all file descriptors except for a certain set, dup2 can be used to move them to the low end beforehand, and to move them back afterward if necessary.

    • closefrom(fd) (Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+, NetBSD 3.0+, OpenBSD 3.5+)

    • fcntl(fd, F_CLOSEM, 0) (AIX, IRIX, NetBSD)

    • close_range(lowfd, highfd, 0) (Linux kernel 5.9+ with glibc 2.34+, FreeBSD 12.2+)

  2. A library function to provide the maximum file descriptor currently in use by the process. To close all file descriptors above a certain number, either close all of them up to this maximum, or continually get and close the highest file descriptor in a loop until the low bound is reached. Which is more efficient depends on the file descriptor density.

    • fcntl(0, F_MAXFD) (NetBSD)

    • pstat_getproc(&ps, sizeof(struct pst_status), (size_t)0, (int)getpid())
      Returns information about the process, including the highest file descriptor currently open in ps.pst_highestfd. (HP-UX)

  3. A library function to list all file descriptors currently in use by the process. This is more flexible in that it allows for closing all file descriptors, finding the highest file descriptor, or doing just about anything else on every open file descriptor, possibly even those of another process. Example (OpenSSH)

    • proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, fdinfo_buf, sz) (macOS)
  4. The number of file descriptor slots currently allocated for a process provides an upper bound on the file descriptor numbers currently in use. Example (Ruby)

    • "FDSize:" line in /proc/pid/status or /proc/self/status (Linux)
  5. A directory containing an entry for each open file descriptor. This is similar to #3 except that it isn't a library function. This can be more complicated than the other approaches for the common uses, and can fail for a variety of reasons such as proc/fdescfs not mounted, a chroot environment, or no file descriptors available to open the directory (process or system limit). Therefore use of this approach is often combined with a fallback mechanism. Example (OpenSSH), another example (glib).

    • /proc/pid/fd/ or /proc/self/fd/ (Linux, Solaris, AIX, Cygwin, NetBSD)
      (AIX does not support "self")

    • /dev/fd/ (FreeBSD, macOS)

It can be difficult to handle all corner cases reliably with this approach. For example consider the situation where all file descriptors >= fd are to be closed, but all file descriptors < fd are used, the current process resource limit is fd, and there are file descriptors >= fd in use. Because the process resource limit has been reached the directory cannot be opened. If closing every file descriptor from fd through the resource limit or sysconf(_SC_OPEN_MAX) is used as a fallback, nothing will be closed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...