]> git.armaanb.net Git - opendoas.git/blob - libopenbsd/closefrom.c
Handle empty argv
[opendoas.git] / libopenbsd / closefrom.c
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
5  *      Todd C. Miller <Todd.Miller@sudo.ws>
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 /*
21  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
22  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
23  */
24
25 #include "config.h"
26
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <paths.h>
34 #ifdef HAVE_PSTAT_GETPROC
35 # include <sys/pstat.h>
36 #else
37 # include <dirent.h>
38 #endif
39
40 #include "openbsd.h"
41
42 #ifndef _POSIX_OPEN_MAX
43 # define _POSIX_OPEN_MAX        20
44 #endif
45
46 /*
47  * Close all file descriptors greater than or equal to lowfd.
48  * This is the expensive (fallback) method.
49  */
50 static void
51 closefrom_fallback(int lowfd)
52 {
53     long fd, maxfd;
54
55     /*
56      * Fall back on sysconf(_SC_OPEN_MAX).  We avoid checking
57      * resource limits since it is possible to open a file descriptor
58      * and then drop the rlimit such that it is below the open fd.
59      */
60     maxfd = sysconf(_SC_OPEN_MAX);
61     if (maxfd < 0)
62         maxfd = _POSIX_OPEN_MAX;
63
64     for (fd = lowfd; fd < maxfd; fd++) {
65 #ifdef __APPLE__
66         /* Avoid potential libdispatch crash when we close its fds. */
67         (void) fcntl((int) fd, F_SETFD, FD_CLOEXEC);
68 #else
69         (void) close((int) fd);
70 #endif
71     }
72 }
73
74 /*
75  * Close all file descriptors greater than or equal to lowfd.
76  * We try the fast way first, falling back on the slow method.
77  */
78 void
79 closefrom(int lowfd)
80 {
81 #if defined(HAVE_PSTAT_GETPROC)
82     struct pst_status pstat;
83 #elif defined(HAVE_DIRFD)
84     const char *path;
85     DIR *dirp;
86 #endif
87
88     /* Try the fast method first, if possible. */
89 #if defined(HAVE_FCNTL_CLOSEM)
90     if (fcntl(lowfd, F_CLOSEM, 0) != -1)
91         return;
92 #endif
93 #if defined(HAVE_PSTAT_GETPROC)
94     /*
95      * EOVERFLOW is not a fatal error for the fields we use.
96      * See the "EOVERFLOW Error" section of pstat_getvminfo(3).
97      */
98     if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1 ||
99         errno == EOVERFLOW) {
100         int fd;
101
102         for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
103             (void) close(fd);
104         return;
105     }
106 #elif defined(HAVE_DIRFD)
107     /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
108 # ifdef __APPLE__
109     path = _PATH_DEV "fd";
110 # else
111     path = "/proc/self/fd";
112 # endif
113     if ((dirp = opendir(path)) != NULL) {
114         struct dirent *dent;
115         while ((dent = readdir(dirp)) != NULL) {
116             const char *errstr;
117             int fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
118             if (errstr == NULL && fd != dirfd(dirp)) {
119 # ifdef __APPLE__
120                 /* Avoid potential libdispatch crash when we close its fds. */
121                 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
122 # else
123                 (void) close(fd);
124 # endif
125             }
126         }
127         (void) closedir(dirp);
128         return;
129     }
130 #endif /* HAVE_DIRFD */
131
132     /* Do things the slow way. */
133     closefrom_fallback(lowfd);
134 }