/src/gnupg/common/exechelp-posix.c
Line | Count | Source |
1 | | /* exechelp.c - Fork and exec helpers for POSIX |
2 | | * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH |
4 | | * |
5 | | * This file is part of GnuPG. |
6 | | * |
7 | | * This file is free software; you can redistribute it and/or modify |
8 | | * it under the terms of either |
9 | | * |
10 | | * - the GNU Lesser General Public License as published by the Free |
11 | | * Software Foundation; either version 3 of the License, or (at |
12 | | * your option) any later version. |
13 | | * |
14 | | * or |
15 | | * |
16 | | * - the GNU General Public License as published by the Free |
17 | | * Software Foundation; either version 2 of the License, or (at |
18 | | * your option) any later version. |
19 | | * |
20 | | * or both in parallel, as here. |
21 | | * |
22 | | * This file is distributed in the hope that it will be useful, |
23 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
25 | | * GNU General Public License for more details. |
26 | | * |
27 | | * You should have received a copy of the GNU General Public License |
28 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
29 | | * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) |
30 | | */ |
31 | | |
32 | | #include <config.h> |
33 | | |
34 | | #if defined(HAVE_W32_SYSTEM) |
35 | | #error This code is only used on POSIX |
36 | | #endif |
37 | | |
38 | | #include <stdio.h> |
39 | | #include <stdlib.h> |
40 | | #include <stdint.h> |
41 | | #include <string.h> |
42 | | #include <errno.h> |
43 | | #include <assert.h> |
44 | | #ifdef HAVE_SIGNAL_H |
45 | | # include <signal.h> |
46 | | #endif |
47 | | #include <unistd.h> |
48 | | #include <fcntl.h> |
49 | | |
50 | | #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ |
51 | | #undef HAVE_NPTH |
52 | | #undef USE_NPTH |
53 | | #endif |
54 | | |
55 | | #ifdef HAVE_NPTH |
56 | | #include <npth.h> |
57 | | #endif |
58 | | #include <sys/wait.h> |
59 | | |
60 | | #ifdef HAVE_GETRLIMIT |
61 | | #include <sys/time.h> |
62 | | #include <sys/resource.h> |
63 | | #endif /*HAVE_GETRLIMIT*/ |
64 | | |
65 | | #ifdef HAVE_STAT |
66 | | # include <sys/stat.h> |
67 | | #endif |
68 | | |
69 | | #if __linux__ |
70 | | # include <sys/types.h> |
71 | | # include <dirent.h> |
72 | | #endif /*__linux__ */ |
73 | | |
74 | | #include "util.h" |
75 | | #include "i18n.h" |
76 | | #include "sysutils.h" |
77 | | #include "exechelp.h" |
78 | | |
79 | | |
80 | | /* Helper */ |
81 | | static inline gpg_error_t |
82 | | my_error_from_syserror (void) |
83 | 0 | { |
84 | 0 | return gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); |
85 | 0 | } |
86 | | |
87 | | |
88 | | /* Return the maximum number of currently allowed open file |
89 | | descriptors. Only useful on POSIX systems but returns a value on |
90 | | other systems too. */ |
91 | | int |
92 | | get_max_fds (void) |
93 | 0 | { |
94 | 0 | int max_fds = -1; |
95 | 0 | #ifdef HAVE_GETRLIMIT |
96 | 0 | struct rlimit rl; |
97 | | |
98 | | /* Under Linux we can figure out the highest used file descriptor by |
99 | | * reading /proc/PID/fd. This is in the common cases much fast than |
100 | | * for example doing 4096 close calls where almost all of them will |
101 | | * fail. On a system with a limit of 4096 files and only 8 files |
102 | | * open with the highest number being 10, we speedup close_all_fds |
103 | | * from 125ms to 0.4ms including readdir. |
104 | | * |
105 | | * Another option would be to close the file descriptors as returned |
106 | | * from reading that directory - however then we need to snapshot |
107 | | * that list before starting to close them. */ |
108 | 0 | #ifdef __linux__ |
109 | 0 | { |
110 | 0 | DIR *dir = NULL; |
111 | 0 | struct dirent *dir_entry; |
112 | 0 | const char *s; |
113 | 0 | int x; |
114 | |
|
115 | 0 | dir = opendir ("/proc/self/fd"); |
116 | 0 | if (dir) |
117 | 0 | { |
118 | 0 | while ((dir_entry = readdir (dir))) |
119 | 0 | { |
120 | 0 | s = dir_entry->d_name; |
121 | 0 | if ( *s < '0' || *s > '9') |
122 | 0 | continue; |
123 | 0 | x = atoi (s); |
124 | 0 | if (x > max_fds) |
125 | 0 | max_fds = x; |
126 | 0 | } |
127 | 0 | closedir (dir); |
128 | 0 | } |
129 | 0 | if (max_fds != -1) |
130 | 0 | return max_fds + 1; |
131 | 0 | } |
132 | 0 | #endif /* __linux__ */ |
133 | | |
134 | | |
135 | 0 | # ifdef RLIMIT_NOFILE |
136 | 0 | if (!getrlimit (RLIMIT_NOFILE, &rl)) |
137 | 0 | max_fds = rl.rlim_max; |
138 | 0 | # endif |
139 | |
|
140 | 0 | # ifdef RLIMIT_OFILE |
141 | 0 | if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl)) |
142 | 0 | max_fds = rl.rlim_max; |
143 | |
|
144 | 0 | # endif |
145 | 0 | #endif /*HAVE_GETRLIMIT*/ |
146 | |
|
147 | 0 | #ifdef _SC_OPEN_MAX |
148 | 0 | if (max_fds == -1) |
149 | 0 | { |
150 | 0 | long int scres = sysconf (_SC_OPEN_MAX); |
151 | 0 | if (scres >= 0) |
152 | 0 | max_fds = scres; |
153 | 0 | } |
154 | 0 | #endif |
155 | |
|
156 | 0 | #ifdef _POSIX_OPEN_MAX |
157 | 0 | if (max_fds == -1) |
158 | 0 | max_fds = _POSIX_OPEN_MAX; |
159 | 0 | #endif |
160 | |
|
161 | | #ifdef OPEN_MAX |
162 | | if (max_fds == -1) |
163 | | max_fds = OPEN_MAX; |
164 | | #endif |
165 | |
|
166 | 0 | if (max_fds == -1) |
167 | 0 | max_fds = 256; /* Arbitrary limit. */ |
168 | | |
169 | | /* AIX returns INT32_MAX instead of a proper value. We assume that |
170 | | this is always an error and use an arbitrary limit. */ |
171 | 0 | #ifdef INT32_MAX |
172 | 0 | if (max_fds == INT32_MAX) |
173 | 0 | max_fds = 256; |
174 | 0 | #endif |
175 | |
|
176 | 0 | return max_fds; |
177 | 0 | } |
178 | | |
179 | | |
180 | | /* Close all file descriptors starting with descriptor FIRST. If |
181 | | EXCEPT is not NULL, it is expected to be a list of file descriptors |
182 | | which shall not be closed. This list shall be sorted in ascending |
183 | | order with the end marked by -1. */ |
184 | | void |
185 | | close_all_fds (int first, const int *except) |
186 | 0 | { |
187 | 0 | int max_fd = get_max_fds (); |
188 | 0 | int fd, i, except_start; |
189 | |
|
190 | 0 | if (except) |
191 | 0 | { |
192 | 0 | except_start = 0; |
193 | 0 | for (fd=first; fd < max_fd; fd++) |
194 | 0 | { |
195 | 0 | for (i=except_start; except[i] != -1; i++) |
196 | 0 | { |
197 | 0 | if (except[i] == fd) |
198 | 0 | { |
199 | | /* If we found the descriptor in the exception list |
200 | | we can start the next compare run at the next |
201 | | index because the exception list is ordered. */ |
202 | 0 | except_start = i + 1; |
203 | 0 | break; |
204 | 0 | } |
205 | 0 | } |
206 | 0 | if (except[i] == -1) |
207 | 0 | close (fd); |
208 | 0 | } |
209 | 0 | } |
210 | 0 | else |
211 | 0 | { |
212 | 0 | for (fd=first; fd < max_fd; fd++) |
213 | 0 | close (fd); |
214 | 0 | } |
215 | |
|
216 | 0 | gpg_err_set_errno (0); |
217 | 0 | } |
218 | | |
219 | | |
220 | | /* Returns an array with all currently open file descriptors. The end |
221 | | of the array is marked by -1. The caller needs to release this |
222 | | array using the *standard free* and not with xfree. This allow the |
223 | | use of this function right at startup even before libgcrypt has |
224 | | been initialized. Returns NULL on error and sets ERRNO |
225 | | accordingly. */ |
226 | | int * |
227 | | get_all_open_fds (void) |
228 | 0 | { |
229 | 0 | int *array; |
230 | 0 | size_t narray; |
231 | 0 | int fd, max_fd, idx; |
232 | | #ifndef HAVE_STAT |
233 | | array = calloc (1, sizeof *array); |
234 | | if (array) |
235 | | array[0] = -1; |
236 | | #else /*HAVE_STAT*/ |
237 | 0 | struct stat statbuf; |
238 | |
|
239 | 0 | max_fd = get_max_fds (); |
240 | 0 | narray = 32; /* If you change this change also t-exechelp.c. */ |
241 | 0 | array = calloc (narray, sizeof *array); |
242 | 0 | if (!array) |
243 | 0 | return NULL; |
244 | | |
245 | | /* Note: The list we return is ordered. */ |
246 | 0 | for (idx=0, fd=0; fd < max_fd; fd++) |
247 | 0 | if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) |
248 | 0 | { |
249 | 0 | if (idx+1 >= narray) |
250 | 0 | { |
251 | 0 | int *tmp; |
252 | |
|
253 | 0 | narray += (narray < 256)? 32:256; |
254 | 0 | tmp = realloc (array, narray * sizeof *array); |
255 | 0 | if (!tmp) |
256 | 0 | { |
257 | 0 | free (array); |
258 | 0 | return NULL; |
259 | 0 | } |
260 | 0 | array = tmp; |
261 | 0 | } |
262 | 0 | array[idx++] = fd; |
263 | 0 | } |
264 | 0 | array[idx] = -1; |
265 | 0 | #endif /*HAVE_STAT*/ |
266 | 0 | return array; |
267 | 0 | } |
268 | | |
269 | | |
270 | | static gpg_error_t |
271 | | do_create_pipe (int filedes[2]) |
272 | 0 | { |
273 | 0 | gpg_error_t err = 0; |
274 | |
|
275 | 0 | if (pipe (filedes) == -1) |
276 | 0 | { |
277 | 0 | err = my_error_from_syserror (); |
278 | 0 | filedes[0] = filedes[1] = -1; |
279 | 0 | } |
280 | |
|
281 | 0 | return err; |
282 | 0 | } |
283 | | |
284 | | |
285 | | static gpg_error_t |
286 | | create_pipe_and_estream (gnupg_fd_t *r_fd, estream_t *r_fp, |
287 | | int outbound, int nonblock) |
288 | 0 | { |
289 | 0 | gpg_error_t err; |
290 | 0 | int filedes[2]; |
291 | |
|
292 | 0 | if (pipe (filedes) == -1) |
293 | 0 | { |
294 | 0 | err = my_error_from_syserror (); |
295 | 0 | log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); |
296 | 0 | *r_fd = -1; |
297 | 0 | *r_fp = NULL; |
298 | 0 | return err; |
299 | 0 | } |
300 | | |
301 | 0 | if (!outbound) |
302 | 0 | { |
303 | 0 | *r_fd = filedes[1]; |
304 | 0 | *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r"); |
305 | 0 | } |
306 | 0 | else |
307 | 0 | { |
308 | 0 | *r_fd = filedes[0]; |
309 | 0 | *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w"); |
310 | 0 | } |
311 | 0 | if (!*r_fp) |
312 | 0 | { |
313 | 0 | err = my_error_from_syserror (); |
314 | 0 | log_error (_("error creating a stream for a pipe: %s\n"), |
315 | 0 | gpg_strerror (err)); |
316 | 0 | close (filedes[0]); |
317 | 0 | close (filedes[1]); |
318 | 0 | *r_fd = -1; |
319 | 0 | return err; |
320 | 0 | } |
321 | 0 | return 0; |
322 | 0 | } |
323 | | |
324 | | |
325 | | /* Portable function to create a pipe. Under Windows the write end is |
326 | | inheritable. Pipe is created and the read end is stored at R_FD. |
327 | | An estream is created for the write end and stored at R_FP. */ |
328 | | gpg_error_t |
329 | | gnupg_create_inbound_pipe (gnupg_fd_t *r_fd, estream_t *r_fp, int nonblock) |
330 | 0 | { |
331 | 0 | if (!r_fd || !r_fp) |
332 | 0 | gpg_error (GPG_ERR_INV_ARG); |
333 | |
|
334 | 0 | return create_pipe_and_estream (r_fd, r_fp, 0, nonblock); |
335 | 0 | } |
336 | | |
337 | | |
338 | | /* Portable function to create a pipe. Under Windows the read end is |
339 | | inheritable. Pipe is created and the write end is stored at R_FD. |
340 | | An estream is created for the write end and stored at R_FP. */ |
341 | | gpg_error_t |
342 | | gnupg_create_outbound_pipe (gnupg_fd_t *r_fd, estream_t *r_fp, int nonblock) |
343 | 0 | { |
344 | 0 | if (!r_fd || !r_fp) |
345 | 0 | gpg_error (GPG_ERR_INV_ARG); |
346 | |
|
347 | 0 | return create_pipe_and_estream (r_fd, r_fp, 1, nonblock); |
348 | 0 | } |
349 | | |
350 | | |
351 | | /* Portable function to create a pipe. FLAGS=GNUPG_PIPE_INBOUND for |
352 | | ihneritable write-end for Windows, GNUPG_PIPE_OUTBOUND for |
353 | | inheritable read-end for Windows, GNUPG_PIPE_BOTH to specify |
354 | | both ends may be inheritable. */ |
355 | | gpg_error_t |
356 | | gnupg_create_pipe (int filedes[2], int flags) |
357 | 0 | { |
358 | 0 | (void)flags; |
359 | 0 | return do_create_pipe (filedes); |
360 | 0 | } |
361 | | |
362 | | |
363 | | /* Close the end of a pipe. */ |
364 | | void |
365 | | gnupg_close_pipe (int fd) |
366 | 0 | { |
367 | 0 | if (fd != -1) |
368 | 0 | close (fd); |
369 | 0 | } |