@@ -177,6 +177,12 @@ typedef struct TaskState {
* the table itself should be guarded.
*/
struct fd_trans_table *fd_trans_tbl;
+
+ /*
+ * A table containing signal actions for the target. It should have at
+ * least TARGET_NSIG entries
+ */
+ struct target_sigaction *sigact_tbl;
} __attribute__((aligned(16))) TaskState;
extern char *exec_path;
@@ -419,7 +425,9 @@ void print_syscall_ret(int num, abi_long arg1);
*/
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
+
/* signal.c */
+struct target_sigaction *sigact_table_clone(struct target_sigaction *orig);
void process_pending_signals(CPUArchState *cpu_env);
void signal_init(void);
int queue_signal(CPUArchState *env, int sig, int si_type,
@@ -25,7 +25,13 @@
#include "trace.h"
#include "signal-common.h"
-static struct target_sigaction sigact_table[TARGET_NSIG];
+struct target_sigaltstack target_sigaltstack_used = {
+ .ss_sp = 0,
+ .ss_size = 0,
+ .ss_flags = TARGET_SS_DISABLE,
+};
+
+typedef struct target_sigaction sigact_table[TARGET_NSIG];
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
@@ -542,6 +548,11 @@ static void signal_table_init(void)
}
}
+struct target_sigaction *sigact_table_clone(struct target_sigaction *orig)
+{
+ return memcpy(g_new(sigact_table, 1), orig, sizeof(sigact_table));
+}
+
void signal_init(void)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;
@@ -556,6 +567,12 @@ void signal_init(void)
/* Set the signal mask from the host mask. */
sigprocmask(0, 0, &ts->signal_mask);
+ /*
+ * Set all host signal handlers. ALL signals are blocked during
+ * the handlers to serialize them.
+ */
+ ts->sigact_tbl = (struct target_sigaction *) g_new0(sigact_table, 1);
+
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
@@ -568,9 +585,9 @@ void signal_init(void)
host_sig = target_to_host_signal(i);
sigaction(host_sig, NULL, &oact);
if (oact.sa_sigaction == (void *)SIG_IGN) {
- sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+ ts->sigact_tbl[i - 1]._sa_handler = TARGET_SIG_IGN;
} else if (oact.sa_sigaction == (void *)SIG_DFL) {
- sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+ ts->sigact_tbl[i - 1]._sa_handler = TARGET_SIG_DFL;
}
/* If there's already a handler installed then something has
gone horribly wrong, so don't even try to handle that case. */
@@ -608,11 +625,12 @@ void force_sig(int sig)
#if !defined(TARGET_RISCV)
void force_sigsegv(int oldsig)
{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
if (oldsig == SIGSEGV) {
/* Make sure we don't try to deliver the signal again; this will
* end up with handle_pending_signal() calling dump_core_and_abort().
*/
- sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
+ ts->sigact_tbl[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
}
force_sig(TARGET_SIGSEGV);
}
@@ -837,6 +855,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
struct sigaction act1;
int host_sig;
int ret = 0;
+ TaskState* ts = (TaskState *)thread_cpu->opaque;
trace_signal_do_sigaction_guest(sig, TARGET_NSIG);
@@ -848,7 +867,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return -TARGET_ERESTARTSYS;
}
- k = &sigact_table[sig - 1];
+ k = &ts->sigact_tbl[sig - 1];
if (oact) {
__put_user(k->_sa_handler, &oact->_sa_handler);
__put_user(k->sa_flags, &oact->sa_flags);
@@ -930,7 +949,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
sa = NULL;
handler = TARGET_SIG_IGN;
} else {
- sa = &sigact_table[sig - 1];
+ sa = &ts->sigact_tbl[sig - 1];
handler = sa->_sa_handler;
}
@@ -1022,9 +1041,9 @@ void process_pending_signals(CPUArchState *cpu_env)
* looping round and round indefinitely.
*/
if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
- || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
+ || ts->sigact_tbl[sig - 1]._sa_handler == TARGET_SIG_IGN) {
sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
- sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
+ ts->sigact_tbl[sig - 1]._sa_handler = TARGET_SIG_DFL;
}
handle_pending_signal(cpu_env, sig, &ts->sync_signal);
@@ -5989,6 +5989,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
return -TARGET_EINVAL;
}
+ if ((flags & CLONE_SIGHAND) && !(flags & CLONE_VM)) {
+ /*
+ * Like CLONE_FILES, this flag combination is unsupported. If
+ * CLONE_SIGHAND is specified without CLONE_VM, then we need to keep
+ * the sigact table in-sync across virtual memory boundaries, which is
+ * substantially more complicated.
+ */
+ qemu_log_mask(LOG_UNIMP, "CLONE_SIGHAND only supported with CLONE_VM");
+ return -TARGET_EINVAL;
+ }
+
pthread_mutex_init(&info.mutex, NULL);
pthread_mutex_lock(&info.mutex);
pthread_cond_init(&info.cond, NULL);
@@ -6025,6 +6036,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
ts->fd_trans_tbl = fd_trans_table_clone(parent_ts->fd_trans_tbl);
}
+ if (flags & CLONE_SIGHAND) {
+ ts->sigact_tbl = parent_ts->sigact_tbl;
+ } else {
+ ts->sigact_tbl = sigact_table_clone(parent_ts->sigact_tbl);
+ }
+
if (flags & CLONE_CHILD_CLEARTID) {
ts->child_tidptr = child_tidptr;
}
sigact_table stores the signal handlers for the given process. Once we support CLONE_VM, two tasks using the same virtual memory may need different signal handler tables (e.g., if CLONE_SIGHAND is not provided). Here we make sigact_table part of the TaskState, so it can be duplicated as needed when cloning children. Signed-off-by: Josh Kunz <jkz@google.com> --- linux-user/qemu.h | 8 ++++++++ linux-user/signal.c | 35 +++++++++++++++++++++++++++-------- linux-user/syscall.c | 17 +++++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-)