Coverage Report

Created: 2022-02-19 20:31

/src/php-src/Zend/zend_signal.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  +----------------------------------------------------------------------+
3
  | Zend Signal Handling                                                 |
4
  +----------------------------------------------------------------------+
5
  | Copyright (c) The PHP Group                                          |
6
  +----------------------------------------------------------------------+
7
  | This source file is subject to version 3.01 of the PHP license,      |
8
  | that is bundled with this package in the file LICENSE, and is        |
9
  | available through the world-wide-web at the following url:           |
10
  | http://www.php.net/license/3_01.txt                                  |
11
  | If you did not receive a copy of the PHP license and are unable to   |
12
  | obtain it through the world-wide-web, please send a note to          |
13
  | license@php.net so we can mail you a copy immediately.               |
14
  +----------------------------------------------------------------------+
15
  | Authors: Lucas Nealan <lucas@php.net>                                |
16
  |          Arnaud Le Blanc <lbarnaud@php.net>                          |
17
  +----------------------------------------------------------------------+
18
19
   This software was contributed to PHP by Facebook Inc. in 2008.
20
21
   Future revisions and derivatives of this source code must acknowledge
22
   Facebook Inc. as the original contributor of this module by leaving
23
   this note intact in the source code.
24
25
   All other licensing and usage conditions are those of the PHP Group.
26
*/
27
28
#define _GNU_SOURCE
29
#include <string.h>
30
31
#include "zend.h"
32
#include "zend_globals.h"
33
#include <signal.h>
34
35
#ifdef HAVE_UNISTD_H
36
#include <unistd.h>
37
#endif
38
39
#ifdef ZEND_SIGNALS
40
41
#include "zend_signal.h"
42
43
#ifdef ZTS
44
ZEND_API int zend_signal_globals_id;
45
ZEND_API size_t zend_signal_globals_offset;
46
#else
47
ZEND_API zend_signal_globals_t zend_signal_globals;
48
#endif /* not ZTS */
49
50
#define SIGNAL_BEGIN_CRITICAL() \
51
0
  sigset_t oldmask; \
52
0
  zend_sigprocmask(SIG_BLOCK, &global_sigmask, &oldmask);
53
#define SIGNAL_END_CRITICAL() \
54
0
  zend_sigprocmask(SIG_SETMASK, &oldmask, NULL);
55
56
#ifdef ZTS
57
# define zend_sigprocmask(signo, set, oldset) tsrm_sigmask((signo), (set), (oldset))
58
#else
59
324k
# define zend_sigprocmask(signo, set, oldset) sigprocmask((signo), (set), (oldset))
60
#endif
61
62
static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context);
63
static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*));
64
65
#ifdef __CYGWIN__
66
#define TIMEOUT_SIG SIGALRM
67
#else
68
#define TIMEOUT_SIG SIGPROF
69
#endif
70
71
static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 };
72
73
324k
#define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND)
74
75
/* True globals, written only at process startup */
76
static zend_signal_entry_t global_orig_handlers[NSIG];
77
static sigset_t            global_sigmask;
78
79
/* {{{ zend_signal_handler_defer
80
 *  Blocks signals if in critical section */
