Annotation of embedaddon/sudo/src/preserve_fds.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2013-2014 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 <config.h>
! 18:
! 19: #include <sys/param.h> /* for howmany() on Linux */
! 20: #ifdef HAVE_SYS_SYSMACROS_H
! 21: # include <sys/sysmacros.h> /* for howmany() on Solaris */
! 22: #endif /* HAVE_SYS_SYSMACROS_H */
! 23: #ifdef HAVE_SYS_SELECT_H
! 24: # include <sys/select.h> /* for FD_* macros */
! 25: #endif /* HAVE_SYS_SELECT_H */
! 26: #include <stdio.h>
! 27: #ifdef STDC_HEADERS
! 28: # include <stdlib.h>
! 29: # include <stddef.h>
! 30: #else
! 31: # ifdef HAVE_STDLIB_H
! 32: # include <stdlib.h>
! 33: # endif
! 34: #endif /* STDC_HEADERS */
! 35: #ifdef HAVE_STRING_H
! 36: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
! 37: # include <memory.h>
! 38: # endif
! 39: # include <string.h>
! 40: #endif /* HAVE_STRING_H */
! 41: #ifdef HAVE_STRINGS_H
! 42: # include <strings.h>
! 43: #endif /* HAVE_STRINGS_H */
! 44: #ifdef HAVE_UNISTD_H
! 45: # include <unistd.h>
! 46: #endif /* HAVE_UNISTD_H */
! 47: #include <errno.h>
! 48: #include <fcntl.h>
! 49: #include <limits.h>
! 50:
! 51: #include "sudo.h"
! 52:
! 53: /*
! 54: * Add an fd to preserve.
! 55: */
! 56: int
! 57: add_preserved_fd(struct preserved_fd_list *pfds, int fd)
! 58: {
! 59: struct preserved_fd *pfd, *pfd_new;
! 60: debug_decl(add_preserved_fd, SUDO_DEBUG_UTIL)
! 61:
! 62: pfd_new = emalloc(sizeof(*pfd));
! 63: pfd_new->lowfd = fd;
! 64: pfd_new->highfd = fd;
! 65: pfd_new->flags = fcntl(fd, F_GETFD);
! 66: if (pfd_new->flags == -1) {
! 67: efree(pfd_new);
! 68: debug_return_int(-1);
! 69: }
! 70:
! 71: TAILQ_FOREACH(pfd, pfds, entries) {
! 72: if (fd == pfd->highfd) {
! 73: /* already preserved */
! 74: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 75: "fd %d already preserved", fd);
! 76: efree(pfd_new);
! 77: break;
! 78: }
! 79: if (fd < pfd->highfd) {
! 80: TAILQ_INSERT_BEFORE(pfd, pfd_new, entries);
! 81: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 82: "preserving fd %d", fd);
! 83: break;
! 84: }
! 85: }
! 86: if (pfd == NULL) {
! 87: TAILQ_INSERT_TAIL(pfds, pfd_new, entries);
! 88: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 89: "preserving fd %d", fd);
! 90: }
! 91:
! 92: debug_return_int(0);
! 93: }
! 94:
! 95: /*
! 96: * Close all descriptors, startfd and higher except those listed
! 97: * in pfds.
! 98: */
! 99: void
! 100: closefrom_except(int startfd, struct preserved_fd_list *pfds)
! 101: {
! 102: int debug_fd, fd, lastfd = -1;
! 103: struct preserved_fd *pfd, *pfd_next;
! 104: fd_set *fdsp;
! 105: debug_decl(closefrom_except, SUDO_DEBUG_UTIL)
! 106:
! 107: debug_fd = sudo_debug_fd_get();
! 108:
! 109: /* First, relocate preserved fds to be as contiguous as possible. */
! 110: TAILQ_FOREACH_REVERSE_SAFE(pfd, pfds, preserved_fd_list, entries, pfd_next) {
! 111: if (pfd->highfd < startfd)
! 112: continue;
! 113: fd = dup(pfd->highfd);
! 114: if (fd == -1) {
! 115: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
! 116: "dup %d", pfd->highfd);
! 117: if (errno == EBADF) {
! 118: TAILQ_REMOVE(pfds, pfd, entries);
! 119: continue;
! 120: }
! 121: /* NOTE: still need to adjust lastfd below with unchanged lowfd. */
! 122: } else if (fd < pfd->highfd) {
! 123: pfd->lowfd = fd;
! 124: fd = pfd->highfd;
! 125: if (fd == debug_fd)
! 126: debug_fd = sudo_debug_fd_set(pfd->lowfd);
! 127: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 128: "dup %d -> %d", pfd->highfd, pfd->lowfd);
! 129: }
! 130: if (fd != -1)
! 131: (void) close(fd);
! 132:
! 133: if (pfd->lowfd > lastfd)
! 134: lastfd = pfd->lowfd; /* highest (relocated) preserved fd */
! 135: }
! 136:
! 137: if (lastfd == -1) {
! 138: /* No fds to preserve. */
! 139: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 140: "closefrom(%d)", startfd);
! 141: closefrom(startfd);
! 142: debug_return;
! 143: }
! 144:
! 145: /* Create bitmap of preserved (relocated) fds. */
! 146: fdsp = ecalloc(howmany(lastfd + 1, NFDBITS), sizeof(fd_mask));
! 147: TAILQ_FOREACH(pfd, pfds, entries) {
! 148: FD_SET(pfd->lowfd, fdsp);
! 149: }
! 150:
! 151: /*
! 152: * Close any unpreserved fds [startfd,lastfd]
! 153: */
! 154: for (fd = startfd; fd <= lastfd; fd++) {
! 155: if (!FD_ISSET(fd, fdsp)) {
! 156: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 157: "closing fd %d", fd);
! 158: #ifdef __APPLE__
! 159: /* Avoid potential libdispatch crash when we close its fds. */
! 160: (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
! 161: #else
! 162: (void) close(fd);
! 163: #endif
! 164: }
! 165: }
! 166: free(fdsp);
! 167:
! 168: /* Let closefrom() do the rest for us. */
! 169: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 170: "closefrom(%d)", lastfd + 1);
! 171: closefrom(lastfd + 1);
! 172:
! 173: /* Restore preserved fds and set flags. */
! 174: TAILQ_FOREACH_REVERSE(pfd, pfds, preserved_fd_list, entries) {
! 175: if (pfd->lowfd != pfd->highfd) {
! 176: if (dup2(pfd->lowfd, pfd->highfd) == -1) {
! 177: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
! 178: "dup2(%d, %d): %s", pfd->lowfd, pfd->highfd,
! 179: strerror(errno));
! 180: } else {
! 181: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 182: "dup2(%d, %d)", pfd->lowfd, pfd->highfd);
! 183: }
! 184: if (fcntl(pfd->highfd, F_SETFD, pfd->flags) == -1) {
! 185: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
! 186: "fcntl(%d, F_SETFD, %d): %s", pfd->highfd,
! 187: pfd->flags, strerror(errno));
! 188: } else {
! 189: sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
! 190: "fcntl(%d, F_SETFD, %d)", pfd->highfd, pfd->flags);
! 191: }
! 192: if (pfd->lowfd == debug_fd)
! 193: debug_fd = sudo_debug_fd_set(pfd->highfd);
! 194: (void) close(pfd->lowfd);
! 195: pfd->lowfd = pfd->highfd;
! 196: }
! 197: }
! 198: debug_return;
! 199: }
! 200:
! 201: /*
! 202: * Parse a comma-separated list of fds and add them to preserved_fds.
! 203: */
! 204: void
! 205: parse_preserved_fds(struct preserved_fd_list *pfds, const char *fdstr)
! 206: {
! 207: const char *cp = fdstr;
! 208: long lval;
! 209: char *ep;
! 210: debug_decl(parse_preserved_fds, SUDO_DEBUG_UTIL)
! 211:
! 212: do {
! 213: errno = 0;
! 214: lval = strtol(cp, &ep, 10);
! 215: if (ep == cp || (*ep != ',' && *ep != '\0')) {
! 216: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
! 217: "unable to parse fd string %s", cp);
! 218: break;
! 219: }
! 220: if ((errno == ERANGE && lval == LONG_MAX) || lval < 0 || lval > INT_MAX) {
! 221: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
! 222: "range error parsing fd string %s", cp);
! 223: } else {
! 224: add_preserved_fd(pfds, (int)lval);
! 225: }
! 226: cp = ep + 1;
! 227: } while (*ep != '\0');
! 228:
! 229: debug_return;
! 230: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>