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 
  39 #if (__STDC_VERSION__ >= 199901L)
  40   #include <stdbool.h>
  41 #else
  42   #define bool int
  43   #define true 1
  44   #define false 0
  45 #endif
  46 
  47 static struct sigaction sact[NSIG]; /* saved signal handlers */
  48 static sigset_t jvmsigs; /* Signals used by jvm. */
  49 
  50 #ifdef MACOSX
  51 static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
  52 #endif
  53 
  54 /* Used to synchronize the installation of signal handlers. */
  55 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  56 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  57 static pthread_t tid = 0;
  58 
  59 typedef void (*sa_handler_t)(int);
  60 typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
  61 typedef sa_handler_t (*signal_function_t)(int, sa_handler_t);
  62 typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
  63 
  64 static signal_function_t os_signal = 0; /* os's version of signal()/sigset() */
  65 static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
  66 
  67 static bool jvm_signal_installing = false;
  68 static bool jvm_signal_installed = false;
  69 
  70 static void signal_lock() {
  71   pthread_mutex_lock(&mutex);
  72   /* When the jvm is installing its set of signal handlers, threads
  73    * other than the jvm thread should wait. */
  74   if (jvm_signal_installing) {
  75     if (tid != pthread_self()) {
  76       pthread_cond_wait(&cond, &mutex);
  77     }
  78   }
  79 }
  80 
  81 static void signal_unlock() {
  82   pthread_mutex_unlock(&mutex);
  83 }
  84 
  85 static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
  86                                    bool is_sigset) {
  87   sa_handler_t res;
  88 
  89   if (os_signal == NULL) {
  90     if (!is_sigset) {
  91       os_signal = (signal_function_t)dlsym(RTLD_NEXT, "signal");
  92     } else {
  93       os_signal = (signal_function_t)dlsym(RTLD_NEXT, "sigset");
  94     }
  95     if (os_signal == NULL) {
  96       printf("%s\n", dlerror());
  97       exit(0);
  98     }
  99   }
 100 
 101 #ifdef MACOSX
 102   /* On macosx, the OS implementation of signal calls sigaction.
 103    * Make sure we do not deadlock with ourself. (See JDK-8072147). */
 104   reentry = true;
 105 #endif
 106 
 107   res = (*os_signal)(sig, disp);
 108 
 109 #ifdef MACOSX
 110   reentry = false;
 111 #endif
 112 
 113   return res;
 114 }
 115 
 116 static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
 117   sigset_t set;
 118   sact[sig].sa_handler = disp;
 119   sigemptyset(&set);
 120   sact[sig].sa_mask = set;
 121   if (!is_sigset) {
 122 #ifdef SOLARIS
 123     sact[sig].sa_flags = SA_NODEFER;
 124     if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
 125       sact[sig].sa_flags |= SA_RESETHAND;
 126     }
 127 #else
 128     sact[sig].sa_flags = 0;
 129 #endif
 130   } else {
 131     sact[sig].sa_flags = 0;
 132   }
 133 }
 134 
 135 static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
 136   sa_handler_t oldhandler;
 137   bool sigused;
 138   bool sigblocked;
 139 
 140   signal_lock();
 141 
 142   sigused = sigismember(&jvmsigs, sig);
 143   if (jvm_signal_installed && sigused) {
 144     /* jvm has installed its signal handler for this signal. */
 145     /* Save the handler. Don't really install it. */
 146     if (is_sigset) {
 147       sigblocked = sigismember(&(sact[sig].sa_mask), sig);
 148     }
 149     oldhandler = sact[sig].sa_handler;
 150     save_signal_handler(sig, disp, is_sigset);
 151 
 152 #ifdef SOLARIS
 153     if (is_sigset && sigblocked) {
 154       /* We won't honor the SIG_HOLD request to change the signal mask */
 155       oldhandler = SIG_HOLD;
 156     }
 157 #endif
 158 
 159     signal_unlock();
 160     return oldhandler;
 161   } else if (jvm_signal_installing) {
 162     /* jvm is installing its signal handlers. Install the new
 163      * handlers and save the old ones. jvm uses sigaction().
 164      * Leave the piece here just in case. */
 165     oldhandler = call_os_signal(sig, disp, is_sigset);
 166     save_signal_handler(sig, oldhandler, is_sigset);
 167 
 168     /* Record the signals used by jvm */
 169     sigaddset(&jvmsigs, sig);
 170 
 171     signal_unlock();
 172     return oldhandler;
 173   } else {
 174     /* jvm has no relation with this signal (yet). Install the
 175      * the handler. */
 176     oldhandler = call_os_signal(sig, disp, is_sigset);
 177 
 178     signal_unlock();
 179     return oldhandler;
 180   }
 181 }
 182 
 183 sa_handler_t signal(int sig, sa_handler_t disp) {
 184   if (sig < 0 || sig >= NSIG) {
 185     errno = EINVAL;
 186     return SIG_ERR;
 187   }
 188 
 189   return set_signal(sig, disp, false);
 190 }
 191 
 192 sa_handler_t sigset(int sig, sa_handler_t disp) {
 193 #ifdef _ALLBSD_SOURCE
 194   printf("sigset() is not supported by BSD");
 195   exit(0);
 196 #else
 197   if (sig < 0 || sig >= NSIG) {
 198     errno = EINVAL;
 199     return (sa_handler_t)-1;
 200   }
 201 
 202   return set_signal(sig, disp, true);
 203 #endif
 204 }
 205 
 206 static int call_os_sigaction(int sig, const struct sigaction  *act,
 207                              struct sigaction *oact) {
 208   if (os_sigaction == NULL) {
 209     os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
 210     if (os_sigaction == NULL) {
 211       printf("%s\n", dlerror());
 212       exit(0);
 213     }
 214   }
 215   return (*os_sigaction)(sig, act, oact);
 216 }
 217 
 218 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
 219   int res;
 220   bool sigused;
 221   struct sigaction oldAct;
 222 
 223   if (sig < 0 || sig >= NSIG) {
 224     errno = EINVAL;
 225     return -1;
 226   }
 227 
 228 #ifdef MACOSX
 229   if (reentry) {
 230     return call_os_sigaction(sig, act, oact);
 231   }
 232 #endif
 233 
 234   signal_lock();
 235 
 236   sigused = sigismember(&jvmsigs, sig);
 237   if (jvm_signal_installed && sigused) {
 238     /* jvm has installed its signal handler for this signal. */
 239     /* Save the handler. Don't really install it. */
 240     if (oact != NULL) {
 241       *oact = sact[sig];
 242     }
 243     if (act != NULL) {
 244       sact[sig] = *act;
 245     }
 246 
 247     signal_unlock();
 248     return 0;
 249   } else if (jvm_signal_installing) {
 250     /* jvm is installing its signal handlers. Install the new
 251      * handlers and save the old ones. */
 252     res = call_os_sigaction(sig, act, &oldAct);
 253     sact[sig] = oldAct;
 254     if (oact != NULL) {
 255       *oact = oldAct;
 256     }
 257 
 258     /* Record the signals used by jvm. */
 259     sigaddset(&jvmsigs, sig);
 260 
 261     signal_unlock();
 262     return res;
 263   } else {
 264     /* jvm has no relation with this signal (yet). Install the
 265      * the handler. */
 266     res = call_os_sigaction(sig, act, oact);
 267 
 268     signal_unlock();
 269     return res;
 270   }
 271 }
 272 
 273 /* The three functions for the jvm to call into. */
 274 void JVM_begin_signal_setting() {
 275   signal_lock();
 276   sigemptyset(&jvmsigs);
 277   jvm_signal_installing = true;
 278   tid = pthread_self();
 279   signal_unlock();
 280 }
 281 
 282 void JVM_end_signal_setting() {
 283   signal_lock();
 284   jvm_signal_installed = true;
 285   jvm_signal_installing = false;
 286   pthread_cond_broadcast(&cond);
 287   signal_unlock();
 288 }
 289 
 290 struct sigaction *JVM_get_signal_action(int sig) {
 291   /* Does race condition make sense here? */
 292   if (sigismember(&jvmsigs, sig)) {
 293     return &sact[sig];
 294   }
 295   return NULL;
 296 }