back to topotato report
topotato coverage report
Current view: top level - lib - sigevent.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 78 104 75.0 %
Date: 2023-11-16 17:19:14 Functions: 6 16 37.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* Quagga signal handling functions.
       3             :  * Copyright (C) 2004 Paul Jakma,
       4             :  */
       5             : 
       6             : #include <zebra.h>
       7             : #include <sigevent.h>
       8             : #include <log.h>
       9             : #include <memory.h>
      10             : #include <lib_errors.h>
      11             : 
      12             : #ifdef HAVE_UCONTEXT_H
      13             : #ifdef GNU_LINUX
      14             : /* get REG_EIP from ucontext.h */
      15             : #ifndef __USE_GNU
      16             : #define __USE_GNU
      17             : #endif /* __USE_GNU */
      18             : #endif /* GNU_LINUX */
      19             : #include <ucontext.h>
      20             : #endif /* HAVE_UCONTEXT_H */
      21             : 
      22             : 
      23             : /* master signals descriptor struct */
      24             : static struct frr_sigevent_master_t {
      25             :         struct event *t;
      26             : 
      27             :         struct frr_signal_t *signals;
      28             :         int sigc;
      29             : 
      30             :         volatile sig_atomic_t caught;
      31             : } sigmaster;
      32             : 
      33             : /* Generic signal handler
      34             :  * Schedules signal event thread
      35             :  */
      36           4 : static void frr_signal_handler(int signo)
      37             : {
      38           4 :         int i;
      39           4 :         struct frr_signal_t *sig;
      40             : 
      41          20 :         for (i = 0; i < sigmaster.sigc; i++) {
      42          16 :                 sig = &(sigmaster.signals[i]);
      43             : 
      44          16 :                 if (sig->signal == signo)
      45           4 :                         sig->caught = 1;
      46             :         }
      47             : 
      48           4 :         sigmaster.caught = 1;
      49           4 : }
      50             : 
      51             : /*
      52             :  * Check whether any signals have been received and are pending. This is done
      53             :  * with the application's key signals blocked. The complete set of signals
      54             :  * is returned in 'setp', so the caller can restore them when appropriate.
      55             :  * If there are pending signals, returns 'true', 'false' otherwise.
      56             :  */
      57        6529 : bool frr_sigevent_check(sigset_t *setp)
      58             : {
      59        6529 :         sigset_t blocked;
      60        6529 :         int i;
      61        6529 :         bool ret;
      62             : 
      63        6529 :         sigemptyset(setp);
      64        6529 :         sigemptyset(&blocked);
      65             : 
      66             :         /* Set up mask of application's signals */
      67       39174 :         for (i = 0; i < sigmaster.sigc; i++)
      68       26116 :                 sigaddset(&blocked, sigmaster.signals[i].signal);
      69             : 
      70        6529 :         pthread_sigmask(SIG_BLOCK, &blocked, setp);
      71             : 
      72             :         /* Now that the application's signals are blocked, test. */
      73        6529 :         ret = (sigmaster.caught != 0);
      74             : 
      75        6529 :         return ret;
      76             : }
      77             : 
      78             : /* check if signals have been caught and run appropriate handlers */
      79        6971 : int frr_sigevent_process(void)
      80             : {
      81        6971 :         struct frr_signal_t *sig;
      82        6971 :         int i;
      83             : #ifdef SIGEVENT_BLOCK_SIGNALS
      84             :         /* shouldn't need to block signals, but potentially may be needed */
      85             :         sigset_t newmask, oldmask;
      86             : 
      87             :         /*
      88             :          * Block most signals, but be careful not to defer SIGTRAP because
      89             :          * doing so breaks gdb, at least on NetBSD 2.0.  Avoid asking to
      90             :          * block SIGKILL, just because we shouldn't be able to do so.
      91             :          */
      92             :         sigfillset(&newmask);
      93             :         sigdelset(&newmask, SIGTRAP);
      94             :         sigdelset(&newmask, SIGKILL);
      95             : 
      96             :         if ((sigprocmask(SIG_BLOCK, &newmask, &oldmask)) < 0) {
      97             :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
      98             :                              "frr_signal_timer: couldnt block signals!");
      99             :                 return -1;
     100             :         }
     101             : #endif /* SIGEVENT_BLOCK_SIGNALS */
     102             : 
     103        6971 :         if (sigmaster.caught > 0) {
     104           4 :                 sigmaster.caught = 0;
     105             :                 /* must not read or set sigmaster.caught after here,
     106             :                  * race condition with per-sig caught flags if one does
     107             :                  */
     108             : 
     109          18 :                 for (i = 0; i < sigmaster.sigc; i++) {
     110          16 :                         sig = &(sigmaster.signals[i]);
     111             : 
     112          16 :                         if (sig->caught > 0) {
     113           4 :                                 sig->caught = 0;
     114           4 :                                 if (sig->handler)
     115           4 :                                         sig->handler();
     116             :                         }
     117             :                 }
     118             :         }
     119             : 
     120             : #ifdef SIGEVENT_BLOCK_SIGNALS
     121             :         if (sigprocmask(SIG_UNBLOCK, &oldmask, NULL) < 0)
     122             :                 return -1;
     123             : #endif /* SIGEVENT_BLOCK_SIGNALS */
     124             : 
     125        6969 :         return 0;
     126             : }
     127             : 
     128             : #ifdef SIGEVENT_SCHEDULE_THREAD
     129             : /* timer thread to check signals. shouldn't be needed */
     130             : void frr_signal_timer(struct event *t)
     131             : {
     132             :         struct frr_sigevent_master_t *sigm;
     133             : 
     134             :         sigm = EVENT_ARG(t);
     135             :         sigm->t = NULL;
     136             :         event_add_timer(sigm->t->master, frr_signal_timer, &sigmaster,
     137             :                         FRR_SIGNAL_TIMER_INTERVAL, &sigm->t);
     138             :         frr_sigevent_process();
     139             : }
     140             : #endif /* SIGEVENT_SCHEDULE_THREAD */
     141             : 
     142             : /* Initialization of signal handles. */
     143             : /* Signal wrapper. */
     144          16 : static int signal_set(int signo)
     145             : {
     146          16 :         int ret;
     147          16 :         struct sigaction sig;
     148          16 :         struct sigaction osig;
     149             : 
     150          16 :         sig.sa_handler = &frr_signal_handler;
     151          16 :         sigfillset(&sig.sa_mask);
     152          16 :         sig.sa_flags = 0;
     153          16 :         if (signo == SIGALRM) {
     154             : #ifdef SA_INTERRUPT
     155           0 :                 sig.sa_flags |= SA_INTERRUPT; /* SunOS */
     156             : #endif
     157             :         } else {
     158             : #ifdef SA_RESTART
     159          16 :                 sig.sa_flags |= SA_RESTART;
     160             : #endif /* SA_RESTART */
     161             :         }
     162             : 
     163          16 :         ret = sigaction(signo, &sig, &osig);
     164          16 :         if (ret < 0)
     165             :                 return ret;
     166             :         else
     167          16 :                 return 0;
     168             : }
     169             : 
     170             : /* XXX This function should be enhanced to support more platforms
     171             :        (it currently works only on Linux/x86). */
     172           0 : static void *program_counter(void *context)
     173             : {
     174             : #ifdef HAVE_UCONTEXT_H
     175             : #ifdef GNU_LINUX
     176             : /* these are from GNU libc, rather than Linux, strictly speaking */
     177             : #if defined(REG_EIP)
     178             : #  define REG_INDEX REG_EIP
     179             : #elif defined(REG_RIP)
     180             : #  define REG_INDEX REG_RIP
     181             : #elif defined(__powerpc__)
     182             : #  define REG_INDEX 32
     183             : #endif
     184             : #endif                 /* GNU_LINUX */
     185             : 
     186             : #ifdef REG_INDEX
     187             : #ifdef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS
     188             : #  define REGS gregs[REG_INDEX]
     189             : #elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS)
     190             : #  define REGS uc_regs->gregs[REG_INDEX]
     191             : #endif /* HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS */
     192             : #endif /* REG_INDEX */
     193             : 
     194             : #ifdef REGS
     195           0 :         if (context)
     196           0 :                 return (void *)(((ucontext_t *)context)->uc_mcontext.REGS);
     197             : #elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_REGS__NIP)
     198             :         /* older Linux / struct pt_regs ? */
     199             :         if (context)
     200             :                 return (void *)(((ucontext_t *)context)->uc_mcontext.regs->nip);
     201             : #endif /* REGS */
     202             : 
     203             : #endif /* HAVE_UCONTEXT_H */
     204             :         return NULL;
     205             : }
     206             : 
     207             : static void __attribute__((noreturn))
     208           0 : exit_handler(int signo, siginfo_t *siginfo, void *context)
     209             : {
     210           0 :         void *pc = program_counter(context);
     211             : 
     212           0 :         zlog_signal(signo, "exiting...", siginfo, pc);
     213           0 :         _exit(128 + signo);
     214             : }
     215             : 
     216             : static void __attribute__((noreturn))
     217           0 : core_handler(int signo, siginfo_t *siginfo, void *context)
     218             : {
     219           0 :         void *pc = program_counter(context);
     220             : 
     221             :         /* make sure we don't hang in here.  default for SIGALRM is terminate.
     222             :          * - if we're in backtrace for more than a second, abort. */
     223           0 :         struct sigaction sa_default = {.sa_handler = SIG_DFL};
     224             : 
     225           0 :         sigaction(SIGALRM, &sa_default, NULL);
     226           0 :         sigaction(signo, &sa_default, NULL);
     227             : 
     228           0 :         sigset_t sigset;
     229             : 
     230           0 :         sigemptyset(&sigset);
     231           0 :         sigaddset(&sigset, SIGALRM);
     232           0 :         sigprocmask(SIG_UNBLOCK, &sigset, NULL);
     233             : 
     234           0 :         alarm(1);
     235             : 
     236           0 :         zlog_signal(signo, "aborting...", siginfo, pc);
     237             : 
     238             :         /* dump memory stats on core */
     239           0 :         log_memstats(stderr, "core_handler");
     240             : 
     241           0 :         zlog_tls_buffer_fini();
     242             : 
     243             :         /* give the kernel a chance to generate a coredump */
     244           0 :         sigaddset(&sigset, signo);
     245           0 :         sigprocmask(SIG_UNBLOCK, &sigset, NULL);
     246           0 :         raise(signo);
     247             : 
     248             :         /* only chance to end up here is if the default action for signo is
     249             :          * something other than kill or coredump the process
     250             :          */
     251           0 :         _exit(128 + signo);
     252             : }
     253             : 
     254           4 : static void trap_default_signals(void)
     255             : {
     256           4 :         static const int core_signals[] = {
     257             :                 SIGQUIT, SIGILL, SIGABRT,
     258             : #ifdef SIGEMT
     259             :                 SIGEMT,
     260             : #endif
     261             :                 SIGFPE,  SIGBUS, SIGSEGV,
     262             : #ifdef SIGSYS
     263             :                 SIGSYS,
     264             : #endif
     265             : #ifdef SIGXCPU
     266             :                 SIGXCPU,
     267             : #endif
     268             : #ifdef SIGXFSZ
     269             :                 SIGXFSZ,
     270             : #endif
     271             :         };
     272           4 :         static const int exit_signals[] = {
     273             :                 SIGHUP,    SIGINT, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2,
     274             : #ifdef SIGPOLL
     275             :                 SIGPOLL,
     276             : #endif
     277             : #ifdef SIGVTALRM
     278             :                 SIGVTALRM,
     279             : #endif
     280             : #ifdef SIGSTKFLT
     281             :                 SIGSTKFLT,
     282             : #endif
     283             :         };
     284           4 :         static const int ignore_signals[] = {
     285             :                 SIGPIPE,
     286             :         };
     287           4 :         static const struct {
     288             :                 const int *sigs;
     289             :                 unsigned int nsigs;
     290             :                 void (*handler)(int signo, siginfo_t *info, void *context);
     291             :         } sigmap[] = {
     292             :                 {core_signals, array_size(core_signals), core_handler},
     293             :                 {exit_signals, array_size(exit_signals), exit_handler},
     294             :                 {ignore_signals, array_size(ignore_signals), NULL},
     295             :         };
     296           4 :         unsigned int i;
     297             : 
     298          16 :         for (i = 0; i < array_size(sigmap); i++) {
     299             :                 unsigned int j;
     300             : 
     301          88 :                 for (j = 0; j < sigmap[i].nsigs; j++) {
     302          76 :                         struct sigaction oact;
     303          76 :                         if ((sigaction(sigmap[i].sigs[j], NULL, &oact) == 0)
     304          76 :                             && (oact.sa_handler == SIG_DFL)) {
     305          76 :                                 struct sigaction act;
     306          76 :                                 sigfillset(&act.sa_mask);
     307          76 :                                 if (sigmap[i].handler == NULL) {
     308           4 :                                         act.sa_handler = SIG_IGN;
     309           4 :                                         act.sa_flags = 0;
     310             :                                 } else {
     311             :                                         /* Request extra arguments to signal
     312             :                                          * handler. */
     313          72 :                                         act.sa_sigaction = sigmap[i].handler;
     314          72 :                                         act.sa_flags = SA_SIGINFO;
     315             : #ifdef SA_RESETHAND
     316             :                                         /* don't try to print backtraces
     317             :                                          * recursively */
     318          72 :                                         if (sigmap[i].handler == core_handler)
     319          36 :                                                 act.sa_flags |= SA_RESETHAND;
     320             : #endif
     321             :                                 }
     322          76 :                                 if (sigaction(sigmap[i].sigs[j], &act, NULL)
     323             :                                     < 0)
     324          76 :                                         flog_err(
     325             :                                                 EC_LIB_SYSTEM_CALL,
     326             :                                                 "Unable to set signal handler for signal %d: %s",
     327             :                                                 sigmap[i].sigs[j],
     328             :                                                 safe_strerror(errno));
     329             :                         }
     330             :                 }
     331             :         }
     332           4 : }
     333             : 
     334           4 : void signal_init(struct event_loop *m, int sigc, struct frr_signal_t signals[])
     335             : {
     336             : 
     337           4 :         int i = 0;
     338           4 :         struct frr_signal_t *sig;
     339             : 
     340             :         /* First establish some default handlers that can be overridden by
     341             :            the application. */
     342           4 :         trap_default_signals();
     343             : 
     344          20 :         while (i < sigc) {
     345          16 :                 sig = &signals[i];
     346          16 :                 if (signal_set(sig->signal) < 0)
     347           0 :                         exit(-1);
     348          16 :                 i++;
     349             :         }
     350             : 
     351           4 :         sigmaster.sigc = sigc;
     352           4 :         sigmaster.signals = signals;
     353             : 
     354             : #ifdef SIGEVENT_SCHEDULE_THREAD
     355             :         sigmaster.t = NULL;
     356             :         event_add_timer(m, frr_signal_timer, &sigmaster,
     357             :                         FRR_SIGNAL_TIMER_INTERVAL, &sigmaster.t);
     358             : #endif /* SIGEVENT_SCHEDULE_THREAD */
     359           4 : }

Generated by: LCOV version v1.16-topotato