81
void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context)
82
0
{
83
0
  int errno_save = errno;
84
0
  zend_signal_queue_t *queue, *qtmp;
85
86
#ifdef ZTS
87
  /* A signal could hit after TSRM shutdown, in this case globals are already freed. */
88
  if (tsrm_is_shutdown()) {
89
    /* Forward to default handler handler */
90
    zend_signal_handler(signo, siginfo, context);
91
    return;
92
  }
93
#endif
94
95
0
  if (EXPECTED(SIGG(active))) {
96
0
    if (UNEXPECTED(SIGG(depth) == 0)) { /* try to handle signal */
97
0
      if (UNEXPECTED(SIGG(blocked))) {
98
0
        SIGG(blocked) = 0;
99
0
      }
100
0
      if (EXPECTED(SIGG(running) == 0)) {
101
0
        SIGG(running) = 1;
102
0
        zend_signal_handler(signo, siginfo, context);
103
104
0
        queue = SIGG(phead);
105
0
        SIGG(phead) = NULL;
106
107
0
        while (queue) {
108
0
          zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context);
109
0
          qtmp = queue->next;
110
0
          queue->next = SIGG(pavail);
111
0
          queue->zend_signal.signo = 0;
112
0
          SIGG(pavail) = queue;
113
0
          queue = qtmp;
114
0
        }
115
0
        SIGG(running) = 0;
116
0
      }
117
0
    } else { /* delay signal handling */
118
0
      SIGG(blocked) = 1; /* signal is blocked */
119
120
0
      if ((queue = SIGG(pavail))) { /* if none available it's simply forgotton */
121
0
        SIGG(pavail) = queue->next;
122
0
        queue->zend_signal.signo = signo;
123
0
        queue->zend_signal.siginfo = siginfo;
124
0
        queue->zend_signal.context = context;
125
0
        queue->next = NULL;
126
127
0
        if (SIGG(phead) && SIGG(ptail)) {
128
0
          SIGG(ptail)->next = queue;
129
0
        } else {
130
0
          SIGG(phead) = queue;
131
0
        }
132
0
        SIGG(ptail) = queue;
133
0
      }
134
0
#if ZEND_DEBUG
135
0
      else { /* this may not be safe to do, but could work and be useful */
136
0
        zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo);
137
0
      }
138
0
#endif
139
0
    }
140
0
  } else {
141
    /* need to just run handler if we're inactive and getting a signal */
142
0
    zend_signal_handler(signo, siginfo, context);
143
0
  }
144
145
0
  errno = errno_save;
146
0
} /* }}} */
147
148
/* {{{ zend_signal_handler_unblock
149
 * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
150
ZEND_API void zend_signal_handler_unblock(void)
151
0
{
152
0
  zend_signal_queue_t *queue;
153
0
  zend_signal_t zend_signal;
154
155
0
  if (EXPECTED(SIGG(active))) {
156
0
    SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */
157
0
    queue = SIGG(phead);
158
0
    SIGG(phead) = queue->next;
159
0
    zend_signal = queue->zend_signal;
160
0
    queue->next = SIGG(pavail);
161
0
    queue->zend_signal.signo = 0;
162
0
    SIGG(pavail) = queue;
163
164
0
    zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
165
0
    SIGNAL_END_CRITICAL();
166
0
  }
167
0
}
168
/* }}} */
169
170
/* {{{ zend_signal_handler
171
 *  Call the previously registered handler for a signal
172
 */
173
static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context)
174
0
{
175
0
  int errno_save = errno;
176
0
  struct sigaction sa;
177
0
  sigset_t sigset;
178
0
  zend_signal_entry_t p_sig;
179
#ifdef ZTS
180
  if (tsrm_is_shutdown()) {
181
    p_sig.flags = 0;
182
    p_sig.handler = SIG_DFL;
183
  } else
184
#endif
185
0
  p_sig = SIGG(handlers)[signo-1];
186
187
0
  if (p_sig.handler == SIG_DFL) { /* raise default handler */
188
0
    if (sigaction(signo, NULL, &sa) == 0) {
189
0
      sa.sa_handler = SIG_DFL;
190
0
      sigemptyset(&sa.sa_mask);
191
192
0
      sigemptyset(&sigset);
193
0
      sigaddset(&sigset, signo);
194
195
0
      if (sigaction(signo, &sa, NULL) == 0) {
196
        /* throw away any blocked signals */
197
0
        zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
198
#ifdef ZTS
199
# define RAISE_ERROR "raise() failed\n"
200
        if (raise(signo) != 0) {
201
          /* On some systems raise() fails with errno 3: No such process */
202
          kill(getpid(), signo);
203
        }
204
#else
205
0
        kill(getpid(), signo);
206
0
#endif
207
0
      }
208
0
    }
209
0
  } else if (p_sig.handler != SIG_IGN) {
210
0
    if (p_sig.flags & SA_SIGINFO) {
211
0
      if (p_sig.flags & SA_RESETHAND) {
212
0
        SIGG(handlers)[signo-1].flags   = 0;
213
0
        SIGG(handlers)[signo-1].handler = SIG_DFL;
214
0
      }
215
0
      (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
216
0
    } else {
217
0
      (*(void (*)(int))p_sig.handler)(signo);
218
0
    }
219
0
  }
220
221
0
  errno = errno_save;
222
0
} /* }}} */
223
224
/* {{{ zend_sigaction
225
 *  Register a signal handler that will be deferred in critical sections */
226
ZEND_API void zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact)
227
324k
{
228
324k
  struct sigaction sa;
229
324k
  sigset_t sigset;
230
231
324k
  if (oldact != NULL) {
232
0
    oldact->sa_flags   = SIGG(handlers)[signo-1].flags;
233
0
    oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler;
234
0
    oldact->sa_mask    = global_sigmask;
235
0
  }
236
324k
  if (act != NULL) {
237
324k
    SIGG(handlers)[signo-1].flags = act->sa_flags;
238
324k
    if (act->sa_flags & SA_SIGINFO) {
239
0
      SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction;
240
324k
    } else {
241
324k
      SIGG(handlers)[signo-1].handler = (void *) act->sa_handler;
242
324k
    }
243
244
324k
    memset(&sa, 0, sizeof(sa));
245
324k
    if (SIGG(handlers)[signo-1].handler == (void *) SIG_IGN) {
246
0
      sa.sa_sigaction = (void *) SIG_IGN;
247
324k
    } else {
248
324k
      sa.sa_flags     = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
249
324k
      sa.sa_sigaction = zend_signal_handler_defer;
250
324k
      sa.sa_mask      = global_sigmask;
251
324k
    }
252
253
324k
    if (sigaction(signo, &sa, NULL) < 0) {
254
0
      zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
255
0
    }
256
257
    /* unsure this signal is not blocked */
258
324k
    sigemptyset(&sigset);
259
324k
    sigaddset(&sigset, signo);
260
324k
    zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
261
324k
  }
262
324k
}
263
/* }}} */
264
265
/* {{{ zend_signal
266
 *  Register a signal handler that will be deferred in critical sections */
