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 */ 63static void 64closefrom_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 87void 88closefrom(int lowfd) 89{ 90 (void) fcntl(lowfd, F_CLOSEM, 0); 91} 92#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) 93void 94closefrom(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) 122void 123closefrom(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 152void 153closefrom(int lowfd) 154{ 155 closefrom_fallback(lowfd); 156} 157#endif /* !HAVE_FCNTL_CLOSEM */ 158#endif /* HAVE_CLOSEFROM */ 159