Merge "Filter out reserved signals in functions that take sigset_t."
am: efa792be64
Change-Id: Ie63dc7e4c77b09032526873247311bac8d865e37
This commit is contained in:
commit
3e75f6d090
8 changed files with 316 additions and 21 deletions
|
@ -28,14 +28,8 @@
|
|||
|
||||
#include <signal.h>
|
||||
|
||||
// Realtime signals reserved for internal use:
|
||||
// 32 (__SIGRTMIN + 0) POSIX timers
|
||||
// 33 (__SIGRTMIN + 1) libbacktrace
|
||||
// 34 (__SIGRTMIN + 2) libcore
|
||||
// 35 (__SIGRTMIN + 3) debuggerd -b
|
||||
#include "private/sigrtmin.h"
|
||||
|
||||
int __libc_current_sigrtmin(void) {
|
||||
// If you change this, also change __ndk_legacy___libc_current_sigrtmin
|
||||
// in <android/legacy_signal_inlines.h> to match.
|
||||
return __SIGRTMIN + 4;
|
||||
int __libc_current_sigrtmin() {
|
||||
return __SIGRTMIN + __SIGRT_RESERVED;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <sys/select.h>
|
||||
|
||||
#include "private/bionic_time_conversions.h"
|
||||
#include "private/sigrtmin.h"
|
||||
#include "private/SigSetConverter.h"
|
||||
|
||||
extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t);
|
||||
|
@ -66,7 +67,15 @@ int ppoll64(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset64_t*
|
|||
mutable_ts = *ts;
|
||||
mutable_ts_ptr = &mutable_ts;
|
||||
}
|
||||
return __ppoll(fds, fd_count, mutable_ts_ptr, ss, sizeof(*ss));
|
||||
|
||||
sigset64_t mutable_ss;
|
||||
sigset64_t* mutable_ss_ptr = nullptr;
|
||||
if (ss != nullptr) {
|
||||
mutable_ss = filter_reserved_signals(*ss);
|
||||
mutable_ss_ptr = &mutable_ss;
|
||||
}
|
||||
|
||||
return __ppoll(fds, fd_count, mutable_ts_ptr, mutable_ss_ptr, sizeof(*mutable_ss_ptr));
|
||||
}
|
||||
|
||||
int select(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, timeval* tv) {
|
||||
|
@ -109,6 +118,13 @@ int pselect64(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_f
|
|||
mutable_ts_ptr = &mutable_ts;
|
||||
}
|
||||
|
||||
sigset64_t mutable_ss;
|
||||
sigset64_t* mutable_ss_ptr = nullptr;
|
||||
if (ss != nullptr) {
|
||||
mutable_ss = filter_reserved_signals(*ss);
|
||||
mutable_ss_ptr = &mutable_ss;
|
||||
}
|
||||
|
||||
// The Linux kernel only handles 6 arguments and this system call really needs 7,
|
||||
// so the last argument is a void* pointing to:
|
||||
struct pselect6_extra_data_t {
|
||||
|
@ -116,8 +132,8 @@ int pselect64(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_f
|
|||
size_t ss_len;
|
||||
};
|
||||
pselect6_extra_data_t extra_data;
|
||||
extra_data.ss_addr = reinterpret_cast<uintptr_t>(ss);
|
||||
extra_data.ss_len = sizeof(*ss);
|
||||
extra_data.ss_addr = reinterpret_cast<uintptr_t>(mutable_ss_ptr);
|
||||
extra_data.ss_len = sizeof(*mutable_ss_ptr);
|
||||
|
||||
return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <time.h>
|
||||
|
||||
// System calls.
|
||||
extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
|
||||
extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t);
|
||||
extern "C" int __timer_create(clockid_t, sigevent*, __kernel_timer_t*);
|
||||
extern "C" int __timer_delete(__kernel_timer_t);
|
||||
extern "C" int __timer_getoverrun(__kernel_timer_t);
|
||||
|
@ -77,7 +79,7 @@ static void* __timer_thread_start(void* arg) {
|
|||
while (true) {
|
||||
// Wait for a signal...
|
||||
siginfo_t si = {};
|
||||
if (sigtimedwait64(&sigset, &si, nullptr) == -1) continue;
|
||||
if (__rt_sigtimedwait(&sigset, &si, nullptr, sizeof(sigset)) == -1) continue;
|
||||
|
||||
if (si.si_code == SI_TIMER) {
|
||||
// This signal was sent because a timer fired, so call the callback.
|
||||
|
@ -146,11 +148,13 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) {
|
|||
sigset64_t sigset = {};
|
||||
sigaddset64(&sigset, TIMER_SIGNAL);
|
||||
sigset64_t old_sigset;
|
||||
sigprocmask64(SIG_BLOCK, &sigset, &old_sigset);
|
||||
|
||||
// Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL.
|
||||
__rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset));
|
||||
|
||||
int rc = pthread_create(&timer->callback_thread, &thread_attributes, __timer_thread_start, timer);
|
||||
|
||||
sigprocmask64(SIG_SETMASK, &old_sigset, nullptr);
|
||||
__rt_sigprocmask(SIG_BLOCK, &old_sigset, nullptr, sizeof(old_sigset));
|
||||
|
||||
if (rc != 0) {
|
||||
free(timer);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private/sigrtmin.h"
|
||||
|
||||
extern "C" void __restore_rt(void);
|
||||
extern "C" void __restore(void);
|
||||
|
||||
|
@ -41,7 +43,7 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga
|
|||
if (bionic_new_action != NULL) {
|
||||
kernel_new_action.sa_flags = bionic_new_action->sa_flags;
|
||||
kernel_new_action.sa_handler = bionic_new_action->sa_handler;
|
||||
kernel_new_action.sa_mask = bionic_new_action->sa_mask;
|
||||
kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask);
|
||||
#if defined(SA_RESTORER)
|
||||
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
|
||||
#if defined(__aarch64__)
|
||||
|
@ -120,6 +122,7 @@ int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigacti
|
|||
kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
|
||||
}
|
||||
#endif
|
||||
kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
|
||||
}
|
||||
|
||||
return __rt_sigaction(signal,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include "private/ErrnoRestorer.h"
|
||||
#include "private/SigSetConverter.h"
|
||||
#include "private/sigrtmin.h"
|
||||
|
||||
extern "C" int __rt_sigpending(const sigset64_t*, size_t);
|
||||
extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_t*);
|
||||
|
@ -255,21 +256,33 @@ extern "C" int sigsetmask(int mask) {
|
|||
int sigsuspend(const sigset_t* bionic_set) {
|
||||
SigSetConverter set = {};
|
||||
set.sigset = *bionic_set;
|
||||
return __rt_sigsuspend(&set.sigset64, sizeof(set.sigset64));
|
||||
return sigsuspend64(&set.sigset64);
|
||||
}
|
||||
|
||||
int sigsuspend64(const sigset64_t* set) {
|
||||
return __rt_sigsuspend(set, sizeof(*set));
|
||||
sigset64_t mutable_set;
|
||||
sigset64_t* mutable_set_ptr = nullptr;
|
||||
if (set) {
|
||||
mutable_set = filter_reserved_signals(*set);
|
||||
mutable_set_ptr = &mutable_set;
|
||||
}
|
||||
return __rt_sigsuspend(mutable_set_ptr, sizeof(*set));
|
||||
}
|
||||
|
||||
int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) {
|
||||
SigSetConverter set = {};
|
||||
set.sigset = *bionic_set;
|
||||
return __rt_sigtimedwait(&set.sigset64, info, timeout, sizeof(set.sigset64));
|
||||
return sigtimedwait64(&set.sigset64, info, timeout);
|
||||
}
|
||||
|
||||
int sigtimedwait64(const sigset64_t* set, siginfo_t* info, const timespec* timeout) {
|
||||
return __rt_sigtimedwait(set, info, timeout, sizeof(*set));
|
||||
sigset64_t mutable_set;
|
||||
sigset64_t* mutable_set_ptr = nullptr;
|
||||
if (set) {
|
||||
mutable_set = filter_reserved_signals(*set);
|
||||
mutable_set_ptr = &mutable_set;
|
||||
}
|
||||
return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set));
|
||||
}
|
||||
|
||||
int sigwait(const sigset_t* bionic_set, int* sig) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <signal.h>
|
||||
|
||||
#include "private/sigrtmin.h"
|
||||
#include "private/SigSetConverter.h"
|
||||
|
||||
extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
|
||||
|
@ -64,5 +65,11 @@ int sigprocmask(int how,
|
|||
int sigprocmask64(int how,
|
||||
const sigset64_t* new_set,
|
||||
sigset64_t* old_set) __attribute__((__noinline__)) {
|
||||
return __rt_sigprocmask(how, new_set, old_set, sizeof(*new_set));
|
||||
sigset64_t mutable_new_set;
|
||||
sigset64_t* mutable_new_set_ptr = nullptr;
|
||||
if (new_set) {
|
||||
mutable_new_set = filter_reserved_signals(*new_set);
|
||||
mutable_new_set_ptr = &mutable_new_set;
|
||||
}
|
||||
return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));
|
||||
}
|
||||
|
|
50
libc/private/sigrtmin.h
Normal file
50
libc/private/sigrtmin.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
// Realtime signals reserved for internal use:
|
||||
// 32 (__SIGRTMIN + 0) POSIX timers
|
||||
// 33 (__SIGRTMIN + 1) libbacktrace
|
||||
// 34 (__SIGRTMIN + 2) libcore
|
||||
// 35 (__SIGRTMIN + 3) debuggerd -b
|
||||
//
|
||||
// If you change this, also change __ndk_legacy___libc_current_sigrtmin
|
||||
// in <android/legacy_signal_inlines.h> to match.
|
||||
|
||||
#define __SIGRT_RESERVED 4
|
||||
static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset) {
|
||||
for (int signo = __SIGRTMIN; signo < __SIGRTMIN + __SIGRT_RESERVED; ++signo) {
|
||||
sigdelset64(&sigset, signo);
|
||||
}
|
||||
return sigset;
|
||||
}
|
|
@ -337,6 +337,214 @@ TEST(signal, sigaction64_SIGRTMIN) {
|
|||
TestSigAction(sigaction64, sigaddset64, SIGRTMIN);
|
||||
}
|
||||
|
||||
static void ClearSignalMask() {
|
||||
uint64_t sigset = 0;
|
||||
if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t GetSignalMask() {
|
||||
uint64_t sigset;
|
||||
if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, nullptr, &sigset, sizeof(sigset)) != 0) {
|
||||
abort();
|
||||
}
|
||||
return sigset;
|
||||
}
|
||||
|
||||
enum class SignalMaskFunctionType {
|
||||
RtAware,
|
||||
RtNonaware,
|
||||
};
|
||||
|
||||
#if defined(__LP64__) || !defined(__BIONIC__)
|
||||
constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtAware;
|
||||
#else
|
||||
constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtNonaware;
|
||||
#endif
|
||||
|
||||
static void TestSignalMaskFiltered(uint64_t sigset, SignalMaskFunctionType type) {
|
||||
for (int signo = 1; signo <= 64; ++signo) {
|
||||
bool signal_blocked = sigset & (1ULL << (signo - 1));
|
||||
if (signo == SIGKILL || signo == SIGSTOP) {
|
||||
// SIGKILL and SIGSTOP shouldn't be blocked.
|
||||
EXPECT_EQ(false, signal_blocked) << "signal " << signo;
|
||||
} else if (signo < __SIGRTMIN) {
|
||||
// Everything else should be blocked.
|
||||
EXPECT_EQ(true, signal_blocked) << "signal " << signo;
|
||||
} else if (signo >= __SIGRTMIN && signo < SIGRTMIN) {
|
||||
// Reserved signals must not be blocked.
|
||||
EXPECT_EQ(false, signal_blocked) << "signal " << signo;
|
||||
} else if (type == SignalMaskFunctionType::RtAware) {
|
||||
// Realtime signals should be blocked, unless we blocked using a non-rt aware function.
|
||||
EXPECT_EQ(true, signal_blocked) << "signal " << signo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TestSignalMaskFunction(std::function<void()> fn, SignalMaskFunctionType fn_type) {
|
||||
ClearSignalMask();
|
||||
fn();
|
||||
TestSignalMaskFiltered(GetSignalMask(), fn_type);
|
||||
}
|
||||
|
||||
TEST(signal, sigaction_filter) {
|
||||
ClearSignalMask();
|
||||
static uint64_t sigset;
|
||||
struct sigaction sa = {};
|
||||
sa.sa_handler = [](int) { sigset = GetSignalMask(); };
|
||||
sigfillset(&sa.sa_mask);
|
||||
sigaction(SIGUSR1, &sa, nullptr);
|
||||
raise(SIGUSR1);
|
||||
ASSERT_NE(0ULL, sigset);
|
||||
TestSignalMaskFiltered(sigset, sigset_type);
|
||||
}
|
||||
|
||||
TEST(signal, sigaction64_filter) {
|
||||
ClearSignalMask();
|
||||
static uint64_t sigset;
|
||||
struct sigaction64 sa = {};
|
||||
sa.sa_handler = [](int) { sigset = GetSignalMask(); };
|
||||
sigfillset64(&sa.sa_mask);
|
||||
sigaction64(SIGUSR1, &sa, nullptr);
|
||||
raise(SIGUSR1);
|
||||
ASSERT_NE(0ULL, sigset);
|
||||
TestSignalMaskFiltered(sigset, SignalMaskFunctionType::RtAware);
|
||||
}
|
||||
|
||||
TEST(signal, sigprocmask_setmask_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset_t sigset_libc;
|
||||
sigfillset(&sigset_libc);
|
||||
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
|
||||
},
|
||||
sigset_type);
|
||||
}
|
||||
|
||||
TEST(signal, sigprocmask64_setmask_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset64_t sigset_libc;
|
||||
sigfillset64(&sigset_libc);
|
||||
ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
}
|
||||
|
||||
TEST(signal, pthread_sigmask_setmask_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset_t sigset_libc;
|
||||
sigfillset(&sigset_libc);
|
||||
ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
|
||||
},
|
||||
sigset_type);
|
||||
}
|
||||
|
||||
TEST(signal, pthread_sigmask64_setmask_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset64_t sigset_libc;
|
||||
sigfillset64(&sigset_libc);
|
||||
ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
}
|
||||
|
||||
TEST(signal, sigprocmask_block_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset_t sigset_libc;
|
||||
sigfillset(&sigset_libc);
|
||||
ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
|
||||
},
|
||||
sigset_type);
|
||||
}
|
||||
|
||||
TEST(signal, sigprocmask64_block_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset64_t sigset_libc;
|
||||
sigfillset64(&sigset_libc);
|
||||
ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
}
|
||||
|
||||
TEST(signal, pthread_sigmask_block_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset_t sigset_libc;
|
||||
sigfillset(&sigset_libc);
|
||||
ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
|
||||
},
|
||||
sigset_type);
|
||||
}
|
||||
|
||||
TEST(signal, pthread_sigmask64_block_filter) {
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
sigset64_t sigset_libc;
|
||||
sigfillset64(&sigset_libc);
|
||||
ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
}
|
||||
|
||||
// glibc filters out signals via sigfillset, not the actual underlying functions.
|
||||
TEST(signal, sigset_filter) {
|
||||
#if defined(__BIONIC__)
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
for (int i = 1; i <= 64; ++i) {
|
||||
sigset(i, SIG_HOLD);
|
||||
}
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(signal, sighold_filter) {
|
||||
#if defined(__BIONIC__)
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
for (int i = 1; i <= 64; ++i) {
|
||||
sighold(i);
|
||||
}
|
||||
},
|
||||
SignalMaskFunctionType::RtAware);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__BIONIC__)
|
||||
// Not exposed via headers, but the symbols are available if you declare them yourself.
|
||||
extern "C" int sigblock(int);
|
||||
extern "C" int sigsetmask(int);
|
||||
#endif
|
||||
|
||||
TEST(signal, sigblock_filter) {
|
||||
#if defined(__BIONIC__)
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
int mask = ~0U;
|
||||
ASSERT_EQ(0, sigblock(mask));
|
||||
},
|
||||
SignalMaskFunctionType::RtNonaware);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(signal, sigsetmask_filter) {
|
||||
#if defined(__BIONIC__)
|
||||
TestSignalMaskFunction(
|
||||
[]() {
|
||||
int mask = ~0U;
|
||||
ASSERT_EQ(0, sigsetmask(mask));
|
||||
},
|
||||
SignalMaskFunctionType::RtNonaware);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(signal, sys_signame) {
|
||||
#if defined(__BIONIC__)
|
||||
ASSERT_TRUE(sys_signame[0] == NULL);
|
||||
|
|
Loading…
Reference in a new issue