1 /*
   2  * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 /* This is a special library that should be loaded before libc &
  27  * libthread to interpose the signal handler installation functions:
  28  * sigaction(), signal(), sigset().
  29  * Used for signal-chaining. See RFE 4381843.
  30  */
  31 
  32 #include <dlfcn.h>
  33 #include <errno.h>
  34 #include <pthread.h>
  35 #include <signal.h>
  36 #include <stdio.h>
  37 #include <stdlib.h>
  38 #include <string.h>
  39 
  40 #if (__STDC_VERSION__ >= 199901L)
  41   #include <stdbool.h>
  42 #else
  43   #define bool int
  44   #define true 1
  45   #define false 0
  46 #endif
  47 
  48 #ifdef SOLARIS
  49 #define MAX_SIGNALS (SIGRTMAX+1)
  50 
  51 /* On solaris, MAX_SIGNALS is a macro, not a constant, so we must allocate sact dynamically. */
  52 static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
  53 #else
  54 #define MAX_SIGNALS NSIG
  55 
  56 static struct sigaction sact[MAX_SIGNALS]; /* saved signal handlers */
  57 #endif
  58 
  59 static sigset_t jvmsigs; /* Signals used by jvm. */
  60 
  61 #ifdef MACOSX
  62 static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
  63 #endif
  64 
  65 /* Used to synchronize the installation of signal handlers. */
  66 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  67 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  68 static pthread_t tid = 0;
  69 
  70 typedef void (*sa_handler_t)(int);
  71 typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
  72 typedef sa_handler_t (*signal_function_t)(int, sa_handler_t);
  73 typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
  74 
  75 static signal_function_t os_signal = 0; /* os's version of signal()/sigset() */
  76 static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
  77 
  78 static bool jvm_signal_installing = false;
  79 static bool jvm_signal_installed = false;
  80 
  81 
  82 /* assume called within signal_lock */
  83 static void allocate_sact() {
  84 #ifdef SOLARIS
  85   if (sact == NULL) {
  86     sact = (struct sigaction *)malloc((MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
  87     if (sact == NULL) {
  88       printf("%s\n", "libjsig.so unable to allocate memory");
  89       exit(0);
  90     }
  91     memset(sact, 0, (MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
  92   }
  93 #endif
  94 }
  95 
  96 static void signal_lock() {
  97   pthread_mutex_lock(&mutex);
  98   /* When the jvm is installing its set of signal handlers, threads
  99    * other than the jvm thread should wait. */
 100   if (jvm_signal_installing) {
 101     if (tid != pthread_self()) {
 102       pthread_cond_wait(&cond, &mutex);
 103     }
 104   }
 105 }
 106 
 107 static void signal_unlock() {
 108   pthread_mutex_unlock(&mutex);
 109 }
 110 
 111 static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
 112                                    bool is_sigset) {
 113   sa_handler_t res;
 114 
 115   if (os_signal == NULL) {
 116     if (!is_sigset) {
 117       os_signal = (signal_function_t)dlsym(RTLD_NEXT, "signal");
 118     } else {
 119       os_signal = (signal_function_t)dlsym(RTLD_NEXT, "sigset");
 120     }
 121     if (os_signal == NULL) {
 122       printf("%s\n", dlerror());
 123       exit(0);
 124     }
 125   }
 126 
 127 #ifdef MACOSX
 128   /* On macosx, the OS implementation of signal calls sigaction.
 129    * Make sure we do not deadlock with ourself. (See JDK-8072147). */
 130   reentry = true;
 131 #endif
 132 
 133   res = (*os_signal)(sig, disp);
 134 
 135 #ifdef MACOSX
 136   reentry = false;
 137 #endif
 138 
 139   return res;
 140 }
 141 
 142 static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
 143   sigset_t set;
 144 
 145   sact[sig].sa_handler = disp;
 146   sigemptyset(&set);
 147   sact[sig].sa_mask = set;
 148   if (!is_sigset) {
 149 #ifdef SOLARIS
 150     sact[sig].sa_flags = SA_NODEFER;
 151     if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
 152       sact[sig].sa_flags |= SA_RESETHAND;
 153     }
 154 #else
 155     sact[sig].sa_flags = 0;
 156 #endif
 157   } else {
 158     sact[sig].sa_flags = 0;
 159   }
 160 }
 161 
 162 static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
 163   sa_handler_t oldhandler;
 164   bool sigused;
 165   bool sigblocked;
 166 
 167   signal_lock();
 168   allocate_sact();
 169 
 170   sigused = sigismember(&jvmsigs, sig);
 171   if (jvm_signal_installed && sigused) {
 172     /* jvm has installed its signal handler for this signal. */
 173     /* Save the handler. Don't really install it. */
 174     if (is_sigset) {
 175       sigblocked = sigismember(&(sact[sig].sa_mask), sig);
 176     }
 177     oldhandler = sact[sig].sa_handler;
 178     save_signal_handler(sig, disp, is_sigset);
 179 
 180 #ifdef SOLARIS
 181     if (is_sigset && sigblocked) {
 182       /* We won't honor the SIG_HOLD request to change the signal mask */
 183       oldhandler = SIG_HOLD;
 184     }
 185 #endif
 186 
 187     signal_unlock();
 188     return oldhandler;
 189   } else if (jvm_signal_installing) {
 190     /* jvm is installing its signal handlers. Install the new
 191      * handlers and save the old ones. jvm uses sigaction().
 192      * Leave the piece here just in case. */
 193     oldhandler = call_os_signal(sig, disp, is_sigset);
 194     save_signal_handler(sig, oldhandler, is_sigset);
 195 
 196     /* Record the signals used by jvm */
 197     sigaddset(&jvmsigs, sig);
 198 
 199     signal_unlock();
 200     return oldhandler;
 201   } else {
 202     /* jvm has no relation with this signal (yet). Install the
 203      * the handler. */
 204     oldhandler = call_os_signal(sig, disp, is_sigset);
 205 
 206     signal_unlock();
 207     return oldhandler;
 208   }
 209 }
 210 
 211 sa_handler_t signal(int sig, sa_handler_t disp) {
 212   if (sig < 0 || sig >= MAX_SIGNALS) {
 213     errno = EINVAL;
 214     return SIG_ERR;
 215   }
 216 
 217   return set_signal(sig, disp, false);
 218 }
 219 
 220 sa_handler_t sigset(int sig, sa_handler_t disp) {
 221 #ifdef _ALLBSD_SOURCE
 222   printf("sigset() is not supported by BSD");
 223   exit(0);
 224 #else
 225   if (sig < 0 || sig >= MAX_SIGNALS) {
 226     errno = EINVAL;
 227     return (sa_handler_t)-1;
 228   }
 229 
 230   return set_signal(sig, disp, true);
 231 #endif
 232 }
 233 
 234 static int call_os_sigaction(int sig, const struct sigaction  *act,
 235                              struct sigaction *oact) {
 236   if (os_sigaction == NULL) {
 237     os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
 238     if (os_sigaction == NULL) {
 239       printf("%s\n", dlerror());
 240       exit(0);
 241     }
 242   }
 243   return (*os_sigaction)(sig, act, oact);
 244 }
 245 
 246 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
 247   int res;
 248   bool sigused;
 249   struct sigaction oldAct;
 250 
 251   if (sig < 0 || sig >= MAX_SIGNALS) {
 252     errno = EINVAL;
 253     return -1;
 254   }
 255 
 256 #ifdef MACOSX
 257   if (reentry) {
 258     return call_os_sigaction(sig, act, oact);
 259   }
 260 #endif
 261 
 262   signal_lock();
 263 
 264   allocate_sact();
 265   sigused = sigismember(&jvmsigs, sig);
 266   if (jvm_signal_installed && sigused) {
 267     /* jvm has installed its signal handler for this signal. */
 268     /* Save the handler. Don't really install it. */
 269     if (oact != NULL) {
 270       *oact = sact[sig];
 271     }
 272     if (act != NULL) {
 273       sact[sig] = *act;
 274     }
 275 
 276     signal_unlock();
 277     return 0;
 278   } else if (jvm_signal_installing) {
 279     /* jvm is installing its signal handlers. Install the new
 280      * handlers and save the old ones. */
 281     res = call_os_sigaction(sig, act, &oldAct);
 282     sact[sig] = oldAct;
 283     if (oact != NULL) {
 284       *oact = oldAct;
 285     }
 286 
 287     /* Record the signals used by jvm. */
 288     sigaddset(&jvmsigs, sig);
 289 
 290     signal_unlock();
 291     return res;
 292   } else {
 293     /* jvm has no relation with this signal (yet). Install the
 294      * the handler. */
 295     res = call_os_sigaction(sig, act, oact);
 296 
 297     signal_unlock();
 298     return res;
 299   }
 300 }
 301 
 302 /* The three functions for the jvm to call into. */
 303 void JVM_begin_signal_setting() {
 304   signal_lock();
 305   sigemptyset(&jvmsigs);
 306   jvm_signal_installing = true;
 307   tid = pthread_self();
 308   signal_unlock();
 309 }
 310 
 311 void JVM_end_signal_setting() {
 312   signal_lock();
 313   jvm_signal_installed = true;
 314   jvm_signal_installing = false;
 315   pthread_cond_broadcast(&cond);
 316   signal_unlock();
 317 }
 318 
 319 struct sigaction *JVM_get_signal_action(int sig) {
 320   allocate_sact();
 321   /* Does race condition make sense here? */
 322   if (sigismember(&jvmsigs, sig)) {
 323     return &sact[sig];
 324   }
 325   return NULL;
 326 }