267
ZEND_API void zend_signal(int signo, void (*handler)(int))
268
324k
{
269
324k
  struct sigaction sa;
270
271
324k
  memset(&sa, 0, sizeof(sa));
272
324k
  sa.sa_flags   = 0;
273
324k
  sa.sa_handler = handler;
274
324k
  sa.sa_mask    = global_sigmask;
275
276
324k
  zend_sigaction(signo, &sa, NULL);
277
324k
}
278
/* }}} */
279
280
/* {{{ zend_signal_register
281
 *  Set a handler for a signal we want to defer.
282
 *  Previously set handler must have been saved before.
283
 */
284
static zend_result zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*))
285
0
{
286
0
  struct sigaction sa;
287
288
0
  if (sigaction(signo, NULL, &sa) == 0) {
289
0
    if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) {
290
0
      return FAILURE;
291
0
    }
292
293
0
    SIGG(handlers)[signo-1].flags = sa.sa_flags;
294
0
    if (sa.sa_flags & SA_SIGINFO) {
295
0
      SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction;
296
0
    } else {
297
0
      SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler;
298
0
    }
299
300
0
    sa.sa_flags     = SA_SIGINFO; /* we'll use a siginfo handler */
301
0
    sa.sa_sigaction = handler;
302
0
    sa.sa_mask      = global_sigmask;
303
304
0
    if (sigaction(signo, &sa, NULL) < 0) {
305
0
      zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
306
0
    }
307
308
0
    return SUCCESS;
309
0
  }
310
0
  return FAILURE;
311
0
} /* }}} */
312
313
/* {{{ zend_signal_activate
314
 *  Install our signal handlers, per request */
315
void zend_signal_activate(void)
316
324k
{
317
324k
  size_t x;
318
319
324k
  memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers));
320
321
324k
  if (SIGG(reset)) {
322
0
    for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
323
0
      zend_signal_register(zend_sigs[x], zend_signal_handler_defer);
324
0
    }
325
0
  }
326
327
324k
  SIGG(active) = 1;
328
324k
  SIGG(depth)  = 0;
329
324k
} /* }}} */
330
331
/* {{{ zend_signal_deactivate */
332
void zend_signal_deactivate(void)
333
324k
{
334
324k
  if (SIGG(check)) {
335
0
    size_t x;
336
0
    struct sigaction sa;
337
338
0
    if (SIGG(depth) != 0) {
339
0
      zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth));
340
0
    }
