1 /* 2 * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "includes.h" 18 19 #if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) 20 21 #include <sys/types.h> 22 #include <unistd.h> 23 #include <stdio.h> 24 #ifdef HAVE_FCNTL_H 25 # include <fcntl.h> 26 #endif 27 #include <limits.h> 28 #include <stdlib.h> 29 #include <stddef.h> 30 #include <string.h> 31 #ifdef HAVE_DIRENT_H 32 # include <dirent.h> 33 # define NAMLEN(dirent) strlen((dirent)->d_name) 34 #else 35 # define dirent direct 36 # define NAMLEN(dirent) (dirent)->d_namlen 37 # ifdef HAVE_SYS_NDIR_H 38 # include <sys/ndir.h> 39 # endif 40 # ifdef HAVE_SYS_DIR_H 41 # include <sys/dir.h> 42 # endif 43 # ifdef HAVE_NDIR_H 44 # include <ndir.h> 45 # endif 46 #endif 47 #if defined(HAVE_LIBPROC_H) 48 # include <libproc.h> 49 #endif 50 51 #ifndef OPEN_MAX 52 # define OPEN_MAX 256 53 #endif 54 55 #if 0 56 __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; 57 #endif /* lint */ 58 59 #ifndef HAVE_FCNTL_CLOSEM 60 /* 61 * Close all file descriptors greater than or equal to lowfd. 62 */ 63 static void 64 closefrom_fallback(int lowfd) 65 { 66 long fd, maxfd; 67 68 /* 69 * Fall back on sysconf() or getdtablesize(). We avoid checking 70 * resource limits since it is possible to open a file descriptor 71 * and then drop the rlimit such that it is below the open fd. 72 */ 73 #ifdef HAVE_SYSCONF 74 maxfd = sysconf(_SC_OPEN_MAX); 75 #else 76 maxfd = getdtablesize(); 77 #endif /* HAVE_SYSCONF */ 78 if (maxfd < 0) 79 maxfd = OPEN_MAX; 80 81 for (fd = lowfd; fd < maxfd; fd++) 82 (void) close((int) fd); 83 } 84 #endif /* HAVE_FCNTL_CLOSEM */ 85 86 #ifdef HAVE_FCNTL_CLOSEM 87 void 88 closefrom(int lowfd) 89 { 90 (void) fcntl(lowfd, F_CLOSEM, 0); 91 } 92 #elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) 93 void 94 closefrom(int lowfd) 95 { 96 int i, r, sz; 97 pid_t pid = getpid(); 98 struct proc_fdinfo *fdinfo_buf = NULL; 99 100 sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); 101 if (sz == 0) 102 return; /* no fds, really? */ 103 else if (sz == -1) 104 goto fallback; 105 if ((fdinfo_buf = malloc(sz)) == NULL) 106 goto fallback; 107 r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz); 108 if (r < 0 || r > sz) 109 goto fallback; 110 for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) { 111 if (fdinfo_buf[i].proc_fd >= lowfd) 112 close(fdinfo_buf[i].proc_fd); 113 } 114 free(fdinfo_buf); 115 return; 116 fallback: 117 free(fdinfo_buf); 118 closefrom_fallback(lowfd); 119 return; 120 } 121 #elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) 122 void 123 closefrom(int lowfd) 124 { 125 long fd; 126 char fdpath[PATH_MAX], *endp; 127 struct dirent *dent; 128 DIR *dirp; 129 int len; 130 131 #ifdef HAVE_CLOSE_RANGE 132 if (close_range(lowfd, INT_MAX, 0) == 0) 133 return; 134 #endif 135 136 /* Check for a /proc/$$/fd directory. */ 137 len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); 138 if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) { 139 while ((dent = readdir(dirp)) != NULL) { 140 fd = strtol(dent->d_name, &endp, 10); 141 if (dent->d_name != endp && *endp == '\0' && 142 fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) 143 (void) close((int) fd); 144 } 145 (void) closedir(dirp); 146 return; 147 } 148 /* /proc/$$/fd strategy failed, fall back to brute force closure */ 149 closefrom_fallback(lowfd); 150 } 151 #else 152 void 153 closefrom(int lowfd) 154 { 155 closefrom_fallback(lowfd); 156 } 157 #endif /* !HAVE_FCNTL_CLOSEM */ 158 #endif /* HAVE_CLOSEFROM */ 159