Merge "Filter out reserved signals in functions that take sigset_t."

am: efa792be64

Change-Id: Ie63dc7e4c77b09032526873247311bac8d865e37
This commit is contained in:
Josh Gao 2018-02-28 00:33:53 +00:00 committed by android-build-merger
commit 3e75f6d090
8 changed files with 316 additions and 21 deletions

View file

@ -28,14 +28,8 @@
#include <signal.h> #include <signal.h>
// Realtime signals reserved for internal use: #include "private/sigrtmin.h"
// 32 (__SIGRTMIN + 0) POSIX timers
// 33 (__SIGRTMIN + 1) libbacktrace
// 34 (__SIGRTMIN + 2) libcore
// 35 (__SIGRTMIN + 3) debuggerd -b
int __libc_current_sigrtmin(void) { int __libc_current_sigrtmin() {
// If you change this, also change __ndk_legacy___libc_current_sigrtmin return __SIGRTMIN + __SIGRT_RESERVED;
// in <android/legacy_signal_inlines.h> to match.
return __SIGRTMIN + 4;
} }

View file

@ -31,6 +31,7 @@
#include <sys/select.h> #include <sys/select.h>
#include "private/bionic_time_conversions.h" #include "private/bionic_time_conversions.h"
#include "private/sigrtmin.h"
#include "private/SigSetConverter.h" #include "private/SigSetConverter.h"
extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t); 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 = *ts;
mutable_ts_ptr = &mutable_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) { 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; 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, // The Linux kernel only handles 6 arguments and this system call really needs 7,
// so the last argument is a void* pointing to: // so the last argument is a void* pointing to:
struct pselect6_extra_data_t { 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; size_t ss_len;
}; };
pselect6_extra_data_t extra_data; pselect6_extra_data_t extra_data;
extra_data.ss_addr = reinterpret_cast<uintptr_t>(ss); extra_data.ss_addr = reinterpret_cast<uintptr_t>(mutable_ss_ptr);
extra_data.ss_len = sizeof(*ss); extra_data.ss_len = sizeof(*mutable_ss_ptr);
return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data); return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data);
} }

View file

@ -35,6 +35,8 @@
#include <time.h> #include <time.h>
// System calls. // 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_create(clockid_t, sigevent*, __kernel_timer_t*);
extern "C" int __timer_delete(__kernel_timer_t); extern "C" int __timer_delete(__kernel_timer_t);
extern "C" int __timer_getoverrun(__kernel_timer_t); extern "C" int __timer_getoverrun(__kernel_timer_t);
@ -77,7 +79,7 @@ static void* __timer_thread_start(void* arg) {
while (true) { while (true) {
// Wait for a signal... // Wait for a signal...
siginfo_t si = {}; 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) { if (si.si_code == SI_TIMER) {
// This signal was sent because a timer fired, so call the callback. // 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 = {}; sigset64_t sigset = {};
sigaddset64(&sigset, TIMER_SIGNAL); sigaddset64(&sigset, TIMER_SIGNAL);
sigset64_t old_sigset; 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); 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) { if (rc != 0) {
free(timer); free(timer);

View file

@ -29,6 +29,8 @@
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include "private/sigrtmin.h"
extern "C" void __restore_rt(void); extern "C" void __restore_rt(void);
extern "C" void __restore(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) { if (bionic_new_action != NULL) {
kernel_new_action.sa_flags = bionic_new_action->sa_flags; kernel_new_action.sa_flags = bionic_new_action->sa_flags;
kernel_new_action.sa_handler = bionic_new_action->sa_handler; 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) #if defined(SA_RESTORER)
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer; kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
#if defined(__aarch64__) #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; kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
} }
#endif #endif
kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
} }
return __rt_sigaction(signal, return __rt_sigaction(signal,

View file

@ -38,6 +38,7 @@
#include "private/ErrnoRestorer.h" #include "private/ErrnoRestorer.h"
#include "private/SigSetConverter.h" #include "private/SigSetConverter.h"
#include "private/sigrtmin.h"
extern "C" int __rt_sigpending(const sigset64_t*, size_t); extern "C" int __rt_sigpending(const sigset64_t*, size_t);
extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_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) { int sigsuspend(const sigset_t* bionic_set) {
SigSetConverter set = {}; SigSetConverter set = {};
set.sigset = *bionic_set; set.sigset = *bionic_set;
return __rt_sigsuspend(&set.sigset64, sizeof(set.sigset64)); return sigsuspend64(&set.sigset64);
} }
int sigsuspend64(const sigset64_t* set) { 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) { int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) {
SigSetConverter set = {}; SigSetConverter set = {};
set.sigset = *bionic_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) { 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) { int sigwait(const sigset_t* bionic_set, int* sig) {

View file

@ -28,6 +28,7 @@
#include <signal.h> #include <signal.h>
#include "private/sigrtmin.h"
#include "private/SigSetConverter.h" #include "private/SigSetConverter.h"
extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t); 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, int sigprocmask64(int how,
const sigset64_t* new_set, const sigset64_t* new_set,
sigset64_t* old_set) __attribute__((__noinline__)) { 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
View 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;
}

View file

@ -337,6 +337,214 @@ TEST(signal, sigaction64_SIGRTMIN) {
TestSigAction(sigaction64, sigaddset64, 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) { TEST(signal, sys_signame) {
#if defined(__BIONIC__) #if defined(__BIONIC__)
ASSERT_TRUE(sys_signame[0] == NULL); ASSERT_TRUE(sys_signame[0] == NULL);