提交 2c9eae1d 编写于 作者: D dhy308

Add support for Sigchain

Issue: I6AEEI
Test: Build & Boot Devices
Signed-off-by: Ndhy308 <tony.gan@huawei.com>
上级 6be141c4
#ifndef _SIGCHAIN_H
#define _SIGCHAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <signal.h>
#include <stdint.h>
#include <stdbool.h>
static const int SIGCHAIN_ALLOW_NORETURN = 0x1UL;
/* The action of the sigchain. */
struct signal_chain_action {
bool (*sca_sigaction)(int, siginfo_t*, void*);
sigset_t sca_mask;
int sca_flags;
};
/* Mark the signal to the sigchain, add the special handler to the sigchain. */
void add_special_signal_handler(int signo, struct signal_chain_action* sa);
/* Remove the special the handler form the sigchain. */
void remove_special_signal_handler(int signo, bool (*fn)(int, siginfo_t*, void*));
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
......@@ -310,6 +310,7 @@
acoshl;
acosl;
addmntent;
add_special_signal_handler;
adjtime;
adjtimex;
aio_cancel;
......@@ -1486,6 +1487,7 @@
remainderl;
remap_file_pages;
remove;
remove_special_signal_handler;
removexattr;
remque;
remquo;
......
......@@ -1040,6 +1040,7 @@ musl_src_file = [
"src/signal/sigtimedwait.c",
"src/signal/sigwait.c",
"src/signal/sigwaitinfo.c",
"src/sigchain/sigchain.c",
"src/stat/__xstat.c",
"src/stat/chmod.c",
"src/stat/fchmod.c",
......@@ -1973,6 +1974,7 @@ musl_inc_root_files = [
"include/setjmp.h",
"include/shadow.h",
"include/signal.h",
"include/sigchain.h",
"include/spawn.h",
"include/stdalign.h",
"include/stdarg.h",
......@@ -2041,6 +2043,7 @@ musl_src_porting_file = [
"include/sys/socket.h",
"include/sys/sysinfo.h",
"include/signal.h",
"include/sigchain.h",
"include/sched.h",
"src/internal/dynlink.h",
"include/sys/tgkill.h",
......@@ -2112,6 +2115,8 @@ musl_src_porting_file = [
"src/thread/pthread_create.c",
"src/sched/sched_cpualloc.c",
"src/signal/signal.c",
"src/signal/sigaction.c",
"src/signal/sigprocmask.c",
"include/langinfo.h",
"include/locale.h",
"src/hilog/hilog_adapter.c",
......@@ -2143,6 +2148,7 @@ musl_src_porting_file = [
"src/process/x86_64/__vfork.s",
"src/linux/cache.c",
"src/sched/sched_getcpu.c",
"src/sigchain/sigchain.c",
]
musl_inc_hook_files = [
......
#ifndef _SIGCHAIN_H
#define _SIGCHAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#define _GNU_SOURCE
#include <signal.h>
#include <stdint.h>
#include <stdbool.h>
static const int SIGCHAIN_ALLOW_NORETURN = 0x1UL;
/* The action of the sigchain. */
struct signal_chain_action {
bool (*sca_sigaction)(int, siginfo_t*, void*);
sigset_t sca_mask;
int sca_flags;
};
/* Mark the signal to the sigchain, add the special handler to the sigchain. */
void add_special_signal_handler(int signo, struct signal_chain_action* sa);
/* Remove the special the handler form the sigchain. */
void remove_special_signal_handler(int signo, bool (*fn)(int, siginfo_t*, void*));
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
#ifndef _SIGCHAIN_H
#define _SIGCHAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <signal.h>
#include <stdint.h>
#include <stdbool.h>
static const int SIGCHAIN_ALLOW_NORETURN = 0x1UL;
/* The action of the sigchain. */
struct signal_chain_action {
bool (*sca_sigaction)(int, siginfo_t*, void*);
sigset_t sca_mask;
int sca_flags;
};
/* Mark the signal to the sigchain, add the special handler to the sigchain. */
void add_special_signal_handler(int signo, struct signal_chain_action* sa);
/* Remove the special the handler form the sigchain. */
void remove_special_signal_handler(int signo, bool (*fn)(int, siginfo_t*, void*));
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
#include <sigchain.h>
#include <locale.h>
#include <pthread.h>
#include <errno.h>
#include <stdio.h>
extern int __libc_sigaction(int sig, const struct sigaction *restrict sa,
struct sigaction *restrict old);
#define SIG_CHAIN_KEY_VALUE_1 1
#define SIGNAL_CHAIN_SPECIAL_ACTION_MAX 2
#if SIGCHAIN_DEBUG
#ifndef SIGCHAIN_PRINT_DEBUG
#define SIGCHAIN_PRINT_DEBUG(fmt, ...) printf("SIGCHAIN D " fmt "\n", ##__VA_ARGS__)
#endif
#else
#define SIGCHAIN_PRINT_DEBUG(fmt, ...)
#endif
#ifndef SIGCHAIN_PRINT_INFO
#define SIGCHAIN_PRINT_INFO(fmt, ...) printf("SIGCHAIN I " fmt "\n", ##__VA_ARGS__)
#endif
#ifndef SIGCHAIN_PRINT_ERROR
#define SIGCHAIN_PRINT_ERROR(fmt, ...) printf("SIGCHAIN E " fmt "\n", ##__VA_ARGS__)
#endif
struct sc_signal_chain {
bool marked;
struct sigaction sig_action;
struct signal_chain_action sca_special_actions[SIGNAL_CHAIN_SPECIAL_ACTION_MAX];
};
/* Signal chain set, from 0 to 63. */
static struct sc_signal_chain sig_chains[_NSIG - 1];
/* static thread Keyword */
static pthread_key_t sigchain_key;
/**
* @brief Get the key of the signal thread.
* @retval int32_t, the value of the sigchain key.
*/
static pthread_key_t get_handling_signal_key() {
static bool isCreated = false;
if (!isCreated) {
/* Create a thread key. */
int rc = pthread_key_create(&sigchain_key, NULL);
if (rc != 0) {
SIGCHAIN_PRINT_ERROR("%s failed to create sigchain pthread key",
__func__, rc);
} else {
isCreated = true;
int32_t value = 0;
pthread_setspecific(sigchain_key, &value);
}
}
return sigchain_key;
}
/**
* @brief Get the value of the sigchain key
* @retval int32_t, the value of the sigchain key.
*/
static int32_t get_handling_signal() {
int32_t *result = pthread_getspecific(get_handling_signal_key());
return *result;
}
/**
* @brief Set the value of the sigchain key
* @param[in] value, the value of the sigchain key
* @retval void.
*/
static void set_handling_signal(int32_t value) {
pthread_setspecific(get_handling_signal_key(),
&value);
}
/**
* @brief Judge whether the signal is marked
* @param[in] signo, the value of the signal.
* @retval true if the signal is marked, or false.
*/
bool ismarked(int signo)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
return sig_chains[signo - 1].marked;
}
/**
* @brief This is a callback function, which is registered to the kernel
* @param[in] signo, the value of the signal.
* @param[in] siginfo, the information of the signal.
* @param[in] ucontext_raw, the context of the signal.
* @retval void
*/
static void signal_chain_handler(int signo, siginfo_t* siginfo, void* ucontext_raw)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
/* Try to call the special handlers first. */
if (get_handling_signal() == 0){
int len = SIGNAL_CHAIN_SPECIAL_ACTION_MAX;
for (int i = 0; i < len; i++) {
if (sig_chains[signo - 1].sca_special_actions[i].sca_sigaction == NULL) {
break;
}
/* The native bridge signal handler might not return. */
bool noreturn = (sig_chains[signo - 1].sca_special_actions[i].sca_flags &
SIGCHAIN_ALLOW_NORETURN);
sigset_t previous_mask;
pthread_sigmask(SIG_SETMASK, &sig_chains[signo - 1].sca_special_actions[i].sca_mask,
&previous_mask);
int32_t previous_value = get_handling_signal();
if (!noreturn) {
set_handling_signal(SIG_CHAIN_KEY_VALUE_1);
}
if (sig_chains[signo - 1].sca_special_actions[i].sca_sigaction(signo,
siginfo, ucontext_raw)) {
set_handling_signal(previous_value);
return;
}
pthread_sigmask(SIG_SETMASK, &previous_mask, NULL);
set_handling_signal(previous_value);
}
}
int sa_flags = sig_chains[signo - 1].sig_action.sa_flags;
ucontext_t* ucontext = (ucontext_t*)(ucontext_raw);
sigset_t mask;
sigorset(&mask, &ucontext->uc_sigmask, &sig_chains[signo - 1].sig_action.sa_mask);
if (!(sa_flags & SA_NODEFER)) {
sigaddset(&mask, signo);
}
pthread_sigmask(SIG_SETMASK, &mask, NULL);
if ((sa_flags & SA_SIGINFO)) {
sig_chains[signo - 1].sig_action.sa_sigaction(signo, siginfo, ucontext_raw);
} else {
if (sig_chains[signo - 1].sig_action.sa_handler == SIG_IGN) {
return;
} else if (sig_chains[signo - 1].sig_action.sa_handler == SIG_DFL) {
SIGCHAIN_PRINT_INFO("%s exiting due to SIG_DFL handler for signal: %d",
__func__, signo);
} else {
sig_chains[signo - 1].sig_action.sa_handler(signo);
}
}
return;
}
/**
* @brief Register the signal chain with the kernel if needed
* @param[in] signo, the value of the signal.
* @retval void
*/
void sigchain_register(int signo)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
struct sigaction signal_action = {};
sigfillset(&signal_action.sa_mask);
signal_action.sa_sigaction = signal_chain_handler;
signal_action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
__libc_sigaction(signo, &signal_action, &sig_chains[signo - 1].sig_action);
}
/**
* @brief Mark the signal to the sigchain.
* @param[in] signo, the value of the signal.
* @retval void
*/
void mark(int signo)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
if (!sig_chains[signo - 1].marked) {
sigchain_register(signo);
sig_chains[signo - 1].marked = true;
}
}
/**
* @brief Set the action of the signal.
* @param[in] signo, the value of the signal.
* @param[in] new_sa, the new action of the signal.
* @retval void
*/
void setaction(int signo, const struct sigaction *restrict new_sa)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
sig_chains[signo - 1].sig_action = *new_sa;
}
/**
* @brief Get the action of the signal.
* @param[in] signo, the value of the signal.
* @retval The current action of the signal
*/
struct sigaction getaction(int signo)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
return sig_chains[signo - 1].sig_action;
}
/**
* @brief Add the special handler to the sigchain.
* @param[in] signo, the value of the signal.
* @param[in] sa, the action with special handler.
* @retval void
*/
void add_special_handler(int signo, struct signal_chain_action* sa)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
int len = SIGNAL_CHAIN_SPECIAL_ACTION_MAX;
for (int i = 0; i < len; i++) {
if (sig_chains[signo - 1].sca_special_actions[i].sca_sigaction == NULL) {
sig_chains[signo - 1].sca_special_actions[i] = *sa;
return;
}
}
}
/**
* @brief Remove the special handler from the sigchain.
* @param[in] signo, the value of the signal.
* @param[in] fn, the special handler of the signal.
* @retval void
*/
void rm_special_handler(int signo, bool (*fn)(int, siginfo_t*, void*))
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
int len = SIGNAL_CHAIN_SPECIAL_ACTION_MAX;
for (int i = 0; i < len; i++) {
if (sig_chains[signo - 1].sca_special_actions[i].sca_sigaction == fn) {
for (int j = i; j < len - 1; ++j) {
sig_chains[signo - 1].sca_special_actions[j] =
sig_chains[signo - 1].sca_special_actions[j + 1];
}
sig_chains[signo - 1].sca_special_actions[len - 1].sca_sigaction = NULL;
return;
}
}
SIGCHAIN_PRINT_INFO("%s failed to find special handler!. signo: %d",
__func__, signo);
}
/**
* @brief This is an external interface,
* Mark the signal to sigchain ,add the special handler to the sigchain.
* @param[in] signo, the value of the signal.
* @param[in] sa, the action with special handler.
* @retval void
*/
void add_special_signal_handler(int signo, struct signal_chain_action* sa)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
if (signo <= 0 || signo >= _NSIG) {
SIGCHAIN_PRINT_ERROR("%s Invalid signal %d", __func__, signo);
return;
}
// Set the special handler.
add_special_handler(signo, sa);
mark(signo);
}
/**
* @brief This is an external interface, remove the special handler from the sigchain.
* @param[in] signo, the value of the signal.
* @param[in] fn, the special handler of the signal.
* @retval void
*/
void remove_special_signal_handler(int signo, bool (*fn)(int, siginfo_t*, void*))
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
if (signo <= 0 || signo >= _NSIG) {
SIGCHAIN_PRINT_ERROR("%s Invalid signal %d", __func__, signo);
return;
}
// remove the special handler.
rm_special_handler(signo, fn);
}
/**
* @brief Intercept the signal and sigaction.
* @param[in] signo, the value of the signal.
* @param[in] sa, the new action with the signal handler.
* @param[out] old, the old action with the signal handler.
* @retval true if the signal if intercepted, or false.
*/
bool intercept_sigaction(int signo, const struct sigaction *restrict sa,
struct sigaction *restrict old)
{
SIGCHAIN_PRINT_DEBUG("%s signo: %d", __func__, signo);
if (signo <= 0 || signo >= _NSIG) {
SIGCHAIN_PRINT_ERROR("%s Invalid signal %d", __func__, signo);
return false;
}
if (ismarked(signo)) {
struct sigaction saved_action = getaction(signo);
if (sa != NULL) {
setaction(signo, sa);
}
if (old != NULL) {
*old = saved_action;
}
return true;
}
return false;
}
/**
* @brief Intercept the sigprocmask.
* @param[in] how, the value of the mask operation .
* @param[out] set, the value of the sigset.
* @retval void.
*/
void intercept_sigprocmask(int how, sigset_t *restrict set)
{
SIGCHAIN_PRINT_DEBUG("%s how: %d", __func__, how);
if (get_handling_signal() != 0) {
return;
}
sigset_t tmpset;
if (set != NULL) {
tmpset = *set;
if (how == SIG_BLOCK || how == SIG_SETMASK) {
for (int i = 1; i < _NSIG; ++i) {
if (ismarked(i) && sigismember(&tmpset, i)) {
sigdelset(&tmpset, i);
}
}
}
*set = tmpset;
}
return;
}
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sigchain.h>
#include "syscall.h"
#include "pthread_impl.h"
#include "libc.h"
#include "lock.h"
#include "ksigaction.h"
extern bool intercept_sigaction(int signo, const struct sigaction *restrict sa, struct sigaction *restrict old);
static volatile int dummy_lock[1] = { 0 };
extern hidden volatile int __abort_lock[1];
weak_alias(dummy_lock, __abort_lock);
static int unmask_done;
static unsigned long handler_set[_NSIG/(8*sizeof(long))];
void __get_handler_set(sigset_t *set)
{
memcpy(set, handler_set, sizeof handler_set);
}
volatile int __eintr_valid_flag;
int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
{
struct k_sigaction ksa, ksa_old;
unsigned long set[_NSIG/(8*sizeof(long))];
if (sa) {
if ((uintptr_t)sa->sa_handler > 1UL) {
a_or_l(handler_set+(sig-1)/(8*sizeof(long)),
1UL<<(sig-1)%(8*sizeof(long)));
/* If pthread_create has not yet been called,
* implementation-internal signals might not
* yet have been unblocked. They must be
* unblocked before any signal handler is
* installed, so that an application cannot
* receive an illegal sigset_t (with them
* blocked) as part of the ucontext_t passed
* to the signal handler. */
if (!libc.threaded && !unmask_done) {
__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
SIGPT_SET, 0, _NSIG/8);
unmask_done = 1;
}
if (!(sa->sa_flags & SA_RESTART)) {
a_store(&__eintr_valid_flag, 1);
}
}
/* Changing the disposition of SIGABRT to anything but
* SIG_DFL requires a lock, so that it cannot be changed
* while abort is terminating the process after simply
* calling raise(SIGABRT) failed to do so. */
if (sa->sa_handler != SIG_DFL && sig == SIGABRT) {
__block_all_sigs(&set);
LOCK(__abort_lock);
}
ksa.handler = sa->sa_handler;
ksa.flags = sa->sa_flags | SA_RESTORER;
ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
}
int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
if (sig == SIGABRT && sa && sa->sa_handler != SIG_DFL) {
UNLOCK(__abort_lock);
__restore_sigs(&set);
}
if (old && !r) {
old->sa_handler = ksa_old.handler;
old->sa_flags = ksa_old.flags;
memcpy(&old->sa_mask, &ksa_old.mask, _NSIG/8);
}
return __syscall_ret(r);
}
int __sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
{
if (sig-32U < 3 || sig-1U >= _NSIG-1) {
errno = EINVAL;
return -1;
}
if (intercept_sigaction(sig, sa, old)) {
return 0;
}
return __libc_sigaction(sig, sa, old);
}
weak_alias(__sigaction, sigaction);
#include <signal.h>
#include <errno.h>
#include <sigchain.h>
extern void intercept_sigprocmask(int how, sigset_t *restrict set);
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict old)
{
sigset_t tmpset = *set;
intercept_sigprocmask(how, &tmpset);
const sigset_t *new_set_ptr = &tmpset;
int r = pthread_sigmask(how, new_set_ptr, old);
if (!r) return r;
errno = r;
return -1;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册