Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/util/closefrom.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2022
5
* Todd C. Miller <[email protected]>
6
*
7
* Permission to use, copy, modify, and distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
20
#include <config.h>
21
22
#ifndef HAVE_CLOSEFROM
23
24
#include <errno.h>
25
#include <fcntl.h>
26
#include <limits.h>
27
#include <stdlib.h>
28
#include <unistd.h>
29
#ifdef HAVE_PSTAT_GETPROC
30
# include <sys/pstat.h>
31
#else
32
# include <dirent.h>
33
#endif
34
#ifdef HAVE_LIBPROC_H
35
# include <libproc.h>
36
#endif
37
#ifdef HAVE_LINUX_CLOSE_RANGE_H
38
# include <linux/close_range.h>
39
#endif
40
41
#include <sudo_compat.h>
42
#include <sudo_util.h>
43
#include <pathnames.h>
44
45
#ifndef OPEN_MAX
46
# define OPEN_MAX 256
47
#endif
48
49
/* Avoid potential libdispatch crash on macOS when we close its fds. */
50
#ifdef __APPLE__
51
# define closefrom_close(x) fcntl((x), F_SETFD, FD_CLOEXEC)
52
#else
53
# define closefrom_close(x) close(x)
54
#endif
55
56
/*
57
* Close all file descriptors greater than or equal to lowfd.
58
* This is the expensive (fallback) method.
59
*/
60
static void
61
closefrom_fallback(int lowfd)
62
{
63
long fd, maxfd;
64
65
/*
66
* Fall back on sysconf(_SC_OPEN_MAX). This is equivalent to
67
* checking the RLIMIT_NOFILE soft limit. It is possible for
68
* there to be open file descriptors past this limit but there's
69
* not much we can do about that since the hard limit may be
70
* RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems).
71
*/
72
maxfd = sysconf(_SC_OPEN_MAX);
73
if (maxfd < OPEN_MAX)
74
maxfd = OPEN_MAX;
75
76
/* Make sure we didn't get RLIM_INFINITY as the upper limit. */
77
if (maxfd > INT_MAX)
78
maxfd = INT_MAX;
79
80
for (fd = lowfd; fd < maxfd; fd++) {
81
(void)closefrom_close((int)fd);
82
}
83
}
84
85
/*
86
* Close all file descriptors greater than or equal to lowfd.
87
* We try the fast way first, falling back on the slow method.
88
*/
89
void
90
sudo_closefrom(int lowfd)
91
{
92
#if defined(HAVE_PSTAT_GETPROC)
93
struct pst_status pst;
94
#elif defined(HAVE_DIRFD)
95
const char *path;
96
DIR *dirp;
97
#endif
98
#if defined(HAVE_PROC_PIDINFO)
99
struct proc_fdinfo *buf = NULL;
100
const pid_t pid = getpid();
101
int i, n, len;
102
#endif
103
104
/* Try the fast method first, if possible. */
105
#if defined(HAVE_FCNTL_CLOSEM)
106
if (fcntl(lowfd, F_CLOSEM, 0) != -1)
107
return;
108
#elif defined(HAVE_CLOSE_RANGE)
109
if (close_range((unsigned int)lowfd, ~0U, 0) != -1)
110
return;
111
#elif defined(HAVE_PROC_PIDINFO)
112
len = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
113
switch (len) {
114
case 0:
115
/* No open files. */
116
return;
117
case -1:
118
/* Fall back on other methods. */
119
break;
120
default:
121
/* Allocate space for 4 extra fds to leave some wiggle room. */
122
buf = malloc(len + (PROC_PIDLISTFD_SIZE * 4));
123
if (buf == NULL)
124
break;
125
n = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, buf, len);
126
if (n == -1 || n > len) {
127
free(buf);
128
break;
129
}
130
n /= PROC_PIDLISTFD_SIZE;
131
for (i = 0; i < n; i++) {
132
if (buf[i].proc_fd >= lowfd) {
133
(void)closefrom_close(buf[i].proc_fd);
134
}
135
}
136
free(buf);
137
return;
138
}
139
#endif /* HAVE_PROC_PIDINFO */
140
#if defined(HAVE_PSTAT_GETPROC)
141
/*
142
* EOVERFLOW is not a fatal error for the fields we use.
143
* See the "EOVERFLOW Error" section of pstat_getvminfo(3).
144
*/
145
if (pstat_getproc(&pst, sizeof(pst), 0, getpid()) != -1 ||
146
errno == EOVERFLOW) {
147
int fd;
148
149
for (fd = lowfd; fd <= pst.pst_highestfd; fd++)
150
(void)closefrom_close(fd);
151
return;
152
}
153
#elif defined(HAVE_DIRFD)
154
/* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
155
# ifdef __APPLE__
156
path = _PATH_DEV "fd";
157
# else
158
path = "/proc/self/fd";
159
# endif
160
if ((dirp = opendir(path)) != NULL) {
161
struct dirent *dent;
162
while ((dent = readdir(dirp)) != NULL) {
163
const char *errstr;
164
int fd = (int)sudo_strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
165
if (errstr == NULL && fd != dirfd(dirp)) {
166
(void)closefrom_close(fd);
167
}
168
}
169
(void)closedir(dirp);
170
return;
171
}
172
#endif /* HAVE_DIRFD */
173
174
/* Do things the slow way. */
175
closefrom_fallback(lowfd);
176
}
177
178
#endif /* HAVE_CLOSEFROM */
179
180