/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "incfs_support/signal_handling.h" #if defined(__BIONIC__) && !INCFS_SUPPORT_DISABLED #include namespace incfs { static void enableSignal(int code) { sigset_t allowed; sigemptyset(&allowed); sigaddset(&allowed, code); pthread_sigmask(SIG_UNBLOCK, &allowed, nullptr); } ScopedJmpBuf::~ScopedJmpBuf() { SignalHandler::mJmpBuf = mPrev; } SignalHandler& SignalHandler::instance() { static SignalHandler self; return self; } SignalHandler::SignalHandler() { const struct sigaction action = { .sa_sigaction = &handler, .sa_flags = SA_SIGINFO, }; if (sigaction(SIGBUS, &action, &mOldSigaction)) { LOG_ALWAYS_FATAL("sigaction(SIGBUS) failed: %d", errno); // not much can be done now return; } // ensure SIGBUS is unblocked, so the process won't get insta-killed enableSignal(SIGBUS); } void SignalHandler::handler(int sig, siginfo_t* info, void* ucontext) { if (sig != SIGBUS) { LOG_FATAL("SIGBUS handler called for unexpected signal %d", sig); return; } if (!mJmpBuf.armed) { // No error handler installed - run the previous one if (mOldSigaction.sa_handler == SIG_DFL) { // reset the action to default and re-raise the signal. It will kill the // process signal(sig, SIG_DFL); raise(sig); return; } if (mOldSigaction.sa_handler == SIG_IGN) { // ignoring SIGBUS won't help us much, as we'll get back right here after // retrying. return; } if (mOldSigaction.sa_flags & SA_SIGINFO) { mOldSigaction.sa_sigaction(sig, info, ucontext); } else { mOldSigaction.sa_handler(sig); } // Returning from a signal handler for SIGBUS is undefined, but if it // happens better to at least forward that undefined thing further. Who are // we to argue with the user? return; } // restore SIGBUS as signal handling blocks it before running the callback enableSignal(SIGBUS); longjmp(mJmpBuf.buf, 1); } } // namespace incfs #endif