Coverage Report

Created: 2026-01-09 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}