341
342
    /* did anyone steal our installed handler */
343
0
    for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
344
0
      sigaction(zend_sigs[x], NULL, &sa);
345
0
      if (sa.sa_sigaction != zend_signal_handler_defer &&
346
0
          sa.sa_sigaction != (void *) SIG_IGN) {
347
0
        zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]);
348
0
      }
349
0
    }
350
0
  }
351
352
  /* After active=0 is set, signal handlers will be called directly and other
353
   * state that is reset below will not be accessed. */
354
324k
  *((volatile int *) &SIGG(active)) = 0;
355
356
324k
  SIGG(running) = 0;
357
324k
  SIGG(blocked) = 0;
358
324k
  SIGG(depth) = 0;
359
360
  /* If there are any queued signals because of a missed unblock, drop them. */
361
324k
  if (SIGG(phead) && SIGG(ptail)) {
362
0
    SIGG(ptail)->next = SIGG(pavail);
363
0
    SIGG(pavail) = SIGG(phead);
364
0
    SIGG(phead) = NULL;
365
0
    SIGG(ptail) = NULL;
366
0
  }
367
324k
}
368
/* }}} */
369
370
static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals) /* {{{ */
371
0
{
372
0
  size_t x;
373
374
0
  memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
375
0
  zend_signal_globals->reset = 1;
376
377
0
  for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
378
0
    zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
379
0
    queue->zend_signal.signo = 0;
380
0
    queue->next = zend_signal_globals->pavail;
381
0
    zend_signal_globals->pavail = queue;
382
0
  }
383
0
}
384
/* }}} */
385
386
void zend_signal_init(void) /* {{{ */
387
0
{
388
0
  int signo;
389
0
  struct sigaction sa;
390
391
  /* Save previously registered signal handlers into orig_handlers */
392
0
  memset(&global_orig_handlers, 0, sizeof(global_orig_handlers));
393
0
  for (signo = 1; signo < NSIG; ++signo) {
394
0
    if (sigaction(signo, NULL, &sa) == 0) {
395
0
      global_orig_handlers[signo-1].flags = sa.sa_flags;
396
0
      if (sa.sa_flags & SA_SIGINFO) {
397
0
        global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction;
398
0
      } else {
399
0
        global_orig_handlers[signo-1].handler = (void *) sa.sa_handler;
400
0
      }
401
0
    }
402
0
  }
403
0
}
404
/* }}} */
405
406
/* {{{ zend_signal_startup
407
 * alloc zend signal globals */
408
ZEND_API void zend_signal_startup(void)
409
0
{
410
411
#ifdef ZTS
412
  ts_allocate_fast_id(&zend_signal_globals_id, &zend_signal_globals_offset, sizeof(zend_signal_globals_t), (ts_allocate_ctor) zend_signal_globals_ctor, NULL);
413
#else
414
0
  zend_signal_globals_ctor(&zend_signal_globals);
415
0
#endif
416
417
  /* Used to block signals during execution of signal handlers */
418
0
  sigfillset(&global_sigmask);
419
0
  sigdelset(&global_sigmask, SIGILL);
420
0
  sigdelset(&global_sigmask, SIGABRT);
421
0
  sigdelset(&global_sigmask, SIGFPE);
422
0
  sigdelset(&global_sigmask, SIGKILL);
423
0
  sigdelset(&global_sigmask, SIGSEGV);
424
0
  sigdelset(&global_sigmask, SIGCONT);
425
0
  sigdelset(&global_sigmask, SIGSTOP);
426
0
  sigdelset(&global_sigmask, SIGTSTP);
427
0
  sigdelset(&global_sigmask, SIGTTIN);
428
0
  sigdelset(&global_sigmask, SIGTTOU);
429
0
#ifdef SIGBUS
430
0
  sigdelset(&global_sigmask, SIGBUS);
431
0
#endif
432
0
#ifdef SIGSYS
433
0
  sigdelset(&global_sigmask, SIGSYS);
434
0
#endif
435
0
#ifdef SIGTRAP
436
0
  sigdelset(&global_sigmask, SIGTRAP);
437
0
#endif
438
439
0
  zend_signal_init();
440
0
}
441
/* }}} */
442
443
444
#endif /* ZEND_SIGNALS */