back to topotato report
topotato coverage report
Current view: top level - lib - sigevent.c (source / functions) Hit Total Coverage
Test: test_pim_cbsr.py::PIMCandidateBSRTest Lines: 78 104 75.0 %
Date: 2023-02-16 02:09:14 Functions: 6 8 75.0 %

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

Generated by: LCOV version v1.16-topotato