Annotation of embedaddon/sudo/src/preserve_fds.c, revision 1.1.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>